有一題丟一行指令給我,內容大概是連到某個網址、下載一個腳本、然後把它跑起來。問這行代表什麼。
我選了「已經建立持久化」。
正解只是「執行了那個腳本」。
我當時的想法是:都下載回來跑了,接下來當然是要長期待著啊。但那行字裡沒有寫登錄機碼、沒有排程、沒有註冊服務,持久化該留的痕跡一個都沒有。是我自己接上去的。
這件事後來變成我讀指令的習慣:先讀這行字做了什麼,不要跳到做這件事的人想幹嘛。
下載加執行,終點就是執行。
把某個路徑加進防毒的排除清單,字面上就是改了一個設定。至於之後會不會有東西塞進那個路徑、是不是要藏東西,那行字沒講。
考試問的通常是前面那個字面,後面那個意圖是我腦補的。我腦補的方向還特別愛往最嚴重的那邊倒。
另一種我栽過的,是那種一長串看不懂的指令。最常見的是 PowerShell 的 -EncodedCommand,後面接一串 base64。
我當時的直覺跟 Day08 一模一樣——丟進 VM 跑跑看不就知道了。但跑起來就是引爆,跟直接雙擊那個檔沒兩樣。
-EncodedCommand 的意思其實很單純,就是把一段指令用 base64 編碼包起來,讓它可以塞進一行、不用處理一堆引號。要看它到底寫什麼,把那串 base64 解開來就好,解開這個動作本身不會執行任何東西。
我自己編一段來試。先做一串出來:
# 在 Linux 上
echo -n 'Write-Output "hello ironman"' | iconv -t UTF-16LE | base64
# 得到:VwByAGkAdABlAC0ATwB1AHQAcAB1AHQAIAAiAGgAZQBsAGwAbwAgAGkAcgBvAG4AbQBhAG4AIgA=
拿到這種東西,反過來解:
echo 'VwByAGkAdABlAC0ATwB1AHQAcAB1AHQAIAAiAGgAZQBsAGwAbwAgAGkAcgBvAG4AbQBhAG4AIgA=' | base64 -d | iconv -f UTF-16LE
# Write-Output "hello ironman"
Windows 上不用裝東西,PowerShell 內建就能解:
[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('VwByAGkAdABlAC0ATwB1AHQAcAB1AHQAIAAiAGgAZQBsAGwAbwAgAGkAcgBvAG4AbQBhAG4AIgA='))
那段指令原本寫什麼,就這樣攤在眼前了,它一次都沒有跑起來。
這裡有個小地方我一開始沒注意:PowerShell 的 -EncodedCommand 吃的是 UTF-16LE(也就是它文件裡寫的 Unicode),不是一般的 UTF-8。所以解 base64 之後還要再用 UTF-16LE 轉一次,不然會看到每個字中間卡一個怪怪的空格。這個微軟自己的文件裡有寫。
順帶一提,這種一行指令常常還會夾一些旗標,像 -nop(不載入設定檔)、-w hidden(視窗藏起來)、-ep bypass(跳過執行原則)。
-ep bypass 我以前以為是什麼很厲害的破解。後來查了才知道,PowerShell 的執行原則本來就不是拿來擋人的安全邊界,微軟自己在文件裡就寫它是「defense in depth,不是 security boundary」,它防的是使用者不小心跑到腳本,不是防真的想跑的人。所以加一個 bypass 上去,對攻擊者來說幾乎是免費的,這也是為什麼這串東西那麼常出現。
-e 是兩件事netcat(nc)我栽在方向上。
nc -l -p 43501 < example.zip,問這行發生了什麼。我答「準備接收 example.zip」。
正解是相反的,這台是把 example.zip 送出去。
-l 是監聽,這個我知道。錯在 < 跟 >。< 是把後面那個檔案的內容讀進來當輸入,所以有人連上來,這個檔就往外送;要接收存檔應該用 >,把收到的東西寫進檔案裡。
< 讀取、> 寫入這條規則在 shell 裡我天天用,換成 nc 的情境就被帶偏了。現在我會多念一次:< 是這個檔案的內容要出去,> 是資料要進來存成這個檔案。
還有一種 netcat 是完全不同的用途,-e cmd.exe(或 -e /bin/sh)這種。它是把整個命令列接到這條連線上,讓連線的另一端可以直接操控這台機器。
所以看到 -e <某個 shell>,跟只有 < > 的檔案傳輸不是同一類。一個是對方拿到了在這台機器下指令的能力,一個只是資料在進出。題目很愛把這兩種放在相鄰的題目互相對照。
指令是讀字面,log 我後來的做法是先確定每一欄記的是誰。
有一行 Linux 認證紀錄大概長這樣:
Aug 30 09:46:54 ip-172-30-0-62 sshd[3051]: Accepted publickey for ec2-user from 10.174.238.88 port 57478
問使用者是從哪裡連進來的。我答了前面那個 172.30.0.62。
那個其實是本機自己。雲端主機(這是 AWS 的命名習慣)會把自己的私有 IP 塞進主機名裡,所以行首那個看起來像 IP 的東西,是「誰在寫這行紀錄」,不是「誰連進來」。真正的來源在 from 後面,是 10.174.238.88。
syslog 每一行開頭的主機名,講的都是寫這行紀錄的那台機器自己。要找連線來源,看 from。
Linux 這邊還有幾個位置我後來記起來的:
/var/log/secure,Debian 這系在 /var/log/auth.log。.bash_history。.bash_history 這個我要多講一句。有題目給過看起來很像真的路徑,像是把指令記錄存成某個 .sqlite 檔、或某個 /var/log/ 底下的檔案。那些是編出來的,Bash 就是把歷史記在純文字的 .bash_history 裡,沒有什麼內建的 SQLite。當然它也很好清,history -c 或直接刪檔就沒了,所以題目如果特別強調「假設對方沒做反鑑識」,通常就是在把答案往這個標準位置導。
| 我錯在哪 | 怎麼改善 |
|---|---|
| 把「下載後執行」讀成已經持久化 | 持久化該有的動作,這行裡有嗎 |
| 把一長串 base64 直接丟去跑 | 先解開,它字面寫什麼 |
把 nc -l < file 讀成接收 |
< 是進還是出 |
| 把 syslog 行首主機名當成來源 | 這一欄記的是誰 |
寫出來才發現都是同一個毛病:我讀到的東西不夠我下那個結論,但我還是下了。指令跟 log 大多時候不用推理,把字面讀完、把欄位對準,答案常常就在上面。
base64 那段現在就可以試。開一個 PowerShell,把上面那行 [Text.Encoding]::Unicode... 貼進去,看它把那串 base64 還原成什麼。整個過程你只是在解碼,沒有執行任何下載或連線的動作。
netcat 想玩的話,找兩台自己的機器(或兩個終端機),一邊 nc -l -p 4444 < 某個檔,另一邊連過去收,看檔案往哪個方向跑。
nc -e 那種把 shell 接出去的用法,只在自己完全掌控、而且沒有連到外網的環境裡試。這等於在自己機器上開一個後門,接錯地方就真的是後門了。