变量探索(SEQVEC)
上一篇写的是"我埋了什么、他们怎么上钩"。这一篇换个角度:日志里那一堆 IP,到底谁是谁。
先更新数据 ------ 蜜罐跑到第 13 天:
原始记录 583 条
剔除自己 475 条
独立真实 IP 157 个
涉及站点 13 个
比上一篇的 502 次又往上走了一截。而且有意思的是:它没有衰减。
下面是这些天整理日志时总结出的一套识别方法。不需要任何安全产品,一台服务器加一个日志文件就够。
数据说明 :下面所有数字都是剔除自己之后的 475 条。 属于我自己的 108 条单独统计,见第一步。
第 0 步:先确认你看到的 IP 是不是真的
这一步是我这次差点栽进去的地方,所以放在最前面。
我一开始按日志里的 IP 做统计,出现了一个说不通的现象:
43.175.168.191 34 次 打过 8 个不同子域名 出现过 9 种不同 UA
43.175.168.101 29 次 打过 5 个不同子域名 出现过 14 种不同 UA
一个攻击者只有一种工具。 一个 IP 上同时出现 curl、企业扫描器、泄露情报采集、 还有伪装成 Chrome 的脚本 ------ 那是好几家公司在扫。而且它还在打你不同的域名。
这只可能是一种东西:共享中间节点。
顺着查下去,43.174 / 43.175 这两个段里的 24 个 IP,占了 500 条样本里的 204 条 ------ 40.8%。它们属于同一个 AS、同一批机房。
再往下就想明白了:这个站前面挂了 CDN。 源站 nginx 的 $remote_addr 记的是 CDN 的回源节点 IP,不是访客 IP。
而真实客户端 IP 一直在同一个日志文件里 ------ 在 X-Forwarded-For 里:
json
{"ip":"43.175.168.101", "xff":"160.176.79.216", ...}
↑ CDN 回源节点 ↑ 真实访客,一直都在
我早先的日志格式里其实记了 xff 字段,只是分析脚本读的是 ip。 数据没丢,是我读错了字段。
修法是源站这边两行:
nginx
set_real_ip_from <CDN 回源段>;
real_ip_header X-Forwarded-For;
配好之后 $remote_addr 直接变成真实 IP,日志、脚本、报表全部自动就对了, 下游一行都不用改。
留一条判断手法
以后再遇到"日志里全是同一个机房"的情况,用这一条就够了:
看一个 IP 打了几种 UA、几个 host。
真实来源 1 种 UA,1--2 个站 中间节点 多种 UA,多个站
这也顺带说明一件事:在 IP 上做任何结论之前,先确认这个 IP 是不是真的。 这一篇的数字,全部是按真实客户端 IP 重算的。
第一步:先把自己清出去
583 条里,有 108 条是我自己:
lua
127.0.0.1 45 次 ← 本机验证(curl、hx-direct、hx-verify-local)
49.233.178.207 34 次 ← 服务器通过公网访问自己的站点(监控)
123.156.181.145 29 次 ← 我自己的出口 IP(浏览和手动测试)
127.0.0.1 以 45 次排在全表第一 ------ 如果不清掉,它就是"最活跃的攻击者"。
不清掉会污染好几个统计:
- 独立 IP 数虚高
- "最活跃 IP"榜单被自己占位置
- 按 UA 分类时会多出一组根本不存在的"攻击者"
而且这次因为 CDN 的事,清自己这件事要做两遍:
第一遍 按原始 IP 清(127.0.0.1、服务器自己的公网地址)
第二遍 换成真实 IP 之后,把你自己的出口 IP 再加进去
第二遍漏了的话,我的出口 IP 会稳稳排在真实 IP 榜的第一名。
所以第一件事永远是:用你自己的 UA 特征、你自己的出口 IP、你自己的验证时间点, 把自家的记录摘出去。 这步不花时间,但不做的话后面全是脏数据。
第二步:看 User-Agent,有三种一眼就是假的
UA 是最容易伪装的字段,但伪装本身会留下痕迹。这些天我见到三类破绽。
第一类:裸奔的 UA(119 次)
ini
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
看着像 Chrome 对吧?它不是。
真实的 Chrome UA 结尾一定有 Chrome/版本号 Safari/537.36 这一段。 上面这串只有 WebKit 声明,没有浏览器版本 ------ 这是脚本作者随手从网上抄了一半 UA 的结果。
这一类的路径极其一致:只有 /.env 和 /config.json 两个,来回扫。
第二类:全零的补丁号(146 次)
Chrome/147.0.0.0
Chrome/148.0.0.0
版本号可以随便写,但真浏览器的版本号长什么样是有规律的:
markdown
Chrome/131.0.6778.86 Safari/537.36
└┬─┘ └──┬───┘ └┬┘
主版本 构建号 补丁号
构建号和补丁号是一串具体数字。而上面那两串是 147.0.0.0、148.0.0.0 ------ 后三段全是零。
真实浏览器的补丁号不会长期是 0。全零意味着这是个占位符: 写脚本的人图省事,只改了主版本号就发出去了。
这一类有 146 次,是所有"假身份"里最多的一种 ------ 占了有效记录的三成。
第三类:自报家门的(这一类反而不必防)
sql
Hello from Palo Alto Networks, find out more about our scans in https://docs-cortex.paloaltonetworks.com/...
Mozilla/5.0 (l9scan/2.0....; +https://leakix.net)
Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; Shap-User/0.1.0
Mozilla/5.0 (compatible; CertLabBot/1.0; certificate research; single GET of the home page)
四家专业扫描服务,UA 里写着公司名和用途说明,有的还附文档地址:
泄露情报采集(LeakIX) 49 次 来自 23 个不同 IP
攻击面扫描(Palo Alto) 11 次 来自 11 个不同 IP
空间测绘(Shap) 6 次 来自 4 个不同 IP
证书研究(CertLabBot) 6 次 来自 1 个 IP
它们不伪装,因为没必要。 商业攻击面扫描、泄露情报采集、网络空间测绘, 这些业务本身就是公开的 ------ 被发现是工作的一部分,藏起来反而违规。
所以判断规则可以简化成一句:
承认自己在扫描的,通常是行业惯例;假装自己是浏览器的,才值得留意。
第三步:看路径,请求什么就暴露了什么意图
有效记录里,访问量排前几位的路径:
bash
281 次 /.env
154 次 /config.json
19 次 /.well-known/security.txt
7 次 /backup/
7 次 /backup/.env
3 次 /_notice
/.env 和 /config.json 两个加起来,占了全部访问的 92%。
这个规律和上一篇一致 ------ 因为它们跨框架通用,一个脚本能扫遍全网,投入产出比最高。
但路径的价值不在排名,在于区分人:
| 行为模式 | 特征 | 典型例子 |
|---|---|---|
| 广撒网 | 只碰 /.env 和 /config.json,高频、机械、路径不变 |
那两类假 UA 背后的 IP |
| 按规程 | 只请求 /.well-known/security.txt,其他一概不碰 |
商业攻击面扫描,11 次全部只碰这一个文件 |
| 有目的 | 直奔 /backup/ 下的具体文件名 |
4 次访问直奔那个假数据库导出 |
第三种最值得注意。浏览可能是爬虫顺手,直奔具体文件名说明他已经知道他在找什么。
还有个细节:这次记录里出现了几次路径变形的尝试:
bash
/.//.env
//.env
/%2eenv
/api/uploads/%2e%2e%2f%2e%2e%2f.env ← 路径穿越
这些都是在试着绕开服务器的路径匹配规则。会做这一步的,说明前面已经扫到了响应, 正在琢磨怎么拿到更多。
顺便说一句:/.well-known/security.txt 本来是"安全研究者联系我"的标准声明文件, 商业扫描器会先读它 ------ 这不是攻击行为,是行业里打招呼的方式。 如果你打算做安全这件事,这个文件建议放上,它是免费的。
第四步:看网段 ------ IP 不是身份,行为才是
这是整篇文章我最想讲的一点。
按 IP 单独统计,"最活跃"前几名看着像十几个不同的人。但把网段 + 行为放一起看, 有一个人立刻显形:
markdown
45.138.12.16 2 次
45.138.12.22 6 次
45.138.12.23 6 次
45.138.12.24 2 次
45.138.12.25 3 次
45.138.12.28 8 次
45.138.12.30 6 次
45.138.12.52 1 次
45.138.12.53 15 次
45.138.12.54 6 次
──────
10 个 IP,合计 55 次
一个 /24 段里 10 个 IP,UA 是同一串裸奔 UA,只碰同样的路径,轮流出现。
查了一下归属:AS218785 TC DATACENTER LIMITED,波兰。
看起来是十个攻击者,实际上是一个人 ------ 他手上有一小段 IP,轮着用。 而且几乎可以确定租的是同一家的机器。
把范围放大,"同一个人"的证据更清楚:那串裸奔 UA 一共出现 119 次, 来自 24 个不同的真实 IP。
反过来也成立 ------ 同一个 IP 也可能属于不同的人(云主机上的多租户、代理池、跳板)。 所以:
按 IP 统计只能得到"有多少个地址", 按行为聚类才能得到"有多少个人"。
具体怎么聚类?我用的是最土的办法:UA + 路径集合 + 时间节奏,三个都对上就归为一簇。 不需要算法,一张表格就能看出来。
顺带算出一个更有意思的:这批人都是在哪儿干活的
把点击量靠前的真实 IP 抽出来查归属:
34.140.132.132 Google LLC(AS396982)
35.205.254.119 Google LLC(AS396982)
94.154.43.125 Storm Industries LLC(荷兰)
46.151.182.7 Blatant Technologies, LLC(德国)
31.59.160.3 Miteflux Technologies Ltd(瑞典)
45.138.12.53 TC DATACENTER LIMITED(波兰)
没有一个来自家宽,全是租来的云主机。
其中最大的一股是 Google Cloud:
erlang
34.x 段 84 次 / 22 个 IP
35.x 段 32 次 / 11 个 IP
────────────────────────────
合计 116 次 / 33 个 IP 占了有效记录的 24%,独立 IP 的两成
而且它们在行为上非常整齐:
一个 IP 只用一个 UA,却横扫 4--7 个不同子域名
比如 34.140.132.132 ------ 打了 7 个站,总共只花了 11 次请求。
这不是撞大运的乱扫,是子域名枚举:先拿一个域名,把所有子域列出来挨个打。 效率极高,成本极低。
这件事的防守含义很直接:你的子域名就是你的暴露面。 主站做得再好,如果 admin.、test.、demo. 这些还在,扫描器会挨个试。
第五步:看时间,这次看不出作息
把 13 天的访问按小时铺开:
bash
00 时 36 次 ####################################
01 时 36 次 ####################################
22 时 33 次 #################################
12 时 33 次 #################################
17 时 29 次 #############################
10 时 27 次 ###########################
02 时 26 次 ##########################
...
08 时 7 次 #######
16 时 6 次 ######
深夜(22--01 时)确实略高,四个小时合计 119 次,占了 25%。 但白天也有明显高峰:12 时 33 次、17 时 29 次。
整体相当平。
这个结论和"深夜异常"的直觉不一样,但我更愿意如实写下来: 这个分布就是自动化在跑的样子,看不出有人在挑时间。
这是这一篇里我唯一没得出确定结论的一步。写下来是因为它本身有价值: 如果你看到的是"某个时段突然扎堆",那才说明背后有人在盯着; 像这样铺开的,基本就是机器。
第六步:那这些画像,防守时怎么用
先说清楚一件事:不要反制。
主动反打回去在技术上不可靠(对方多半是跳板),在法律上有明确风险 ------ 那是网络攻击行为,不是防守。
画像真正的用途是这三个:
一、判断自己有没有被"盯上"。
随手扫和盯着打,在日志里长得不一样。随手扫是散的、路径固定的、单次请求; 盯着打会反复来、会试变形路径、会去翻备份目录。我这份数据里,四家专业扫描服务属于前者, 那几个同段 IP 轮着来的、以及直奔备份文件的,属于后者。
二、验证防护有没有生效。
那些诱饵的路径,在真实系统里本来就该返回 404。 如果你哪天在真实日志里看到它们拿到 200,说明有东西不该在那儿。
三、做溯源准备的底子。
如果你在响应里带了唯一标识(上一篇讲过这个做法),那么将来某份内部资料外流时, 你能反查到是哪一次访问带走的。前提是 ------ 你得先认得出"谁来过"。
最后
这一篇比上一篇多了一个教训,我觉得比方法本身更重要:
你以为在做画像,其实可能是在给 CDN 的节点池画像。
我一开始统计出的"最活跃攻击者"是 127.0.0.1(我自己), "第二大来源"是 CDN 的回源节点,"一个人握着一小段 IP"看起来成立, 但举的是一堆机器。
全部退回重算之后,真实的那张画像反而更清楚 ------ 一个波兰机房里的 10 个 IP 是同一个人,四分之一流量从 Google Cloud 来,扫的是子域名。
所以顺序应该是:
先确认 IP 是真的 → 再清掉自己 → 最后才谈行为
区别不在工具,在"你决定记什么",也在"你确认过读到的是什么"。
变量探索(SEQVEC)