1.2 红队侦察与账户枚举


1.2 红队侦察与账户枚举

本节摘要:本节跟着红队侦察小组完成开幕日的一轮情报收集:公开渠道信息汇聚、登录接口的账户枚举、口令规律推断,以及蓝队侧的统一报错、登录节流与暴露面收敛。侦察是所有后续科目的弹药库,本节给出可落地的反枚举加固与检测思路。

回合开始:红队怎么找目标

开幕日下午,红队还没碰任何攻击工具,先泡在公开信息里。招聘启事写着"负责内部运维平台 Java 开发",技术博客的截图角落露出内网域名,官网新闻稿点名了新上任的运维负责人——这些碎片拼起来,账号命名规律、技术栈、组织结构就有了轮廓。接着是接口行为探测:拿一批常见用户名去撞登录口,不为了登进去,只为了看系统"怎么回答"。

侦察阶段的产出不是漏洞,是信息差。判断侦察价值的标准很朴素:这条信息能不能让后续攻击少猜、少试、少暴露。账号清单让口令攻击有的放矢,报错差异让枚举零成本,员工邮箱列表让钓鱼邮件有真人可发。反过来说,蓝队要做的就是把信息差压到最小。

漏洞原理:登录口为什么会"泄密"

账户枚举的原理,是登录接口对不同失败原因给出了可区分的响应。经典的错误写法有表现"用户不存在"返回"该用户名未注册",密码错误返回"密码错误"。攻击者只要遍历用户名,就能从报错文本里筛出有效账号。除了报错文本,还有隐式差异:响应时间差异(用户不存在时直接返回,用户存在时要算一次哈希,慢了几十毫秒)、注册/找回密码流程的差异(填已注册邮箱提示"该邮箱已使用")、HTTP 状态码与响应长度差异。

修复思路只有一条主线:对外行为不可区分。无论用户存在与否,报错文案、状态码、响应耗时都要拉平。找回密码、注册等旁路接口同样要处理,否则登录口堵住了,枚举从找回密码口又漏出去。

利用演示:一次最小化的枚举

下面的演示在本地靶场完成,只测响应差异,不做任何真实登录尝试:

# 本地靶场:登录口响应差异探测(仅用于自检自己的系统) import time, requests TARGET = "http://lab.local/api/login" # 靶场地址 probes = { "alice": {"password": "WrongPwd!x9"}, # 假设存在的用户 "nosuch": {"password": "WrongPwd!x9"}, # 大概率不存在的用户 } for user, payload in probes.items(): body = {"username": user, **payload} t0 = time.perf_counter() r = requests.post(TARGET, json=body, timeout=5) cost = (time.perf_counter() - t0) * 1000 print(f"{user:8s} status={r.status_code} len={len(r.text):4d} " f"time={cost:6.1f}ms body={r.json().get('message')}")

输出长这样(靶场实录):

alice status=401 len=54 time= 148.3ms body=用户名或密码错误 nosuch status=401 len=54 time= 21.7ms body=用户名或密码错误

文案与长度已拉平,但时间差暴露了真相:存在用户要多算一次口令哈希,慢了一百多毫秒。批量探测再做个统计,两类响应的分布泾渭分明,枚举照样成立。这个演示说明:统一报错只做了一半,时间侧信道也要抹平——不存在用户时也执行一次等价开销的哑哈希,是常见修法。

蓝队加固:把暴露面收干净

蓝队这边的动作分四层。第一层是登录口本身:统一报错文案与状态码;对不存在用户执行哑哈希拉平耗时;登录失败统一计数进入节流。第二层是旁路接口:注册、找回密码、订阅推送,凡是能区分"账号存在与否"的行为全部拉平,找回密码无论邮箱是否存在都返回同一句"若该邮箱存在,我们将发送重置邮件"。第三层是外围信息收敛: robots 文件、目录列表、页面注释、错误页堆栈、API 文档站点的访问控制。第四层是命名规律治理:内部账号避免"姓名拼音.工号"这类可批量推导的格式,让红队即使拿到员工名单也拼不出账号。

登录口的节流用反向代理即可落地:

# 登录接口限速:单 IP 每分钟至多 10 次失败尝试,超出直接 429 limit_req_zone $binary_remote_addr zone=login_zone:10m rate=10r/m; location = /api/login { limit_req zone=login_zone burst=5 nodelay; limit_req_status 429; proxy_pass http://app_upstream; }

注意限速要按"失败次数"而非"请求次数"累计更友好,业务层可用内存计数或 Redis 计数实现"按账号 + 按 IP"双维度阈值,后面口令攻击回合会展开。

检测与应急:让侦察本身成为告警

侦察是最好的预警窗口:红队在试探,蓝队若看得见,就能抢在利用阶段之前布防。检测上关注异常模式而非单条请求——同源 IP 对登录口的高频探测、大量"用户不存在"类失败在短时间内聚集、同一账号被不同 IP 轮番试探、找回密码接口被批量遍历邮箱。一条最小化的检测规则:

-- 近一小时同一来源对登录口的失败探测聚合(阈值示例) SELECT src_ip, count(*) AS fails, count(DISTINCT username) AS uniq_users FROM auth_log WHERE result = 'fail' AND ts > now() - interval '1 hour' GROUP BY src_ip HAVING count(*) > 30 OR count(DISTINCT username) > 20 ORDER BY fails DESC;

命中后先封禁观察再人工复核,避免误伤共享出口的用户。应急动作保留现场日志、扩粒度检索同指纹行为、检查枚举命中的账号是否已被成功登录——若已有成功记录,立即按口令攻击回合的流程处置。

本回合的胜负手不在工具,在响应行为的"不可区分性"。上线前用上面的探测脚本扫一遍自己的登录与找回密码口,是最便宜的安全测试。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U