01shellcode简介
shellcode是一段用于利用软件漏洞而执行的代码,shellcode为16进制的机器码,因为经常让攻击者获得shell而得名。shellcode常常使用机器语言编写。可在暂存器eip溢出后,塞入一段可让CPU执行的shellcode机器码,让电脑可以执行攻击者的任意指令。
1.1 依赖项
因Shellcode有一些依赖关系,所以编写Shellcode存在一定难度。
- 长度 - 因为 shellcode 利用内存中的特定漏洞,所以序列需要尽可能的高效。这意味着攻击者必须使其长度适合于缓冲区的大小,所有的指令都将在内存空间中运行。如果shellcode的长度大于缓冲区的大小,可能造成程序崩溃或甚至被非法利用(如缓冲区溢出等)。
- 不允许的字符 - 当shellcode 中出现‘\r’, ‘\n’,0x00等字符时,代码将终止运行。例如,当'Null Bytes'(如0x00值)被读取时,CPU会将它识别为字符串的结束(Null Terminator)。
1.2 Unix Shellcode
Unix操作系统提供了直接访问通信和管理内核的途径—指令int 0x80。因此,当系统调用跟随该指令设置时,shellcode 将直接被赋予以高权限执行的能力。
1.3 Windows Shellcode
在基于Windows的操作系统中,由于内存保护机制,如ASLR(地址空间布局随机化)等,创建shellcode比较困难。
02内存中查找 API 函数的地址
一般情况下,shellcode会被注入到一个正在运行的进程中,没有任何关于内存状态以及 API 函数地址的预先知识,据此可以得出结论:shellcode不能以静态地址为基础。
如上所述,shellcode不能使用Call CreateProcessA或jmp sub_40100000这样的指令,必须独立运行才能找到所需的 API 函数并手动解析地址。换句话说,要找到使用的DLL需要基于内存中对象的结构。这也是它被称为位置无关代码(PIC)的原因。
示例:要调用GetProcAddress,shellcode 需要找到Kernel32.dllDLL 的地址。
操作流程如下:
2.1 PEB - 过程环境块
因PEB 对象总是被加载到内存的同一个地址FS:[0x30],所以 shellcode 可以使用。
执行步骤:
转到 PEB 对象。
传递PEB_LDR_DATA对象到InMemoryOrderModuleList链表,其中包含有关进程加载模块的信息。在此之后,shellcode 将保存所需模块(通常Kernel32.dll是第三个对象)。
DllBase 使用该字段查找所需 DLL 的基地址。
找到它的导出表。
找到想要的功能(如GetProcAddress)。
使用函数获取函数的地址GetProcAddress。
最终,使用合适的参数运行想要的功能。
2.2 使用SEH—结构化异常处理
该技术是通过输入TIB(线程信息块)的第一个属性来访问SEH链的底部,它有一个常数地址--FS:[0x0]。该地址包含Kernel32.dll模块的默认异常处理程序。要定位所需模块的地址,可以返回内存地址,直到找到模块的入口点为止。(使用MZ签名或0x5A4D为例)。
2.3 使用TEB——线程环境块
与 SEH 技术一样,可以访问 TEB 对象,该对象在内存中有固定的位置 — FS:[0x18]. 通过这个对象可以进入 SEH 链,如上所述。
2.4 TopStack
该方法依赖于在堆栈中具有所需 API 函数的所需 DLL 的地址,所以并不常见。
2.5 通过哈希查找API 函数
这种技术也被称为SFHA(Stephen Fewer’s Hash API)。它使用4个字节来表示DAX寄存器中的DLL!WinAPI内部函数的Hash值。然后向该地址发送JMP调用该函数。需要注意哪个函数从EAX被调用,以及得到了哪些参数(可以在MSDN中查看)。接下来比较内存中的实际值。例如,如果一个shellcode调用Win_Exec函数,将通过每一个DLL!WinApi使用其他技术之一,并带有其他参数(可以通过寄存器调用前的PUSH指令识别)。当输入参数的内存地址时就可以知道该地址的内容是什么(也许是PS1脚本或编码命令)。
03shellcode检测
对shellcode有所了解之后,下面探讨如何检测 shellcode。
首先注意去掉混淆,解密一个混淆或加密的脚本,以暴露出shellcode真实代码。
3.1 使用行为模式
如上所述,shellcode 是表示指令的 Opcodes 序列。因此可以找到这个序列并对其进行检查。
如果有恶意程序的源代码运行 shellcode(如 PowerShell 或 JavaScript),可以寻找可能代表Opcodes的值/变量/字符串,该方式有利于找到shellcode本身。
下面来看这条指令:mov ebp, esp。shellcode使用的字符序列可以有多种格式:
十六进制值:8B EC
反斜杠十六进制值:\x8B\EC
Unicode 百分比: %u8B%EC
反斜杠 Unicode:\u8B\uEC
Array:[0x8B, 0xEC]
重点关注这些字符的序列可以代表 CPU 指令。
04转储 shellcode
在检测到潜在的 shellcode 后,将其转储到二进制文件是第一步。
- base64dump.py工具 — 允许查找可能包含 shellcode 的部分并将其转储到二进制文件 ( .bin) 中,以便对其进行分析
- 参数:
pu — 允许搜索用于百分比 Unicode 编码 ( %u) 的字符串。
bu — 允许搜索用于反斜杠 Unicode 编码 ( \u) 的字符串。
hex — 允许搜索用作十六进制值的字符串。
base64 — 允许使用 Base64 编码搜索字符串。
base64dump.py -e {param} {file} -s {sectionID} -d > {outFile.bin}
允许通过 ID 定位想要的部分,并将其转储到二进制文件中。大多数情况下将选择最大的部分
base 64 dump . py { param }{ file }- s { section ID }- a
显示所选部分的十六进制视图。
objdump.pytool — 允许在提取 shellcode 时转储。
Using a Hex-Editor — Hex-Editor 可用于删除不相关的部分,剩下的 shellcode代码可以保存到.bin文件中。
05如何分析shellcode
可以通过两种主要方式分析 shellcode :静态分析和动态分析。
5.1 静态分析——代码分析
通过静态分析,包含 shellcode 的二进制文件将被转换为可执行文件,并被加载到反汇编程序(如 IDA PRO)中。然后被分析为可执行文件。
用法:
shellcode2exe.py {file.bin}shellcode2exe.bat {32\64} {file.bin} {file.exe}
5.2 动态分析
scdbg工具--允许模拟shellcode的执行,以便找到它所使用的API函数,这可以表明shellcode的许多行为。
scdbg -s {steps} -f {file.bin}
运行GUI scdbg工具并向其启动二进制文件。
使用FindSC将在加载的二进制文件中找到shellcode的开头。
jmp2it工具--允许在一个专门的进程中执行shellcode,该进程作为可执行文件的 "外壳"。因此可以将调试器附加到运行的进程中,便于分析人员调试shellcode。
jmp2it {file.bin} {offset}—offset表示 shellcode 从二进制入口点的偏移量(0x0用于开始)。
shellcode_launcher.exe--与之前的工具类似。