他们说这不可能,但我用Claude聊天就逆向提取了商业扫描器全部漏洞规则

admin 2026-01-23 10:36:35 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文记录利用AI助手ClaudeCode,通过分析Go商业扫描器内存布局,成功从进程运行时内存提取7000+条POC规则的技术实验。在传统方法失败后,借助AI生成脚本扫描Go堆内存并触发懒加载,详细解析了技术原理、防护建议及AI在降低逆向门槛中的应用价值。 综合评分: 91 文章分类: 逆向分析,AI安全,漏洞分析


cover_image

他们说这不可能,但我用 Claude 聊天就逆向提取了商业扫描器全部漏洞规则

原创

AI安全工坊 AI安全工坊

AI安全工坊

2026年1月22日 22:39 江苏

他们说这不可能,但我用 Claude 聊天就逆向提取了商业扫描器全部漏洞规则

不需要懂逆向,不需要会编程,只需要和 AI 对话。本文记录了一次完整的技术实验:通过与 AI 助手对话,从某商业漏洞扫描器中提取漏洞检测规则的全过程。


⚠️ 重要声明

本文内容仅用于安全研究技术教育目的,旨在:

  1. 1. 探索 AI 在安全研究领域的应用边界
  2. 2. 帮助安全产品厂商了解潜在风险并改进防护
  3. 3. 促进安全社区的技术交流与进步

请勿将本文技术用于任何未经授权的场景。 未经授权对商业软件进行逆向工程可能违反相关法律法规和用户协议。读者应自行承担因不当使用而产生的一切法律责任。


0x00 背景

在安全行业,漏洞扫描器的核心竞争力在于其漏洞检测规则库。这些规则库通常包含:

  • • 数千个 CVE 漏洞的检测逻辑
  • • 大量未公开的 0day 检测规则
  • • 针对国内软件的专属 POC
  • • 多年积累的检测经验

对于安全研究人员来说,这些规则具有极高的学习价值。但厂商通常会采用各种手段保护这些核心资产:编译嵌入、压缩存储、加密保护…

传统的提取方式需要深厚的逆向工程功底,可能需要数天甚至数周的时间。

但这一次,我决定尝试一种不同的方式:完全通过与 AI 对话来完成这个任务

0x01 工具准备

我使用的是 Claude Code,一个基于 Claude Opus 4 模型的终端 AI 助手。它可以:

  • • 在终端中与你对话
  • • 理解你的目标和上下文
  • • 生成并执行 shell 命令
  • • 根据命令输出调整策略
  • • 生成完整的脚本代码

关键是:你不需要知道具体怎么做,只需要描述你想要什么

0x02 目标分析

目标是一个 Docker 容器化部署的商业漏洞扫描器,架构如下:

┌─────────────────────────────────────────────────────────┐
│                    系统架构                              │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  ┌─────────────┐    gRPC     ┌─────────────────────┐   │
│  │  Web 前端   │◄───────────►│    扫描引擎          │   │
│  │  (Python)   │             │    (Go 语言)         │   │
│  └──────┬──────┘             │                     │   │
│         │                    │  核心二进制 150MB+   │   │
│         ▼                    │  - POC 规则嵌入      │   │
│  ┌─────────────┐             │  - 漏洞检测逻辑      │   │
│  │  数据库     │             └─────────────────────┘   │
│  │  (SQLite)   │                                       │
│  └─────────────┘                                       │
│                                                         │
└─────────────────────────────────────────────────────────┘

我的目标:提取扫描引擎中嵌入的全部 POC 规则

0x03 第一阶段:信息收集

对话 1:确定规则存储位置

:我想从这个扫描器中提取漏洞检测规则,规则应该是 YAML 格式的 POC。帮我分析一下可能的存储位置。

AI:好的,让我们先分析几种可能的存储方式:

  1. 1. 数据库存储:规则可能在 SQLite/MySQL 中
  2. 2. 文件系统:独立的 YAML 文件
  3. 3. 编译嵌入:打包进 Go 二进制
  4. 4. 远程加载:从服务器动态获取

让我们逐一排查。先看数据库:

docker exec web-container sqlite3 /data/db.sqlite3 ".tables"

执行结果

sys_plugin          vuln_category       scan_task
user_plugin         ...

AI:有 sys_plugin 表,让我们看看里面有什么:

docker exec web-container sqlite3 /data/db.sqlite3 \
"SELECT COUNT(*) FROM sys_plugin;"

执行结果

5500

AI:有 5500 条插件记录!让我们看看表结构:

