Mirai 是一網路殭屍病毒,名稱可能是取自日文「未来」,最近作者Anna-senpai開放原始碼,正好可以一窺殭屍病毒作法。本篇針對其程式流程做一介紹,希望在開發自家產品時,能夠避開這些攻擊方法,避免成為殭屍大軍一員。
針對殭屍病毒,需要先了解幾個名詞
Zombies: 被控制的電腦(又可稱為robot,一般簡寫為bot)
CNC: Command And Control,就是決定何時發動攻擊的控制中心
Mirai 的基本運作方式
- 每個 bot 會根據 Table.c 內的 TABLE_CNC_DOMAIN, 連到某一個 CNC, 因為是 domain name, 所以實際解析出來的 IP 位址是可變的。
- 因為 TCP 有 3way handshake 機制 (SYNC, ACK, SYNC+ACK), bot 會利用 SYN scanner 找到網路上有開放 port(23) 的機器 (機器會回應 SYNC-ACK),並試著將字典內的所有帳號密碼都測試一次,若能夠登入Telnet,則將掃描結果回報另一台伺服器。
- bot 透過 port 48101 回傳結果給 scan receiver,mirai/tools/scanListen.go 會負責處理回傳結果,將找到的機器的 ip, username, password 都打印出來。
- 接著 scan receiver 便可以透過 telnet 登入機器,稱此機器為機器 A。
- 若機器 A 有現成的 wget 或 tftp,便會直接使用它們下載執行檔mirai,否則會使用一個自帶的wget下載mirai. (mirai/tools/wget.c)接著執行mirai, 然後機器 A 就變成了一個新的殭屍電腦(bot)。
基本上要測試此方法,最少要有兩台伺服器。其伺服器用途如下:
2 servers: 1 for CNC + mysql, 1 for scan receiver
最好是能夠將 mysql 分別架設在另一台伺服器,並且額外提供 load balancing server
Mirai 程式碼分析
1. bot
main(),
一旦程式開始執行之後,首先做的就是隱藏自己,包含以下動作
- 首先把自己刪除 (刪除檔案系統內的 mirai 執行檔)。
- 接著註冊 SIGTRAP,避免有人利用 gdb 了解程式運作流程。
- 關掉 watchdog,避免機器因為 watchdog 重啟。命令是ioctl(wfd, 0x80045704, &one);
- 試著 bind port 48101,若成功,就進行 listen等待連接。若失敗,表示有其他行程正在使用 48101,刪除現在正在占用 48101 的行程並且再試一次。此處 killer_kill_by_port() 函數的作法值得一看。
- 亂數產生程式名稱,改變 argv[0] 以及 行程的名稱,並且在STDOUT內加入此執行檔的紀錄。因為是亂數產生的名稱,因此使用 ps 檢視可以很容易看出問題。所以後面要關閉可能使用 ps 檢視系統資訊的各種遠端登入方式。(如:telnet,ssh, http)
- 接著執行 attack_init(), killer_init(), scanner_init(),然後建立連線至 CNC Server,此連線記錄在 fd_serv。
- 最後執行下列程式邏輯
if (pending_connection)
pending_connection = FALSE;
通知 CNC, 送出初始訊息, 會先送出 0x00000001, 再送出 id
else
等待 CNC送來的命令,若收到攻擊命令,就開始進行 DOS 攻擊。attack_start()
attack_init()
初始化攻擊類型,目前共提供十種攻擊方法,所有攻擊方法都放在 Attack_*.ckiller_init()
各種攻擊基本上都是使用 setsockopt(IP_HDRINCL),根據各種漏洞,自行製作會引發問題的 IP 封包。
刪除 port 23, 22, 80 對應的行程,也就是關閉 telnet, ssh, http 服務,scanner_init()
並且占用這三個對應的 port,如此便可以避免 telnet, ssh, http 服務重啟。 如此沒有人可以登入這台機器,也就避免 mirai 被發現。
將各種預設帳號密碼加入 mysql,這些帳號密碼都會使用 0xdeadbeef 作 XOR 運作。
接著產生 connection table,共可記錄 128 組連線資訊
隨意產生 160 組 Public IP 位址,試著看看這些 IP 是否會對 port 23 有反應。(回SYNC-ACK)
若有回應,則會將此連線資訊紀錄至 connection table
若 connection table 有值,則隨意從資料庫內挑一組帳號密碼,試試能否正確登入機器。總共會測試十次,每次使用不同帳號密碼
若發現可以正確連線,會將可正確建立TELNET連線的資訊告知 scan receiver.
由 scan receiver 負責針對機器植入木馬。
establish_connection()
自動連線到 CNC Server注意:此處 table_lock_val() 與 table_unlock_val() 都是同樣的處理邏輯,
把記憶體內容與 0xdeadbeef 作 XOR 運算,並且設定 val->locked = !val->locked; 此作法值得參考
2. Loader (scan receiver)
先載入 bins/ 目錄下的所有執行檔,後續可以根據此時所在的硬體平台,直接呼叫當作函數檔案內對應的直接呼叫。此處 binary_init() 值得參考
啟動一個 Server Process, 並且根據CPU個數,分別建立對應的 worker threads。
主程式會從 STDIN 讀取 telnet 相關資訊,分析後進行連線,並將此事件透過 epoll_ctl 加入監聽列表重複上述 STDIN 讀取動作,直到 STDIN 沒有值可讀取。
worker thread 則會等待 epoll_wait()返回,一旦有事件觸發,便會呼叫 handle_events,根據事件的狀態,進行相對應的任務。
任務的終極目的是登入機器,找到可以寫入的磁碟空間,透過 wget 或 tftp 將 Mirai 搬移至機器內,並且執行Mirai(bot)。
3. CNC
先參考 main.go
此程式會建立 clientlist 與 database,initialHandler() 可參考 bot.go
接著在 port 23 與 101 各建立一個 socket, 等待資料
port 101 接收的資料由 initialHandler() 負責處理
port 23 接收的資料由 apiHandler() 負責處理
若收到的訊息長度為四,且符合 0x0000000x,x>0,便會在 clientList 新增一筆資料,記錄新的 bot。否則便是新增一個新的管理者帳號 (ADMIN)。apiHandler() 可參考 api.go
收到訊息後,會先呼叫 CheckApiCode() 取得使用者的資訊,接著解析收到的訊息,並通知 bot 進行攻擊,共可採用十種攻擊方法
當設備有下列缺陷,便可能成為殭屍大軍一員
1. 預設開放 Telnet
2. 設備的預設帳號密碼列在 mirai source code 之中。
下面列出 mirai 收集的帳號密碼
建議避免 Mirai 感染的方式便是
- 機器預設不要開放 Telnet
- 強制使用者登入機器之後,就得要修改帳號密碼。