---
# System prepended metadata

title: pwn

---

# pwn
## 環境配置


### pwn ⼯具懶⼈包
```
git clone https://github.com/r888800009/CTF-tool.git
cd CTF-tool/pwn_docker
./setup_docker.sh 20.04
docker run --privileged --rm -it\v $(pwd):/work ctf_ubuntu_20.04
```
### Ghidra
Download: https://github.com/NationalSecurityAgency/ghidra/releases
```
unzip ghidra_*_PUBLIC_*.zip
sudo apt-get install default-jdk
/ghidraRun
```

## Lab readelf
readelf 讀取 /bin/sh 的
* ELF Header
* Section Header
* Program Header
```
readelf -h /bin/sh 
```
![](https://i.imgur.com/GxdrFNe.png)
```
readelf -S /bin/sh
```
![](https://i.imgur.com/dG5vmId.png)



```
readelf -l /bin/sh
```
![](https://i.imgur.com/6Grycuu.png)
下方Segment Sections的00,01,02都對着Program Header的Type,PHDR,INTERP

Example:
找出.text在上方Program Header的哪裏?
可見.text在下方的Segment Sections 03的位置，而03剛好對着LOAD           0x0000000000000000 
## gcc參數
* -o 
    * 制定目標名稱
* -l
    * 制定編譯的時候使用的庫
* -no-pie
    * 關閉PIE保護
* -fno-stack-protector
    * 關閉canary保護

## gdb指令
### 常用
* run / start
    * start 會停在 main()，run 會直接執⾏完
    * run 也可以傳入⼀些參數
    * attach <pid>
    * 如果要 attach 需要⽤ sudo 開啟 gdb 才有
    
* ptrace 的權限
    * b *0x1234
    * 在 0x1234 這個地址設定斷點
    * 也可以直接 b main 斷在 main

* 單步執⾏
    * si 進入 function
    * ni 不進入 function
* c
    * 程式繼續執⾏
* finish
    * 完成⽬前的 function，讓 gdb 停在 ret 這個指
令上⾯
* bt
    * backtrace 顯⽰⽬前的函數 Call stack
* q
    * 退出 gdb 不過 ctrl+d 也是可以的
* ctrl+r
    * 可以快速搜尋打過的指令

* print <*addr/symbol>
    * 顯⽰特定地址內容
* set $rip=0x1234
    * 將⽬前的 rip 改成 0x1234
* set follow-fork-mode <mode>
    * 可以是 parent 或 child
    
### Plugin
*	context
    *	顯⽰ stack / code / registers / trace 這些視窗
*	vmmap
    *    顯⽰ virtual memory layout
    *	i proc mappings
    *	每個 page 的
    *	權限
    *	起點與結束位置
    *	page 所載入的 image
*	checksec
    *	顯⽰⽬前保護機制哪些有啟⽤
*	telescope
    *	打印出記憶體內容，預設是 $rsp
    *	telescope $rsp+0x10
    *	telescope $fs_base 可以查詢 TLS
*	search-pattern \<pattern> / search \<pattern>
    *	搜尋記憶體是否有特殊數值或字串
## Lab stack-frame and fork_canary
1. 熟悉 gdb 與 gef / pwndbg 插件，並且認識 process
1. https://github.com/r888800009/pwn-labs/blob/main/stack-frame
1. 在 gdb 外⾯ attach 另外⼀個 /bin/sh 的 process
1. stack-frame
    * 練習斷點
    * 進入 puts() 函數裡⾯，之後透過 finish 出來
    * 透過 vmmap 找出 libc.so 的 base address
    * 找出 "/bin/sh" 這個字串
    * 在 main 直接跳過 puts 不要輸出顯⽰
1. fork_canary
    * 這個程式會 fork ⼀個 process，並且把 parent 的
    * canary print 出來，請猜猜看 child 的 canary
    * 如果猜到的話，請解釋怎麼猜的。
    * https://github.com/r888800009/pwn-labs/blob/main/fork_canary

```
gdb /bin/sh
start
```
![](https://i.imgur.com/ahIdlbm.png)
---
如果要在0x555555555150 <main+23> mov rdi, rax設breakpoint可以使用
```
    b *Address
    
    example:
    b *0x555555555150
```
如下圖  
![](https://i.imgur.com/KAv1pvW.png)
### stack-frame
    
在\<puts@plt>設breakpoint然後一直si到沒plt為止就進到puts()裏了
![](https://i.imgur.com/A4FsnpJ.png)
    
用vmmap看出libc.so在0x007ffff7dcd000 ... r-- .../x86_64-linux-gnu/libc-2.31.so
![](https://i.imgur.com/tRoh9gg.png)

使用search-pattern "/bin/sh"
![](https://i.imgur.com/JU9J5iq.png)
    
在\<puts@plt>前一行設breakpoint和用set $rip=xxxx把rip設在\<puts@plt>後一行，就能跳過puts執行下一行。
如果沒跳過的話會輸出hello world
    
### fork canary
```
set follow-fork-mode parent
canary
```
![](https://i.imgur.com/UXzTKoz.png)

![](https://i.imgur.com/N1qU4p0.png)
---
可以看見child 和 parent canary是一樣的，因為fork的時候，child會複製一樣的東西出來，包括Physical memory也指向同一個。如果child裏有改動的話，就需要從原先在physical memory的值再複製一份做更改。
    
![](https://i.imgur.com/sEm1tCB.png)

## Lab Mitigations
https://github.com/r888800009/pwn-labs/blob/main/mitigations.c
1. 了解常⾒ CTF 保護機制等等
1. ⽬標 (將解法打到共筆上⾯)
    * 編譯沒有 PIE 但是有 canary 保護的 ELF
    * 執⾏四次 ./mitigations，並且記錄每次 libc 的位置
    * Checksec
    * 檢視編譯好的 mitigations 有限制哪些 syscall
    * 透過 gdb 找出 canary 的數值
    * 透過搜尋 canary 找出 TLS 的位置
---
編譯沒有 PIE 但是有 canary 保護的 ELF
編譯的時候會出現警告訊息，因為程式中使用了不安全的gets，可以無視
```
gcc -no-pie mitigations.c -l seccomp -o mitigations 
```
![](https://i.imgur.com/UhDtCvm.png)
雖然已經關閉了PIE但是因為還有canary所以libc的位置還是會隨機
![](https://i.imgur.com/x0pfs6G.png)
```
seccomp-tools dump ./mitigations
```
syscall為如下
![](https://i.imgur.com/i2xPpZv.png)