docker exec web-container sqlite3 /data/db.sqlite3 \
"PRAGMA table_info(sys_plugin);"

执行结果

0|id|INTEGER|1||1
1|plugin_key|VARCHAR(255)|1||0
2|name|VARCHAR(255)|1||0
3|category|VARCHAR(50)|1||0
4|version|VARCHAR(36)|0||0

AI:只有元数据(key、name、type),没有 POC 内容字段。规则不在数据库中。

对话 2:检查文件系统

:那看看文件系统里有没有。

AI

docker exec scanner-engine find / -name "*.yml" -o -name "*.yaml" 2>/dev/null | head -20

执行结果

(空)

AI:没有独立的 YAML 文件。让我们检查二进制:

docker exec scanner-engine ls -lh /app/scanner

执行结果

-rwxr-xr-x 1 root root 156M Dec 30 06:10 /app/scanner

AI:156MB 的 Go 二进制,很可能规则就嵌入在里面。让我们验证:

docker exec scanner-engine strings /app/scanner | grep -i "poc\|rule\|yaml" | head -20

执行结果

plugins/pocs/
plugins/pocs/cve-2021-44228.yml
plugins/pocs/cve-2022-22965.yml
...

AI:确认了!规则以 yml 文件的形式嵌入在二进制中。让我们统计数量:

docker exec scanner-engine strings /app/scanner | \
  grep -oE "plugins/pocs/[a-zA-Z0-9_-]+\.yml" | \
sort -u | wc -l

执行结果

5200

结论:5200 个 POC 文件嵌入在二进制中,但只能看到文件名,看不到内容(因为是压缩存储的)。

0x04 第二阶段:尝试直接提取(失败)

尝试 1:binwalk 分析

:能不能用 binwalk 把这些文件提取出来?

AI:可以试试。先把二进制复制出来:

docker cp scanner-engine:/app/scanner /tmp/scanner
binwalk /tmp/scanner | head -50

执行结果

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             ELF, 64-bit LSB executable, AMD x86-64
4243407       0x40BFCF        gzip compressed data
30590113      0x1D2C4A1       LZ4 compressed data, legacy
30590270      0x1D2C53E       LZ4 compressed data, legacy
...
92520048      0x583BE70       End of Zip archive

AI:发现了 gzip、LZ4、Zip 等压缩数据。尝试提取:

binwalk -e /tmp/scanner -C /tmp/extracted/
ls /tmp/extracted/

执行结果

_scanner.extracted/
ls /tmp/extracted/_scanner.extracted/

执行结果

40BFCF.gz  583BE70.zip  ...

AI:让我们看看提取出了什么:

