2016年11月6日 星期日

Mirai程式碼分析

Mirai程式碼分析

Mirai 是一網路殭屍病毒,名稱可能是取自日文「未来」,最近作者Anna-senpai開放原始碼,正好可以一窺殭屍病毒作法。本篇針對其程式流程做一介紹,希望在開發自家產品時,能夠避開這些攻擊方法,避免成為殭屍大軍一員。

針對殭屍病毒,需要先了解幾個名詞
Zombies: 被控制的電腦(又可稱為robot,一般簡寫為bot)
CNC: Command And Control,就是決定何時發動攻擊的控制中心

Mirai 的基本運作方式
  1. 每個 bot 會根據 Table.c 內的 TABLE_CNC_DOMAIN, 連到某一個 CNC, 因為是 domain name, 所以實際解析出來的 IP 位址是可變的。 
  2. 因為 TCP 有 3way handshake 機制 (SYNC, ACK, SYNC+ACK), bot 會利用 SYN scanner 找到網路上有開放 port(23) 的機器 (機器會回應 SYNC-ACK),並試著將字典內的所有帳號密碼都測試一次,若能夠登入Telnet,則將掃描結果回報另一台伺服器。
  3. bot 透過 port 48101 回傳結果給 scan receiver,mirai/tools/scanListen.go 會負責處理回傳結果,將找到的機器的 ip, username, password 都打印出來。
  4. 接著 scan receiver 便可以透過 telnet 登入機器,稱此機器為機器 A。
  5. 若機器 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_*.c
各種攻擊基本上都是使用 setsockopt(IP_HDRINCL),根據各種漏洞,自行製作會引發問題的 IP 封包。
killer_init()
刪除 port 23, 22, 80 對應的行程,也就是關閉 telnet, ssh, http 服務,
並且占用這三個對應的 port,如此便可以避免 telnet, ssh, http 服務重啟。 如此沒有人可以登入這台機器,也就避免 mirai 被發現。
scanner_init()
將各種預設帳號密碼加入 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,
接著在 port 23 與 101 各建立一個 socket, 等待資料
port 101 接收的資料由 initialHandler() 負責處理
port 23 接收的資料由 apiHandler() 負責處理
initialHandler() 可參考 bot.go
若收到的訊息長度為四,且符合 0x0000000x,x>0,便會在 clientList 新增一筆資料,記錄新的 bot。否則便是新增一個新的管理者帳號 (ADMIN)。
apiHandler() 可參考 api.go
收到訊息後,會先呼叫 CheckApiCode() 取得使用者的資訊,接著解析收到的訊息,並通知 bot 進行攻擊,共可採用十種攻擊方法

當設備有下列缺陷,便可能成為殭屍大軍一員
1. 預設開放 Telnet 
2. 設備的預設帳號密碼列在 mirai source code 之中。
    下面列出 mirai 收集的帳號密碼

建議避免 Mirai 感染的方式便是

  1. 機器預設不要開放 Telnet
  2. 強制使用者登入機器之後,就得要修改帳號密碼。