作者:Kevin Clark
红队对抗模拟 · 恶意代码分析
https://trustedsec.com/blog/operating-inside-the-interpreted-offensive-python


一、引言

我时常会回头复盘那些早年盛行、如今在攻击圈渐渐失宠的技术手段。Office宏、PowerShell、自定义ShellCode加载器这类技术曾经无往不利,但如今不少行业同行都称它们已经“失效暴露”。
这话虽有一定道理,但在实际渗透作业中,我和团队多次发现,这些所谓“被标记”的战术、技术与流程(TTP)依然能发挥奇效,时常带来意料之外的突破。

本文将重点介绍另一套老牌攻击手段:Windows平台下基于Python构建恶意载荷。开篇先梳理该领域过往相关研究成果。

二、Python恶意程序

黑客使用Python编写恶意代码由来已久,从Python反弹Shell,到Py2Exe打包简易植入程序,层出不穷。我最早接触的Python攻击工具是Chris Truncer开发的Veil Evasion项目,该工具2013年首次发布,能将Python代码转化为可执行Shell载荷,在当年堪称“黑科技”。

此后不久,微软宣布PowerShell预装于全系列Windows系统,开启了PowerShell攻击工具的黄金时代:PowerSploit初代工具集及大量衍生攻击脚本陆续问世,依托系统自带的PowerShell环境即可直接执行。
相较之下Python恶意程序逐渐边缘化——目标主机必须预先安装Python解释器才能运行相关代码。

但好景不长,微软对PowerShell做出大幅整改:引入反恶意软件扫描接口(AMSI)、完善各类行为日志记录机制,大幅提升了PowerShell恶意代码的开发与免杀门槛。最终攻击工具开发者纷纷放弃PowerShell,重新转向C、C++这类非托管原生语言。

2018年末,微软在微软商店(原Windows商店)上架Python程序。我时隔数年才意识到这套安装流程极其简便,相信很多安全从业者此前也并未留意。
2022年,Diego Capriotti推出纯Python编写的漏洞利用框架Pyramid,在我看来,这标志着现代Python攻击工具正式成型。同期Anthony Rose发布了嵌入.NET环境的Python3引擎实现方案,灵感源自图拉(Turla)组织的IronNetInjector恶意代码。依托该方案,无需在目标主机安装Python解释器,就能直接在Windows上运行Python代码。

如今Windows系统获取Python的渠道十分便捷,配套攻击工具生态也逐步完善。在恶意代码开发领域,Python已经形成一块独特且实用的攻击细分赛道。

三、从微软应用商店安装Python

前文提到,通过微软商店可以一键安装Python。现代Windows系统只需打开微软商店,搜索“Python”即可,商店内提供3.7至3.13全系列版本。点击“获取”按钮就能下载,全程无需管理员权限

除此之外,微软商店提供专属协议跳转链接,已知对应程序ID即可直接拉起安装页面。以Python3.13为例,跳转地址:
ms-windows-store://pdp/?ProductId=9pnrbtzxmb4z

安装完成后,可通过开始菜单启动Python,也能直接运行路径下的引导程序:
C:\Users\[用户名]\AppData\Local\Microsoft\WindowsApps\

四、Python离线下载与安装

部分场景无法通过微软商店在线安装Python,典型情况包括:

  1. 仅能使用命令行,无图形界面操作权限
  2. 组策略或系统管控禁用微软商店
  3. 目标主机无外网访问能力

即便存在上述限制,依然可以离线部署微软商店类应用(含Python),完整步骤如下:

步骤1:浏览器打开Python商店详情页

步骤2:提取离线安装包

复制商店页面URL,粘贴至第三方站点 https://store.rg-adguard.net/,下载MSIX/APPX/APPXBundle格式离线安装包。
补充说明:该第三方站点可信度存疑,但下载的安装包带有官方数字签名,文件不会被篡改。建议先在实验环境测试安装包,确认无异常后再部署至目标主机。

步骤3:将安装包传输至目标主机

  • 有图形界面:双击MSIX文件,系统自动调用AppInstaller.exe启动安装向导

  • 无图形界面:使用PowerShell Add-AppxPackage 命令或dism.exe完成安装/卸载
    注意:dism.exe执行需要管理员权限,而单纯安装商店应用本身不需要提权。

