Confucius APT組織樣本分析
目的
網上看到一個較新的Confucius APT樣本,這里記錄一下分析過程,主要目的是提取C&C以及分析其流量特征
初步分析
為了能夠調試dll,設置x64dbg的命令行如下
"C:\Windows\SysWOW64\rundll32.exe" C:\Users\l\Desktop\d345a80e349b79c78faa9bf10922416b0d5cfb1b805e0bfb2f675d83f63c7e47\1.dll,version
跑起來直接異常了,只能先靜態看看
從IDA中發現有一些加密的字符串,并且加密字符串后續的操作疑是解密過程
結合x64dbg在解密函數開頭設置新的運行點可以發現解密的過程就是異或0x1D


通過IDA腳本解密出部分xor編碼的字符串
import idc
import idaapi
def getStrAddress(addr):
addr = prev_head(addr)
if print_insn_mnem(addr) == "push" and "offset" in print_operand(addr,0):
return get_operand_value(addr,0)
else:
return 0
def getEncodeStr(addr):
out = ""
while(True):
ch = idaapi.get_byte(addr)
if ch != 0:
out += chr(ch)
else:
break
addr += 1
return out
def getDecodeStr(str):
i = 0
out = ""
length = len(str)
while i < length:
out += chr(ord(str[i]) ^ 0x1d)
i += 1
return out
if __name__ == '__main__':
try:
for x in XrefsTo(0x1001E410,flags = 0):
addr = getStrAddress(x.frm)
if addr == 0:
continue
eStr = getEncodeStr(addr)
if eStr == "":
continue
dStr = getDecodeStr(eStr)
set_cmt(prev_head(x.frm), dStr, 0)
except:
print("Error")
解密出部分字符串,發現有檢測windows版本的功能,以及C&C


深入分析
二進制代碼中有大量的mov操作,以及利用try catch的混淆手段擾亂著代碼塊,靜態看起來比較復雜。


硬著頭皮看了一段時間后發現樣本中竟然有log函數

通過log函數我們就能很方便的梳理出樣本的大致邏輯了。

大致的邏輯是獲取dll name,獲取計算機名,發送ping包等(在分析的過程中發現還有一些操作沒有通過log函數記錄,不過這也不影響我們分析其流量特征了)


為了獲得流量特征定位到first ping,這里就是發送第一個數據包的地方

往上找找有一個send操作,為了方便查看流量特征,現在得想辦法讓dll正常跑起來,并在send下斷點,查看buf的值。

由于前面動態調試的時候一直報異常,第一反應是有反調試,也的確發現了反調試API。,但下斷點后發現在反調試之前就已經異常了。


通過棧回溯定位到異常產生的函數,分析發現該函數有路徑字符串替換的功能,這里意識到樣本的啟動與路徑有關。


為了搞清楚該dll啟動的方式和啟動路徑,需要先獲取上一階段word文檔中的VB宏。


對上面的VB腳本進行解密,獲取到powershell腳本
import string
bpw = string.ascii_lowercase
gfgdfgefugwrifgr = bpw[18] + bpw[2] + bpw[17] + bpw[8] + bpw[15] + bpw[19] + bpw[8] + bpw[13] + bpw[6] + chr(46) + bpw[5]
oherfuirfgrgfffwfwe = bpw[8] + bpw[11] + bpw[4] + bpw[18] + bpw[24] + bpw[18] + bpw[19] + bpw[4] + bpw[12] + bpw[14] + bpw[1] + bpw[9] + bpw[4] + bpw[2] + bpw[19]
p3rhfrbbgoigrtgreg = chr(67) + chr(58) + chr(92) + "U" + bpw[18] + bpw[4] + bpw[17] + bpw[18] + chr(92) + "P" + bpw[20] + bpw[1] + bpw[11] + bpw[8] + bpw[2] + chr(92)
jvpgvwfwg4tuh5yjat4rtgfrfhg = "D" + bpw[14] + bpw[22] + bpw[13] + bpw[11] + bpw[14] + bpw[0] + bpw[3] + bpw[18] + chr(92) + bpw[6] + bpw[8] + bpw[18] + bpw[19]
pqwefbevfgvugrgfv = "." + bpw[19] + bpw[23] + bpw[19]
jfur6yroo97ighgyte6 = bpw[18] + bpw[2] + bpw[7] + bpw[4] + bpw[3] + bpw[20] + bpw[11] + bpw[4] + "." + bpw[18] + bpw[4] + bpw[17] + bpw[21] + bpw[8] + bpw[2] + bpw[4]
Path = bpw[15] + bpw[14] + bpw[22] + bpw[4] + bpw[17] + bpw[18] + bpw[7] + bpw[4] + bpw[11] + bpw[11]
pbvfewi4regfergf8734 = " -" + bpw[22] + " " + bpw[7] + bpw[8] + bpw[3] + bpw[3] + bpw[4] + bpw[13] + " " + bpw[8] + bpw[4] + bpw[23] + " ((["
pfjs3jdnbighgtohthhf = "S" + bpw[24] + bpw[18] + bpw[19] + bpw[4] + bpw[12] + ".T" + bpw[4] + bpw[23] + bpw[19] + ".E" + bpw[13] + bpw[2] + bpw[14] + bpw[3] + bpw[8] + bpw[13] + bpw[6] + "]::A" + "SC" + "II)." + "G" + bpw[4]
pqk3ggnolhzbzgbid8rg = bpw[19] + "S" + bpw[19] + bpw[17] + bpw[8] + bpw[13] + bpw[6] + "(([" + bpw[18] + bpw[19] + bpw[17] + bpw[8] + bpw[13] + bpw[6] + "](" + bpw[6] + bpw[4] + bpw[19] + "-" + bpw[2] + bpw[14] + bpw[13] + bpw[19] + bpw[4] + bpw[13] + bpw[19] + " -p" + bpw[0] + bpw[19] + bpw[7] + " "
poht95bgsf894bgiu538 = "))." + bpw[18] + bpw[15] + bpw[11] + bpw[8] + bpw[19] + "('#')))." + bpw[17] + bpw[4] + bpw[15] + bpw[11] + bpw[0] + bpw[2] + bpw[4] + "('?','')"
pef = pbvfewi4regfergf8734 + pfjs3jdnbighgtohthhf + pqk3ggnolhzbzgbid8rg + p3rhfrbbgoigrtgreg + jvpgvwfwg4tuh5yjat4rtgfrfhg + pqwefbevfgvugrgfv + poht95bgsf894bgiu538
str1 = "239#......"
str1 = str1.split("#")
str1 = map(chr ,map(int, str1))
str1 = "".join(str1)
print(str1)

在x64dbg下構造新的命令行后成功跑起來

后續的調試就相對簡單了,發送的buf復用了之前的xor函數以及一個base64函數,并使用"#$#*"進行分隔,"iqaz"字符串作為結束符

至此我們就成功提取到了該樣本的C&C以及流量特征

參考
http://blog.nsfocus.net/aptconfuciuspakistanibo/