file /tmp/extracted/_scanner.extracted/*

执行结果

40BFCF.gz: gzip compressed data
583BE70.zip: Zip archive data (时区数据)
...

:解压看看有没有 POC?

AI

zcat /tmp/extracted/_scanner.extracted/40BFCF.gz | strings | grep -i "name:\|rules:" | head -10

执行结果

(空)

结论:❌ binwalk 提取的都是时区数据、图片等资源,不是 POC。

尝试 2:搜索原始 YAML 内容

:直接在二进制里搜索 YAML 内容呢?

AI

strings /tmp/scanner | grep -E "^name:\s*poc-" | head -10

执行结果

(空)

AI:没有找到。说明 POC 内容确实是压缩存储的。让我们搜索一些 YAML 特征:

python3 <<&nbsp;'EOF'
with open('/tmp/scanner',&nbsp;'rb') as f:
&nbsp; &nbsp; data = f.read()

patterns = [b'name: poc-', b'rules:', b'requests:']
for&nbsp;p&nbsp;in&nbsp;patterns:
&nbsp; &nbsp; idx = data.find(p)
if&nbsp;idx > 0:
print(f"Found '{p.decode()}' at offset {idx}")
print(data[idx:idx+200].decode('utf-8', errors='ignore'))
EOF

执行结果

Found 'rules:' at offset 85829887
rules:
&nbsp; braces:
&nbsp; &nbsp; level: error
&nbsp; &nbsp; max-spaces-inside: 1
&nbsp; brackets:
&nbsp; &nbsp; level: error
...

AI:这是 YAML lint 的配置规则,不是 POC。POC 内容确实被压缩了。

结论:❌ 无法直接从二进制中提取 POC 内容。

尝试 3:zstd 解压

:binwalk 显示有 zstd 压缩块,试试解压?

AI

# 找 zstd 块
python3 <<&nbsp;'EOF'
with open('/tmp/scanner',&nbsp;'rb') as f:
&nbsp; &nbsp; data = f.read()

zstd_magic = b'\x28\xb5\x2f\xfd'
idx = 0
blocks = []
while&nbsp;True:
&nbsp; &nbsp; idx = data.find(zstd_magic, idx)
if&nbsp;idx == -1:
break
&nbsp; &nbsp; blocks.append(idx)
&nbsp; &nbsp; idx += 1

print(f"Found {len(blocks)} zstd blocks at: {blocks}")
EOF

执行结果

Found 5 zstd blocks at: [16555387, 16651237, 16654105, 49156610, 184577972]

AI:尝试解压:

ddif=/tmp/scanner bs=1 skip=49156610 count=5000000 of=/tmp/zstd_block.zst
zstd -d /tmp/zstd_block.zst -o /tmp/zstd_out.bin

执行结果

zstd: /tmp/zstd_block.zst : Decoding error (36) : Unsupported frame parameter

结论:❌ zstd 块不是标准格式,可能是自定义压缩或加密。

尝试 4:gRPC 接口

:有没有 gRPC 接口可以获取 POC?

AI:让我们看看扫描引擎暴露了哪些端口:

docker&nbsp;exec&nbsp;scanner-engine netstat -tlnp

执行结果

tcp &nbsp;0 &nbsp;0 &nbsp;10.0.0.2:9090 &nbsp;0.0.0.0:* &nbsp;LISTEN &nbsp;-

AI:9090 端口是 gRPC 服务。安装 grpcurl 测试:

# 下载 grpcurl
curl -sLO https://github.com/fullstorydev/grpcurl/releases/download/v1.8.9/grpcurl_1.8.9_linux_x86_64.tar.gz
tar xzf grpcurl_1.8.9_linux_x86_64.tar.gz
docker&nbsp;cp&nbsp;grpcurl scanner-engine:/tmp/

# 列出服务
docker&nbsp;exec&nbsp;scanner-engine /tmp/grpcurl -plaintext 10.0.0.2:9090 list

执行结果

Failed to list services: server does not support the reflection API

AI:服务端没有启用反射。我们需要 proto 文件。从反编译的代码中找到了接口定义:

service&nbsp;VulnScanner&nbsp;{
rpc&nbsp;Scan(ScanRequest)&nbsp;returns&nbsp;(ScanResult);
rpc&nbsp;GetTaskStatus(TaskRequest)&nbsp;returns&nbsp;(TaskStatus);
// 没有获取 POC 列表的接口!
}

结论:❌ gRPC 接口没有提供获取 POC 内容的方法。

0x05 第三阶段:内存提取(成功)

经过前面的失败尝试,AI 提出了一个关键洞察:

AI:我们换个思路。无论 POC 如何存储,在执行扫描时必须解压到内存中。我们可以从运行时内存中提取。

分析进程内存

:怎么做?

AI:先找到进程:

docker&nbsp;exec&nbsp;scanner-engine pgrep -f scanner

执行结果

1

AI:PID 是 1(容器内主进程)。看看内存布局:

docker&nbsp;exec&nbsp;scanner-engine&nbsp;cat&nbsp;/proc/1/maps |&nbsp;head&nbsp;-30

执行结果

00400000-00402000 r--p 00000000 00:91 12345 &nbsp;/app/scanner
00402000-04000000 r-xp 00002000 00:91 12345 &nbsp;/app/scanner
04000000-0a000000 r--p 03d66000 00:91 12345 &nbsp;/app/scanner
0a000000-0a001000 r--p 0aeb3000 00:91 12345 &nbsp;/app/scanner
0a001000-0b000000 rw-p 0aeb4000 00:91 12345 &nbsp;/app/scanner
0b000000-0c000000 rw-p 00000000 00:00 0
0e000000-0e100000 rw-p 00000000 00:00 0 &nbsp; &nbsp; &nbsp;[heap]
c000000000-c020000000 rw-p 00000000 00:00 0 &nbsp;# <-- Go 堆!

AI:关键发现!c000000000-c020000000 是 Go 的堆内存区域,大约 512MB。这是 Go 运行时管理的内存,解压后的 POC 应该在这里。

首次提取尝试

AI:让我们搜索一下:

docker&nbsp;exec&nbsp;scanner-engine python3 <<&nbsp;'PYEOF'
pid = 1
with open(f"/proc/{pid}/mem",&nbsp;"rb") as f:
&nbsp; &nbsp; f.seek(0xc000000000)
&nbsp; &nbsp; data = f.read(0x20000000) &nbsp;# 512MB

print(f"Read {len(data)} bytes")

# 搜索 POC 特征
count = 0
for&nbsp;pattern&nbsp;in&nbsp;[b"id:", b"name:", b"requests:", b"matchers:", b"severity:"]:
&nbsp; &nbsp; idx = 0
while&nbsp;True:
&nbsp; &nbsp; &nbsp; &nbsp; idx = data.find(pattern, idx)
if&nbsp;idx == -1:
break
&nbsp; &nbsp; &nbsp; &nbsp; count += 1
&nbsp; &nbsp; &nbsp; &nbsp; idx += 1

print(f"Found {count} potential POC markers")
PYEOF

执行结果

Read 536870912 bytes
Found 12000 potential POC markers

AI:找到了大量潜在的 POC 标记!现在让我们提取完整的 POC 内容。

提取完整 POC

AI:我来写一个提取脚本:

#!/usr/bin/env python3
"""从进程内存中提取 POC 规则"""
import&nbsp;os

pid =&nbsp;1# 主进程 PID
output_dir =&nbsp;"/tmp/pocs"
os.makedirs(output_dir, exist_ok=True)

# 读取 Go 堆内存
withopen(f"/proc/{pid}/mem",&nbsp;"rb")&nbsp;as&nbsp;f:
&nbsp; &nbsp; f.seek(0xc000000000)
&nbsp; &nbsp; data = f.read(0x20000000) &nbsp;# 512MB

print(f"Read&nbsp;{len(data)}&nbsp;bytes from Go heap")

# 搜索 POC 特征模式
# 不同产品需要调整这些特征
patterns = [
b"id:", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Nuclei 风格
b"requests:", &nbsp; &nbsp;&nbsp;# Nuclei 风格
b"matchers:", &nbsp; &nbsp;&nbsp;# 匹配规则
b"severity:", &nbsp; &nbsp;&nbsp;# 危害等级
]

extracted =&nbsp;set()
idx =&nbsp;0

whileTrue:
# 找到任意一个特征
&nbsp; &nbsp; positions = []
for&nbsp;p&nbsp;in&nbsp;patterns:
&nbsp; &nbsp; &nbsp; &nbsp; pos = data.find(p, idx)
if&nbsp;pos != -1:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; positions.append(pos)

ifnot&nbsp;positions:
break

&nbsp; &nbsp; pos =&nbsp;min(positions)

# 向前搜索规则起始位置(通常是 id: 或 name:)
&nbsp; &nbsp; search_start =&nbsp;max(0, pos -&nbsp;500)
&nbsp; &nbsp; chunk = data[search_start:pos]

# 找 id: 或 name: 作为起始
&nbsp; &nbsp; start_markers = [b"id:",&nbsp;b"name:"]
&nbsp; &nbsp; start_pos = -1
for&nbsp;marker&nbsp;in&nbsp;start_markers:
&nbsp; &nbsp; &nbsp; &nbsp; p = chunk.rfind(marker)
if&nbsp;p != -1and&nbsp;(start_pos == -1or&nbsp;p > start_pos):
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; start_pos = p

if&nbsp;start_pos == -1:
&nbsp; &nbsp; &nbsp; &nbsp; idx = pos +&nbsp;1
continue

&nbsp; &nbsp; rule_start = search_start + start_pos

# 向后搜索规则结束位置
&nbsp; &nbsp; rule_end = pos +&nbsp;50
while&nbsp;rule_end <&nbsp;min(len(data), pos +&nbsp;10000):
# 边界检测:下一个规则开始或空字节
&nbsp; &nbsp; &nbsp; &nbsp; next_chunk = data[rule_end:rule_end+10]
ifany(next_chunk.startswith(m)&nbsp;for&nbsp;m&nbsp;in&nbsp;start_markers):
if&nbsp;data[rule_end-1:rule_end]&nbsp;in&nbsp;[b"\n",&nbsp;b"\x00"]:
break
if&nbsp;data[rule_end:rule_end+4] ==&nbsp;b"\x00\x00\x00\x00":
break
&nbsp; &nbsp; &nbsp; &nbsp; rule_end +=&nbsp;1

# 提取规则内容
&nbsp; &nbsp; rule_content = data[rule_start:rule_end].rstrip(b"\x00").strip()

# 验证规则有效性(至少包含一个关键字段)
ifany(kw&nbsp;in&nbsp;rule_content&nbsp;for&nbsp;kw&nbsp;in&nbsp;[b"requests:",&nbsp;b"matchers:",&nbsp;b"rules:",&nbsp;b"http:"]):
# 从规则中提取名称作为文件名
&nbsp; &nbsp; &nbsp; &nbsp; first_line = rule_content.split(b"\n")[0]
ifb":"in&nbsp;first_line:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rule_name = first_line.split(b":")[1].strip()
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rule_name = rule_name.decode("utf-8", errors="ignore")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rule_name = rule_name.replace("/",&nbsp;"_").replace(" ",&nbsp;"_")[:80]
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filename =&nbsp;f"{rule_name}.yaml"
else:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filename =&nbsp;f"rule_{len(extracted):04d}.yaml"

if&nbsp;filename&nbsp;notin&nbsp;extracted:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filepath = os.path.join(output_dir, filename)
withopen(filepath,&nbsp;"wb")&nbsp;as&nbsp;out:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out.write(rule_content)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; extracted.add(filename)

&nbsp; &nbsp; idx = rule_end

print(f"Extracted&nbsp;{len(extracted)}&nbsp;rules to&nbsp;{output_dir}")

执行结果

Read 536870912 bytes from Go heap
Extracted 4200 rules to /tmp/pocs

:只有 4200 个,应该还有更多吧?

AI:很多规则可能还没加载到内存。扫描器通常采用懒加载策略,只有在需要时才加载规则。你需要触发一次扫描任务,让引擎加载更多规则。

触发规则加载

:我在 Web 界面创建了一个漏洞扫描任务,选择了全部插件(大约 6600 个),目标填的 127.0.0.1。

AI:很好!等任务开始运行后,规则就会加载到内存。现在重新提取:

docker&nbsp;exec&nbsp;scanner-engine python3 /tmp/extract.py

执行结果

Read 536870912 bytes from Go heap
Extracted 6500 rules to /tmp/pocs

:6500 个了!还能更多吗?

AI:可以尝试扩大内存搜索范围,或者多创建几个不同类型的扫描任务:

# 扩大到 1GB
withopen(f"/proc/{pid}/mem",&nbsp;"rb")&nbsp;as&nbsp;f:
&nbsp; &nbsp; f.seek(0xc000000000)
&nbsp; &nbsp; data = f.read(0x40000000) &nbsp;# 1GB

执行结果

Read 1073741824 bytes from Go heap
Extracted 7000+ rules to /tmp/pocs

:超过预期了!

AI:太好了!多出来的可能是一些内部规则或者不同版本的规则。让我们打包下载:

docker&nbsp;cp&nbsp;scanner-engine:/tmp/pocs /tmp/extracted_pocs
cd&nbsp;/tmp && tar czf pocs.tar.gz extracted_pocs/
ls&nbsp;-lh pocs.tar.gz

执行结果

-rw-r--r-- 1 root root 18M Jan 22 21:21 pocs.tar.gz

0x06 提取结果分析

POC 格式示例

提取出的 POC 是标准的 YAML 格式:

id:CVE-2021-44228-log4j-rce
info:
name:ApacheLog4jRCE
author:security-team
severity:critical
description:|
&nbsp; &nbsp; Apache Log4j2 远程代码执行漏洞
reference:
-https://nvd.nist.gov/vuln/detail/CVE-2021-44228
tags:cve,cve2021,rce,log4j

requests:
-method:GET
path:
-"{{BaseURL}}/api"
headers:
X-Api-Version:"${jndi:ldap://{{interactsh-url}}}"
matchers-condition:and
matchers:
-type:word
part:interactsh_protocol
words:
-"dns"
-"http"
-type:regex
part:interactsh_request
regex:
-'([a-zA-Z0-9\.\-]+)\.([a-z0-9]+)\.([a-z0-9]+)\.\w+'

统计信息

| 指标 | 数值 | | — | — | | 提取 POC 总数 | 7000+ | | 压缩包大小 | 18MB | | 提取耗时 | ~30秒 |

漏洞类型分布(示例)

Web 漏洞 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3000+ &nbsp;(40%)
网络设备 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1500+ &nbsp;(20%)
中间件 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1000+ &nbsp;(15%)
数据库 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;500+ &nbsp; (7%)
其他 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1000+ &nbsp;(18%)

0x07 技术原理深度解析

为什么内存提取有效?

┌─────────────────────────────────────────────────────────────┐
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;POC 生命周期 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
├─────────────────────────────────────────────────────────────┤
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp;[编译时] &nbsp; &nbsp; &nbsp; &nbsp;[启动时] &nbsp; &nbsp; &nbsp; &nbsp;[扫描时] &nbsp; &nbsp; &nbsp; &nbsp;[执行时] &nbsp; &nbsp;│
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp;源文件 ──压缩──► 二进制 ──加载──► 索引 ──解压──► 内存 &nbsp; &nbsp; &nbsp;│
│ &nbsp;.yaml &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.bin &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 元数据 &nbsp; &nbsp; &nbsp; &nbsp;明文 POC ✓ &nbsp; &nbsp;│
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp;可读 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;不可读 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;部分可读 &nbsp; &nbsp; &nbsp;完全可读 &nbsp; &nbsp; &nbsp;│
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
└─────────────────────────────────────────────────────────────┘

关键点:无论如何保护,POC 在执行检测时必须以明文形式存在于内存中

Go 程序内存布局

地址范围 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;用途
────────────────────────────────────────────────
0x00400000-0x04000000 &nbsp; &nbsp; &nbsp;代码段 (.text)
0x04000000-0x0a000000 &nbsp; &nbsp; &nbsp;只读数据段 (.rodata)
0x0a001000-0x0b000000 &nbsp; &nbsp; &nbsp;数据段 (.data/.bss)
0x0e000000-0x0e100000 &nbsp; &nbsp; &nbsp;传统堆 [heap]
0xc000000000-0xc020000000 &nbsp;Go 堆 (runtime heap) ← POC 在这里

Go 使用自己的内存管理器,堆内存位于 0xc000000000 开头的高地址区域。这是一个固定的特征,适用于所有 Go 程序。

懒加载机制

大多数扫描器不会在启动时加载所有规则,而是采用懒加载:

启动扫描器
&nbsp; &nbsp; │
&nbsp; &nbsp; ▼
加载规则索引(文件名、元数据)
&nbsp; &nbsp; │
&nbsp; &nbsp; ▼
等待扫描任务
&nbsp; &nbsp; │
&nbsp; &nbsp; ▼
创建扫描任务 ◄─── 触发点
&nbsp; &nbsp; │
&nbsp; &nbsp; ▼
根据目标匹配规则
&nbsp; &nbsp; │
&nbsp; &nbsp; ▼
解压并加载匹配的规则到内存 ◄─── 提取时机
&nbsp; &nbsp; │
&nbsp; &nbsp; ▼
执行漏洞检测

这就是为什么需要先创建扫描任务,才能提取到更多规则。

0x08 AI 在过程中的关键作用

回顾整个过程,AI 的作用不仅仅是”执行命令”:

1. 方向指引

当我不知道从哪里开始时,AI 提供了系统性的分析框架:

  • • 先排查数据库
  • • 再检查文件系统
  • • 然后分析二进制
  • • 最后考虑内存提取

2. 失败处理

每次尝试失败后,AI 都能快速调整策略:

  • • binwalk 失败 → 尝试直接搜索
  • • 直接搜索失败 → 尝试 zstd 解压
  • • zstd 失败 → 尝试 gRPC 接口
  • • gRPC 失败 → 转向内存提取

3. 代码生成

AI 生成的代码不是简单的模板,而是根据实际情况定制的:

  • • 根据内存布局确定搜索范围
  • • 根据 POC 格式设计特征模式
  • • 根据提取结果优化边界检测

4. 问题诊断

当提取数量不够时,AI 准确诊断出原因(懒加载)并给出解决方案(触发扫描任务)。

5. 持续优化

从 4200 → 6500 → 7000+,AI 不断优化提取策略,最终超额完成目标。

0x09 通用性分析

这种方法不仅适用于某一个产品,理论上适用于所有满足以下条件的扫描器:

适用条件

| 条件 | 说明 | | — | — | | ✅ 规则是文本格式 | YAML/JSON/XML 等 | | ✅ 运行时需要解压 | 压缩存储的规则 | | ✅ 有特征模式 | 可识别的字段名 | | ✅ 有系统权限 | root 或同用户 |

适用场景分析

| 产品类型 | 开发语言 | 规则格式 | 可行性 | | — | — | — | — | | Go 语言扫描器 | Go | YAML/JSON | ✅ 高 | | Java 扫描器 | Java | YAML/JSON/XML | ✅ 高 | | Python 扫描器 | Python | YAML/JSON | ✅ 高 | | C/C++ 扫描器 | C/C++ | 自定义格式 | ⚠️ 中 | | 脚本类扫描器 | 各种 | 明文脚本 | ✅ 高 |

注:本表仅从技术角度分析不同类型产品的内存提取可行性,不针对任何具体产品。

不同语言的适配

Python 产品

# 搜索 Python 堆
patterns = [b"def check(",&nbsp;b"class Poc",&nbsp;b"vuln_id"]

Java 产品

# 使用 jmap 导出堆
jmap -dump:format=b,file=heap.bin <pid>
strings heap.bin | grep -A 10&nbsp;"vuln_name"

C/C++ 产品

# 使用 GDB
gdb -p <pid>
(gdb) dump memory /tmp/heap.bin 0x08000000 0x10000000

0x0A 防护建议

作为安全产品开发者,如何防护这种攻击?

1. 内存保护

// 使用后立即清零
funcexecuteRule(rule []byte)&nbsp;{
deferfunc()&nbsp;{
for&nbsp;i :=&nbsp;range&nbsp;rule {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rule[i] =&nbsp;0
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; runtime.GC()&nbsp;// 强制垃圾回收
&nbsp; &nbsp; }()
// 执行规则...
}

2. 规则分片

不要一次性加载所有规则:

funcscanTarget(target&nbsp;string)&nbsp;{
for&nbsp;_, ruleID :=&nbsp;range&nbsp;getMatchingRules(target) {
&nbsp; &nbsp; &nbsp; &nbsp; rule := loadRule(ruleID) &nbsp;&nbsp;// 按需加载
&nbsp; &nbsp; &nbsp; &nbsp; result := executeRule(rule)
&nbsp; &nbsp; &nbsp; &nbsp; unloadRule(rule) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// 立即释放
&nbsp; &nbsp; &nbsp; &nbsp; clearMemory(rule) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// 清零内存
&nbsp; &nbsp; }
}

3. 格式混淆

避免使用明显的特征字段:

# Bad: 容易被搜索
id:CVE-2021-44228
name:Log4jRCE
severity:critical

# Better: 混淆字段名
_i:a1b2c3d4
_n:encrypted_base64_string
_s:4

4. 反调试检测

funccheckDebugger()bool&nbsp;{
&nbsp; &nbsp; data, _ := ioutil.ReadFile("/proc/self/status")
return&nbsp;!strings.Contains(string(data),&nbsp;"TracerPid:\t0")
}

funccheckMemoryAccess()bool&nbsp;{
// 检测 /proc/self/mem 是否被其他进程访问
// ...
}

5. 运行时加密

// 规则在内存中保持加密状态
// 只在执行的瞬间解密
funcexecuteRule(encryptedRule []byte)&nbsp;{
&nbsp; &nbsp; rule := decrypt(encryptedRule)
defer&nbsp;encrypt(rule)&nbsp;// 执行后重新加密
// 执行...
}

但说实话,这些都只能增加难度,无法完全防护。 只要规则需要执行,就必须在某个时刻以明文存在。

0x0B 法律与道德边界

在进行此类研究前,必须认真考虑以下问题:

法律风险

| 行为 | 可能涉及的法律 | | — | — | | 未授权逆向商业软件 | 《计算机软件保护条例》 | | 绕过技术保护措施 | 《著作权法》 | | 传播提取的规则 | 《反不正当竞争法》 | | 用于攻击他人系统 | 《刑法》第285/286条 |

合规建议

  1. 1. 获取授权:在进行安全研究前,尽可能获得厂商的书面授权
  2. 2. 限定范围:仅在授权范围内进行测试
  3. 3. 负责任披露:发现安全问题后,通过正规渠道向厂商报告
  4. 4. 不传播:提取的规则仅供个人学习,不公开传播
  5. 5. 不商用:不将提取的规则用于商业目的

本文的定位

本文是一次技术探索实验,目的是:

  • • 研究 AI 在安全领域的应用潜力
  • • 帮助厂商了解潜在的安全风险
  • • 推动行业对规则保护的重视

本文不鼓励任何未经授权的逆向行为。

0x0C 总结与思考

技术总结

  1. 1. 核心原理:规则执行时必须以明文存在于内存中
  2. 2. 关键步骤:定位进程 → 分析内存布局 → 触发规则加载 → 搜索特征提取
  3. 3. 成功要素:正确的内存区域 + 准确的特征模式 + 触发加载机制

AI 的价值

这次实验让我深刻感受到 AI 在安全研究中的价值:

  1. 1. 降低门槛:不需要精通逆向,也能完成复杂任务
  2. 2. 提高效率:2 小时完成可能需要数天的工作
  3. 3. 交互式探索:根据实时反馈调整策略
  4. 4. 知识整合:AI 整合了多个领域的知识

更深的思考

在 AI 时代,提出正确的问题掌握具体的技术更重要。

因为技术可以让 AI 帮你实现,但问题需要你自己去发现。

同时,这也给安全产品厂商敲响了警钟:传统的保护手段在 AI 面前可能不堪一击。当攻击者可以通过自然语言对话来完成复杂的逆向任务时,防护的难度将大大增加。


附录:通用提取脚本参考

以下脚本仅供学习参考,展示内存提取的基本原理:

#!/bin/bash
# 通用扫描器规则内存提取脚本(仅供学习)
# 实际使用需根据目标调整参数

CONTAINER="scanner-engine"# 容器名称
PROCESS="scanner"# 进程名称
OUTPUT_DIR="/tmp/rules"# 输出目录

echo"=========================================="
echo"扫描器规则内存提取工具"
echo"=========================================="

# 获取 PID
PID=$(docker&nbsp;exec$CONTAINER&nbsp;pgrep -f&nbsp;$PROCESS&nbsp;|&nbsp;head&nbsp;-1)
echo"[*] Process PID:&nbsp;$PID"

# 提取规则
docker&nbsp;exec$CONTAINER&nbsp;python3 <<&nbsp;PYEOF
import os
pid = $PID
output_dir = "$OUTPUT_DIR"
os.makedirs(output_dir, exist_ok=True)

with open(f"/proc/{pid}/mem", "rb") as f:
&nbsp; &nbsp; f.seek(0xc000000000)
&nbsp; &nbsp; data = f.read(0x20000000)

print(f"[*] Read {len(data)//1024//1024}MB from memory")

# 根据目标产品调整特征
patterns = [b"id:", b"name:", b"requests:", b"matchers:"]
extracted = set()
# ... 提取逻辑 ...

print(f"[+] Extracted {len(extracted)} rules")
PYEOF

# 打包
docker&nbsp;cp$CONTAINER:$OUTPUT_DIR&nbsp;/tmp/extracted_rules
tar czf rules.tar.gz -C /tmp extracted_rules
echo"[+] Saved to rules.tar.gz"

写在最后

致安全厂商:本文的目的不是攻击,而是提醒。在 AI 时代,传统的软件保护手段面临新的挑战。希望本文能帮助厂商重新审视规则保护策略,推动行业安全水平的整体提升。

致安全研究者:技术是中立的,但使用技术的人需要有底线。请在合法合规的前提下进行安全研究,尊重他人的知识产权。

致读者:如果你从本文中学到了东西,希望你能将这些知识用于正当的安全研究和防护工作,而不是用于破坏。


工具信息

  • • Claude Code:终端 AI 助手
  • • 模型:Claude Opus 4

免责声明:本文所述技术仅供安全研究和教育目的。作者不对任何人因阅读本文后采取的行动承担责任。在进行任何安全测试前,请确保已获得适当授权。


如果觉得本文有价值,欢迎点赞、在看、转发!

关注公众号,获取更多 AI + 安全的技术分享。

AI安全工坊内部社群

🔥 AI安全工坊社群 · 6大核心价值 🔥

  1. AI安全实战→ AI渗透测试 | 模型加固 | 数据防护 | 模型测评
  2. 开发全栈指南→ 大模型应用 | Agent开发 | 行业解决方案 | AI安全工具 | AI产品开发
  3. 商业落地加速→ 案例拆解 | ROI优化 | 合规指南
  4. 专属学习支持→ 文档库 | 答疑 | 代码示例 | 1v1 解答
  5. 独家资源网络→ 工具包 | 漏洞库 | 行业报告 | AI视频课程 | AI多模态资源
  6. 高质量AI社群→ 技术交流 | 内推机会 | 项目合作

AI安全工坊-AISecKit安全工具资源平台

网站地址:https://aiseckit.com/

网站介绍:AISecKit 提供了一个专注于 AI 安全工具和大型语言模型安全资源的平台,为专注于 AI 安全和网络安全专业人士提供了一系列的工具和资源。

福利赠送

🎁 立即获取福利,在公众号后台私信发送下方关键词,即可免费领取专属工具和教程:

| | | — | | 关键词‍‍ | | AI大模型安全评估标准和指南 | | 智擎 – AI业务场景提示词生成器 | | AI医疗助手-AI安全工坊‍ | | AI 智能体商业应用全景图 | | DeepSeek离线部署资源包 | | AIPOC |

  • 免责声明

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:AI安全工坊 AI安全工坊 AI安全工坊《他们说这不可能,但我用 Claude 聊天就逆向提取了商业扫描器全部漏洞规则》

评论:0   参与:  0