我编写过一段Python脚本,无需完成安装即可预判商店应用主程序的存放路径,可用于提前定位Python可执行文件。
Python3.13默认完整路径示例:
C:\Users\kevinclark\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\python3.13.exe

通用路径模板:
C:\Users\[用户名]\AppData\Local\Microsoft\WindowsApps\[厂商名].[应用名]_[发布者哈希值]\[主程序].exe
其中发布者哈希值由开发者证书生成,主程序名称定义于安装包内AppxManifest.xml清单文件。少数程序会偏离该路径规则,但绝大多数商店应用均可套用此模板预判位置。

五、Pip包管理器

微软商店版Python自带Pip包管理工具,直接执行Python.exe -m pip即可调用。若主机可连通PyPI官方仓库,能正常在线下载安装第三方库。

但多数企业内网会拦截PyPI站点,或部署网络代理导致在线下载失败,极大限制Python攻击工具使用。应对方案分为两类:

  1. 仅使用Python标准库开发攻击工具,不依赖第三方组件
  2. 离线下载全部依赖库文件,上传至目标主机本地安装

离线部署流程可行,我编写了两套配套脚本:一套仅依赖标准库的离线依赖下载器、一套离线本地安装程序。

  1. 下载脚本:拉取目标工具所有依赖的Wheel离线包,自动打包为单一压缩文件,可上传内网主机或托管至私有Web服务
  2. 安装脚本:读取离线压缩包,批量完成所有Wheel包本地安装

六、Python标准库

即便可以离线导入第三方库,开发攻击性代码时仍应优先复用标准库,降低载荷体积与落地复杂度。例如网络请求场景,优先使用内置urllib,而非第三方requests库。

下表整理攻击开发高频需求,以及对应的内置标准库模块:

实现功能 标准库模块
网页网络请求 urllib
TCP套接字通信 socket
SHA256哈希计算 hashlib
文件压缩/解压缩 gzip、bz2、zlib、zipfile
加载DLL、调用原生非托管函数 ctypes
创建子进程、执行系统命令 subprocess
结构化数据解析 json、xml
Windows注册表读写修改 winreg
二进制编解码 base64
IP地址处理 ipaddress

但标准库无法覆盖全部攻击需求,部分核心能力必须借助第三方库或自主实现:

实现功能 所需第三方库
AES加密解密 pycryptodome
WebSocket长连接 aiohttp
加载.NET公共语言运行时、交互托管代码 pythonnet
网卡抓包流量分析 libpcap
LDAP目录服务交互 ldap3
Windows协议漏洞利用 impacket

Windows版Python预装标准库完整清单可查阅文末附链。

七、基于ctypes执行非托管代码

ctypes是我最常用的Python内置模块,搭配struct库后,能够用Python实现类C语言开发逻辑:加载非托管动态链接库、获取导出函数、手动内存管理、指针操作。如果熟悉C#的PInvoke机制,ctypes可以理解为Python版PInvoke。

通过ctypes调用Win32 Windows API固定分为6步:

  1. 加载包含目标函数的DLL文件
  2. 获取目标导出函数句柄
  3. 定义函数原型:参数类型、返回值类型
  4. 将Python数据类型转换适配C语言类型(数据封送)
  5. 调用原生API函数
  6. (可选)将原生返回值转回Python类型供后续代码使用

DLL加载语法

# 加载系统内置kernel32.dll
kernel32 = ctypes.windll.kernel32
kernel32_2 = ctypes.WinDLL("kernel32")

# 加载自定义路径第三方DLL
custom_dll = ctypes.CDLL(r"C:\test\custom.dll")

获取导出函数句柄

推荐通过函数名获取;按导出序号读取不推荐,不同Windows版本序号会发生变动:

# 通过函数名获取CreateFileW
CreateFileW = kernel32.CreateFileW

# 通过导出序号212读取(不推荐)
CreateFileW_ord = kernel32[212]

定义函数原型

导入wintypes模块,内置全套Windows标准数据类型;通过argtypes声明参数列表,restype定义返回值类型。以文件创建API CreateFileW为例:

from ctypes import wintypes

