返回文章列表

日誌監控與入侵檢測系統設計

本文探討如何利用 Shell 指令碼開發輕量級入侵檢測系統,結合 tail 與 egrep 指令監控日誌,並比對自定義入侵指標(IOCs)。文章涵蓋 Windows 日誌監控技巧、即時直方圖生成方法,以及網路服務變更偵測工具的開發與排程自動化,提供全面的日誌監控和入侵檢測解決方案。

資安 系統管理

在現今網路環境中,主動監控系統日誌並即時偵測入侵行為至關重要。本文介紹如何結合 tailegrep 等指令,搭配自定義的入侵指標(IOCs)檔案,建立輕量級的入侵檢測系統。除了 Linux 系統的日誌監控,也涵蓋 Windows 系統的日誌監控方法,並提供 Shell 指令碼範例,示範如何模擬 tail -f 功能。此外,文章也說明瞭如何產生即時直方圖,將日誌活動視覺化,更直觀地掌握系統狀態。更進一步,我們將探討如何開發網路服務變更偵測工具,監控系統開放連線埠的變化,並結合排程任務實作自動化監控和郵件通知,提升資安防護的效率。

即時日誌監控與入侵檢測系統

在資安領域中,日誌監控是一項至關重要的任務。透過監視系統或應用程式的日誌,可以即時發現潛在的安全威脅或異常行為。本文將介紹如何利用 tailegrep 指令來建立一個輕量級的入侵檢測系統(IDS),並進一步探討如何在 Windows 環境中監控日誌以及如何產生即時直方圖。

根據日誌的入侵檢測

要建立一個根據日誌的入侵檢測系統,首先需要定義一些已知的安全威脅模式,也就是所謂的「入侵指標」(Indicators of Compromise, IOCs)。這些 IOCs 可以是特定的字串或正規表示式,用於匹配日誌中的可疑活動。

建立 IOCs 檔案

首先,建立一個名為 ioc.txt 的檔案,並在其中加入已知的 IOCs,例如:

\.\./
etc/passwd
etc/shadow
cmd\.exe
/bin/sh
/bin/bash

這些模式對應不同的安全威脅,例如目錄遍歷攻擊、未授權存取敏感檔案、反向 Shell 等。

使用 tailegrep 監控日誌

接下來,可以使用以下指令來監控 Apache2 的存取日誌,並輸出匹配 IOCs 的日誌條目:

tail -f /var/logs/apache2/access.log | egrep -i -f ioc.txt

若要同時將匹配結果輸出到螢幕和儲存到檔案中,可以使用 tee 指令:

tail -f /var/logs/apache2/access.log | egrep --line-buffered -i -f ioc.txt | tee -a interesting.txt

監控 Windows 日誌

在 Windows 環境中,可以使用 wevtutil 指令來存取 Windows 事件日誌。然而,wevtutil 並沒有像 tail 一樣的功能來即時監控日誌。因此,需要撰寫一個簡單的 bash 指令碼來模擬 tail 的功能。

wintail.sh 指令碼

#!/bin/bash -