# 匹配MSDN官方文档参数结构
CreateFileW.argtypes = [
 wintypes.LPCWSTR,        # 文件路径
 wintypes.DWORD,          # 访问权限
 wintypes.DWORD,          # 共享模式
 wintypes.LPVOID,         # 安全属性(可选)
 wintypes.DWORD,          # 文件创建方式
 wintypes.DWORD,          # 文件属性标识
 wintypes.HANDLE          # 模板文件句柄(可选)
]
CreateFileW.restype = wintypes.HANDLE

封装参数并调用API

ctypes会自动完成Python字符串、空值到C语言对应类型的转换:

# 常量定义
filename = "test.txt"
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
CREATE_ALWAYS = 2
FILE_ATTRIBUTE_NORMAL = 0x80

# 调用API创建文件
handle = CreateFileW(
 filename,
 GENERIC_READ | GENERIC_WRITE,
 0,
 None,
 CREATE_ALWAYS,
 FILE_ATTRIBUTE_NORMAL,
 None
)

执行完成后,当前目录会生成test.txt文件,整套流程仅依靠Python内置ctypes模块完成原生系统调用。

八、ctypes实操示例

示例1:弹窗展示当前进程名与PID

完整可运行代码:

import ctypes
from ctypes import c_char_p, c_uint32, c_void_p, create_string_buffer
import os.path

# Windows弹窗常量
MAX_PATH = 260
MB_OK = 0x00000000
MB_ICONINFORMATION = 0x00000040

# 加载系统DLL
kernel32 = ctypes.windll.kernel32
user32 = ctypes.windll.user32

# 定义API原型
GetCurrentProcessId = kernel32.GetCurrentProcessId
GetCurrentProcessId.restype = c_uint32
GetCurrentProcessId.argtypes = []

GetModuleFileNameA = kernel32.GetModuleFileNameA
GetModuleFileNameA.restype = c_uint32
GetModuleFileNameA.argtypes = [c_void_p, ctypes.c_char_p, c_uint32]

MessageBoxA = user32.MessageBoxA
MessageBoxA.restype = ctypes.c_int32
MessageBoxA.argtypes = [c_void_p, c_char_p, c_char_p, c_uint32]

# 获取进程PID
process_id = GetCurrentProcessId()

# 获取程序完整路径
buffer = create_string_buffer(MAX_PATH)
path_length = GetModuleFileNameA(None, buffer, MAX_PATH)
if path_length == 0:
 raise Exception("读取模块路径失败")

# 截取程序文件名
full_path = buffer.value.decode('ascii')
process_name = os.path.basename(full_path)

# 弹窗内容
message = f"进程名称:{process_name}\n进程PID:{process_id}"

# 弹出系统提示框
MessageBoxA(
 None,
 message.encode('ascii'),
 b"进程信息",
 MB_OK | MB_ICONINFORMATION
)

示例2:反射DLL加载器

我还编写了一套简易反射DLL加载器代码,属于红队攻击核心技术落地演示。该样例无法直接用于实战渗透,但清晰展示了攻击者常用载荷注入逻辑:

  1. 内存反射加载DLL文件
  2. 主动调用DllMain入口函数
  3. 查找并执行DLL内自定义导出Run函数

九、Python相关入侵指标(IoC)

Python是企业内网广泛使用的合法程序,python.exe带有微软与Python软件基金会双重有效数字签名,可信度高;大量工作站、服务器预装Python,攻击者无需额外安装即可直接利用。

和所有解释型语言一致,Python运行时会产生特殊内存特征:Windows官方CPython在执行任意代码前,就会创建无文件映射的可执行内存段、RWX(读写执行)权限内存页。

但Python本身是通用编程语言,业务场景覆盖数据分析、系统运维、游戏开发、云编排等,行为边界极广:

  • python.exe联网访问外部网站是否正常?
  • 与内网其他主机建立Socket连接是否合理?
  • 申请、修改高权限内存页是否属于常规操作?
  • 占用大量CPU/内存资源是否存在风险?

以上问题均没有固定答案,只能结合业务场景判断。多重模糊特征叠加,极大提升终端安全产品基线建模难度,方便攻击者以Python进程为掩护,实现行为隐匿驻留。

十、总结

Python作为恶意载荷载体的潜力长期被低估:安装部署门槛低、内置工具库完善、进程行为天然具备隐蔽优势。
它不会完全替代原生C/C++攻击方案,但在PowerShell、传统原生注入等手段失效受限的场景下,是一套便捷、可行的替代攻击方案。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