WINLOG="Application"
LASTLOG=$(wevtutil qe "$WINLOG" //c:1 //rd:true //f:text)

while true
do
    CURRENTLOG=$(wevtutil qe "$WINLOG" //c:1 //rd:true //f:text)
    if [[ "$CURRENTLOG" != "$LASTLOG" ]]
    then
        echo "$CURRENTLOG"
        echo "
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
---
"
        LASTLOG="$CURRENTLOG"
    fi
done

這個指令碼會不斷檢查指定的 Windows 日誌是否有新的條目,並將新的條目輸出到螢幕上。

產生即時直方圖

若要計算一段時間內新增的日誌條目數量,可以結合 tail -f 和訊號(signal)機制來實作。

使用訊號進行程式間通訊

首先,需要定義兩個指令碼:一個用於計數日誌條目,另一個用於定時傳送訊號。

looper.sh 指令碼
#!/bin/bash -

trap 'echo "Count: $COUNT"; COUNT=0' SIGUSR1

COUNT=0
tail -f "$1" | while read line
do
    ((COUNT++))
done

這個指令碼會對輸入的日誌檔案進行計數,並在接收到 SIGUSR1 訊號時輸出計數結果。

使用訊號通知計數結果

另一個指令碼可以用來定時傳送 SIGUSR1 訊號給 looper.sh 指令碼,以觸發計數結果的輸出。

動態監控日誌檔案更新的 Shell 指令碼實作

在資安維運與系統監控領域,實時監控日誌檔案的更新對於及時發現系統異常至關重要。本文將深入解析一個利用 Bash Shell 實作的日誌檔案監控指令碼,並詳細闡述其設計思路、技術細節及應用場景。

實作原理與指令碼架構

該監控指令碼主要由兩個部分組成:looper.shtailcount.shlooper.sh 負責持續監控指定的日誌檔案,並統計單位時間內的日誌行數;tailcount.sh 則控制 looper.sh 的執行,並定期傳送訊號使其匯報統計結果。

looper.sh:日誌監控與統計指令碼

#!/bin/bash -

# 定義 interval 函式,用於匯報統計結果
function interval() {
    echo $(date '+%y%m%d %H%M%S') $cnt
    cnt=0
}

declare -i cnt=0
trap interval SIGUSR1
shopt -s lastpipe

# 持續監控日誌檔案更新
tail -f --pid=$$ ${1:-log.file} | while read aline; do
    let cnt++
done

內容解密:

  1. interval 函式:當接收到 SIGUSR1 訊號時被呼叫,輸出當前時間戳和已統計的日誌行數 $cnt,然後重置 $cnt 為 0。
  2. trap interval SIGUSR1:設定當接收到 SIGUSR1 訊號時,執行 interval 函式。
  3. shopt -s lastpipe:啟用 lastpipe 選項,使管道中的最後一個命令在當前 Shell 行程中執行,而非子 Shell。這樣可以確保 $cnt 的值在主行程中被更新。
  4. tail -f --pid=$$ ${1:-log.file}:持續監控指定的日誌檔案(預設為 log.file)。當當前 Shell 行程結束時,tail 命令也會終止。

tailcount.sh:控制指令碼

#!/bin/bash -

# 清理函式,用於結束背景行程
function cleanup() {
    [[ -n $LOPID ]] && kill $LOPID
}

trap cleanup EXIT

# 在背景執行 looper.sh
bash looper.sh $1 &
LOPID=$!

# 等待 looper.sh 初始化
sleep 3

# 每隔 5 秒傳送 SIGUSR1 訊號給 looper.sh
while true; do
    kill -SIGUSR1 $LOPID
    sleep 5
done >&2

內容解密:

  1. cleanup 函式:當 tailcount.sh 結束時,傳送 SIGTERM 訊號給 looper.sh 的行程,以清理背景行程。
  2. bash looper.sh $1 &:在背景啟動 looper.sh,並傳遞檔名引數。
  3. while true 迴圈:每隔 5 秒向 looper.sh 傳送 SIGUSR1 訊號,使其匯報統計結果。

livebar.sh:動態水平條形圖生成指令碼

#!/bin/bash -

function pr_bar() {
    local raw maxraw scaled
    raw=$1
    maxraw=$2
    ((scaled = (maxbar * raw) / maxraw))
    ((scaled == 0)) && scaled = 1 # 保證最小長度
    for ((i = 0; i < scaled; i++)); do
        printf '#'
    done
    printf '\n'
}

maxbar = 60 # 最大條形長度
MAX = 60

while read dayst timst qty; do
    if ((qty > MAX)); then
        let MAX = $qty + $qty / 4 # 調整最大刻度
        echo " **** rescaling: MAX=$MAX"
    fi
    printf '%6.6s %6.6s %4d:' $dayst $timst $qty
    pr_bar $qty $MAX
done

內容解密:

  1. pr_bar 函式:根據輸入值和最大刻度,列印對應長度的 # 條形。
  2. 動態調整最大刻度:當輸入值超過當前最大刻度時,自動調整最大刻度並重新縮放條形。

使用方法與應用場景

  1. 啟動監控:執行 bash tailcount.sh | bash livebar.sh,即可啟動日誌監控並動態顯示統計結果的水平條形圖。
  2. 應用場景:此指令碼組合可用於實時監控系統日誌、網路流量或其他需要動態統計的場景,幫助維運人員快速掌握系統狀態。

網路監控工具:偵測網路服務變更

在網路安全領域中,早期偵測敵對活動是關鍵。監控網路中新或未預期的網路服務(即開放的連線埠)是一種有效的偵測技術。這可以完全透過命令列實作。

建立網路監控工具

本章節中,我們將建立一個工具來監控網路中系統開放連線埠的變化。該工具的需求如下:

  1. 讀取包含 IP 位址或主機名稱的檔案
  2. 對檔案中的每個主機進行網路連線埠掃描,以確定開放的連線埠
  3. 將連線埠掃描的輸出儲存到以目前日期命名的檔案中
  4. 當指令碼再次執行時,將進行連線埠掃描,然後將結果與上次儲存的結果進行比較,並將任何變更顯示在螢幕上
  5. 自動化指令碼以每天執行一次,如果發生任何變更,則向系統管理員傳送電子郵件

使用的命令

本章節中,我們介紹 crontabschtasks 命令。

crontab

crontab 命令允許您編輯 Linux 系統上的 cron 表。cron 表用於排程任務以在特定時間或間隔執行命令。

常見的命令選項:

  • -e:編輯 cron 表
  • -l:列出目前的 cron 表
  • -r:刪除目前的 cron 表

schtasks

schtasks 命令允許您在 Windows 環境中排程任務以在特定時間或間隔執行命令。

常見的命令選項:

  • /Create:排程新的任務
  • /Delete:刪除排程的任務
  • /Query:列出所有排程的任務

步驟 1:建立連線埠掃描器

建立連線埠掃描器的第一步是讀取包含 IP 位址或主機名稱的檔案。對於檔案中的每個主機,您將嘗試連線到主機上的連線埠範圍。如果連線成功,您就知道該連線埠是開放的。

範例 9-1:scan.sh

#!/bin/bash -
# 網路安全操作與 bash
# scan.sh
# 描述:
# 對指定的主機進行連線埠掃描
# 用法:./scan.sh <輸出檔案>
# <輸出檔案> 儲存結果的檔案

function scan() {
  host=$1
  printf '%s' "$host"
  for ((port=1; port<1024; port++)) {
    # 重定向的順序很重要,有兩個原因
    echo >/dev/null 2>&1 < /dev/tcp/${host}/${port}
    if (($? == 0)); then printf ' %d' "${port}"; fi
  }
  echo # 或 printf '\n'
}

# 主迴圈
# 從標準輸入讀取每個主機名稱
# 並掃描開放的連線埠
# 將結果儲存到檔案中
# 其名稱作為引數提供
# 或預設為根據今天日期的名稱
printf -v TODAY 'scan_%(%F)T' -1 # 例如,scan_2017-11-27
OUTFILE=${1:-$TODAY}
while read HOSTNAME; do
  scan $HOSTNAME
done > "$OUTFILE"

內容解密:

  1. function scan() 定義了一個名為 scan 的函式,用於對指定的主機進行連線埠掃描。
  2. for ((port=1; port<1024; port++)) 迴圈遍歷從 1 到 1023 的連線埠號。
  3. echo >/dev/null 2>&1 < /dev/tcp/${host}/${port} 試圖建立到指定主機和連線埠的 TCP 連線。如果連線成功,則該連線埠是開放的。
  4. if (($? == 0)); then printf ' %d' "${port}"; fi 如果連線成功(傳回狀態為 0),則輸出開放的連線埠號。
  5. while read HOSTNAME; do scan $HOSTNAME; done > "$OUTFILE" 從標準輸入讀取主機名稱,對每個主機進行連線埠掃描,並將結果儲存到指定的輸出檔案中。

本章節介紹瞭如何使用 bash 指令碼建立一個簡單的網路監控工具,用於偵測網路服務的變更。透過結合 crontabschtasks 命令,可以實作自動化的網路監控和變更通知。指令碼首先讀取包含 IP 位址或主機名稱的檔案,然後對每個主機進行連線埠掃描,將結果儲存到檔案中,並與之前的結果進行比較,以檢測任何變更。

網路掃描與比較工具的實作細節

網路連線測試的關鍵步驟

在網路掃描工具的實作中,實際建立網路連線是至關重要的步驟。以下程式碼片段展示瞭如何使用bash shell實作對特定主機和埠的連線測試:

echo >/dev/null 2>&1 < /dev/tcp/${host}/${port}

內容解密:

  1. 重定向操作:這行程式碼利用了bash的特殊檔案名稱/dev/tcp/host/port來嘗試建立網路連線。
  2. 輸入重定向< /dev/tcp/${host}/${port}將標準輸入重定向到指定的網路連線。
  3. 輸出丟棄>/dev/null 2>&1將標準輸出和標準錯誤輸出都重定向到/dev/null,有效地丟棄了輸出結果。
  4. 邏輯判斷echo命令本身不讀取輸入,但嘗試開啟指定的網路檔案。如果成功,表示連線建立;否則,表示連線失敗。

日期與輸出檔名的處理

在掃描工具中,使用printf函式來格式化輸出日期和時間,並將結果儲存於變數中,以作為預設的輸出檔名。

TODAY=$(printf "%(%F)T" -1)

內容解密:

  1. printf格式控制%(%F)T指定了輸出的日期格式為ISO 8601(年-月-日)。
  2. -1引數:表示使用目前的時間作為輸出值。
  3. 變數儲存:將格式化後的日期字串儲存於TODAY變數中,用於後續的檔名生成。

掃描結果的比較邏輯

比較兩個掃描結果檔案,以找出主機開放埠的變化,是檢測網路變化的關鍵步驟。

while true; do
    read aline <&4 || break
    read bline <&5 || break
    # 比較alog與bline的內容
done 4< ${1:-day1.data} 5< ${2:-day2.data}

內容解密:

  1. 檔案描述符的使用:使用檔案描述符4和5來同時讀取兩個檔案。
  2. read命令:從指定的檔案描述符讀取一行內容,若到達檔案結尾則傳回錯誤並跳出迴圈。
  3. 比較邏輯:對比兩行內容,若不同則進一步解析埠變化。

埠變化檢測的實作

在比較邏輯中,進一步解析主機和埠資訊,以檢測埠的開啟或關閉狀態。

HOSTA=${aline%% *}
PORTSA=( ${aline#* } )
HOSTB=${bline%% *}
PORTSB=( ${bline#* } )

for porta in ${PORTSA[@]}; do
    LOOKFOR=$porta NotInList ${PORTSB[@]} && echo " closed: $porta"
done

for portb in ${PORTSB[@]}; do
    LOOKFOR=$portb NotInList ${PORTSA[@]} && echo " new: $portb"
done

內容解密:

  1. 主機與埠的解析:使用引數擴充套件來提取主機名稱和埠列表。
  2. NotInList函式呼叫:檢查某個埠是否出現在對方的列表中,若不存在則輸出相應的狀態變化訊息。

網路監控工具的自動化與排程

在前面的章節中,我們介紹了一個用於監控網路變化的指令碼工具。為了提高該工具的實用性,我們將進一步探討如何實作自動化執行以及如何設定排程任務,以便定期執行指令碼並在發現變化時通知使用者。

自動化執行與通知

手動執行指令碼雖然可行,但更理想的方式是能夠定期自動執行並在檢測到變化時通知使用者。autoscan.sh 指令碼結合了 scan.shfd2.sh,能夠掃描網路並輸出變化。

autoscan.sh 指令碼解析

#!/bin/bash -
# 網路安全營運使用 bash
# autoscan.sh
# 描述:
# 自動執行埠掃描(使用 scan.sh),
# 比較輸出與之前的結果,並透過電子郵件通知使用者
# 假設 scan.sh 位於當前目錄。
# 用法:./autoscan.sh
./scan.sh < hostlist
FILELIST=$(ls scan_* | tail -2)
FILES=( $FILELIST )
TMPFILE=$(tempfile)
./fd2.sh ${FILES[0]} ${FILES[1]} > $TMPFILE
if [[ -s $TMPFILE ]] # 非空
then
    echo "郵寄今天的埠差異到 $USER"
    mail -s "今天的埠差異" $USER < $TMPFILE
fi
# 清理
rm -f $TMPFILE

#### 內容解密:

  1. ./scan.sh < hostlist:執行 scan.sh 指令碼並從 hostlist 檔案中讀取主機列表進行掃描。
  2. FILELIST=$(ls scan_* | tail -2):列出所有以 scan_ 開頭的檔案,並取得最新的兩個檔名稱。
  3. FILES=( $FILELIST ):將檔案列表轉換為陣列,方便後續操作。
  4. TMPFILE=$(tempfile):建立一個臨時檔案,用於存放比較結果。
  5. ./fd2.sh ${FILES[0]} ${FILES[1]} > $TMPFILE:比較最新的兩個掃描結果,並將差異輸出到臨時檔案中。
  6. if [[ -s $TMPFILE ]]:檢查臨時檔案是否非空,如果非空,表示有變化。
  7. mail -s "今天的埠差異" $USER < $TMPFILE:將變化內容透過電子郵件傳送給使用者。

在 Linux 中排程任務

要在 Linux 中排程任務,首先列出現有的 cron 檔案:

$ crontab -l
no crontab for paul

然後,使用 -e 選項建立和編輯新的 cron 檔案:

$ crontab -e

在 cron 檔案中新增一行,使 autoscan.sh 每天早上 8:00 執行:

0 8 * * * /home/paul/autoscan.sh

#### 內容解密:

  • 0 8 * * * 指定了執行時間為每天的 8:00 AM。
  • /home/paul/autoscan.sh 是要執行的指令碼路徑。

在 Windows 中排程任務

要在 Windows 中排程任務,需要透過 schtasks 命令來實作。由於 autoscan.sh 是 Bash 指令碼,需要透過 Git Bash 來執行:

schtasks //Create //TN "網路掃描器" //SC DAILY //ST 08:00 //TR "C:\Users\Paul\AppData\Local\Programs\Git\git-bash.exe C:\Users\Paul\autoscan.sh"

#### 內容解密:

  • //Create 表示建立一個新的任務。
  • //TN "網路掃描器" 指定任務名稱。
  • //SC DAILY 設定排程頻率為每天。
  • //ST 08:00 指定開始時間為早上 8:00。
  • //TR 後面跟著要執行的命令和指令碼路徑。