rivalsec/sinkshot

GitHub: rivalsec/sinkshot

一个基于Playwright的全自动化DOM XSS扫描器,专门用于检测和确认客户端跨站脚本漏洞。

Stars: 0 | Forks: 0

# for "Docker", keep it as "Docker". But that's not a translation to Chinese. 基于 Playwright 构建的 DOM XSS 扫描器。对于每个输入 URL,每个查询值都会被替换为一个标记 (``),一个预加载脚本会钩取 DOM 读取和危险的 sink(汇点),任何其值仍包含该标记的 sink 都会被标记为来自该参数的流。已确认的流随后会用上下文感知的有效负载重新驱动,并通过页面内触发的 `alertfunc` 回调验证执行。 ## 工作原理 **阶段一 — 发现。** [js/preload.js](js/preload.js) 通过 Playwright 的 `addInitScript` 添加,因此它在任何页面脚本之前运行: - 重写 URL,使每个现有查询值变为 ``,然后使用 `pushState` 将相同的 canary 推送到从 [config.yaml](config.yaml) 中策划的 `topparams` 列表中(因此页面即使在 URL 中没有的情况下也能看到常见的名称,如 `redirect`/`url`/`q`)。片段设置为 `#_hash`。 - 钩取 `URLSearchParams.get/getAll/has`,即使页面请求的但 URL 中未包含的键也会返回一个 canary 值,并将每个读取到的键记录到 `uspRevealed`。 - 钩取 JS sink(`eval`、`Function`、字符串 `setTimeout`/`setInterval`、`script.text`/`textContent`)、HTML sink(`innerHTML`、`outerHTML`、`insertAdjacentHTML`、`document.write[ln]`)、DOM URL sink(`a.href`、`form.action`、`*.src`)以及通用的 `setAttribute`(记录为 `setAttribute__`)。任何包含 canary 的沉没字符串都会与匹配的源键和一段违规代码片段一起记录。 - 在 Chromium 中无法可靠地修补 `Location.{assign,replace,href}`(自身的不可配置属性),因此基于导航的 sink 改为在网络层捕获:一个 Playwright 路由处理器监视主框架请求,并将任何加载后导航且其 URL 包含 canary 的记录为 `location_nav`,然后使用 HTTP 204 响应它,以保持页面(和 `rsjsstorage`)活动。 - Python 端 ([mthook.py](mthook.py)) 还会捕获主文档的原始 HTML 响应,并用 `lxml` 扫描其中反映的 canary,根据上下文(html / script / style / attr)标记命中。 **阶段二 — 确认。** 对于每个新发现的 sink,[`get_payloads`](mthook.py#L242) 会构建一个上下文适当的 payload —— 针对 JS sink 基于引号计数的字符串字面量突破,针对 URL/href 类型的 sink 使用 `javascript:rsjsstorage.alertfunc(...)`,针对 HTML sink 使用关闭 `style`/`title`/`textarea`/`script` 标签并使用 `` 的标签突破 payload。页面使用 [js/preload_inject.js](js/preload_inject.js) 重新加载,该脚本使 `URLSearchParams.get(key)` 返回该键的 payload,并将 hash payload 推送到 `location.hash` 中。当 payload 的 `rsjsstorage.alertfunc(key)` 实际运行且 `key` 最终进入 `window.rsjsstorage.jsEvals` 时,流即被确认。对于 canary 控制完整 URL 或其 netloc 的 URL sink(由于没有实际点击而无法自动触发),确认由 `static_confirm_url_sinks` 静态决定,无需触发阶段二。 每个域名的去重(`-D`,可选)对 `sink|sources|code` 和 `keys|context|tag|attr` 进行哈希,这样同一主机不同 URL 上的相同发现就不会被重复打印。每个域名的错误计数器(`DOMAIN_MAX_ERRORS = 10`)会静默跳过持续失败的主机。一个看门狗每 5 秒检查一次,并终止任何浏览器在同一个 URL 上忙碌超过 `WORKER_TIMEOUT`(60 秒)的工作线程,并生成一个替代线程;工作线程还会每处理 `BROWSER_REFRESH_INTERVAL`(20)个 URL 就回收其浏览器,以限制内存增长。 ## 安装 ``` python3 -m venv venv source venv/bin/activate pip install -r requirements.txt playwright install chromium ``` ## 用法 从文件读取: ``` python mthook.py -u urls.txt -t 10 ``` 从 stdin 读取: ``` cat urls.txt | python mthook.py -t 10 ``` 标志: - `-u, --urls FILE` — 以换行符分隔的 URL(省略则从 stdin 读取)。 - `-t, --threads N` — 并行浏览器工作线程数(默认 `10`)。 - `-w, --wait SECONDS` — 阶段一加载后额外的 `networkidle` 等待时间(默认 `0`)。 - `-o, --output FILE` — 将确认的发现追加到文件(打开时截断)。 - `-d, --debug` — 将未确认的 sink 和反映的命中打印到 stderr。 - `-D, --dedup` — 启用每个域名的 sink/反映去重。 ## I think I'm overcomplicating. In the context, these might be terms that need to be translated based on common practice. 构建镜像: ``` docker build -t sinkshot . ``` 针对主机上的 URL 文件运行(将其挂载进去并引用容器路径): ``` docker run --rm -v "$PWD/urls.txt:/urls.txt:ro" sinkshot -u /urls.txt -t 10 ``` 从 stdin 读取: ``` cat urls.txt | docker run --rm -i sinkshot -t 10 ``` ## 配置 [config.yaml](config.yaml): - `canary` — 注入到参数中的标记字符串(例如 `rivalsss`)。选择一个不太可能与网站内容冲突的字符串。 - `preload_script` — 阶段一钩子脚本的路径(默认 `js/preload.js`)。 - `ua` — 所有页面使用的 User Agent。 - `topparams` — 通过 `pushState` 自动注入的额外参数名,这样即使 URL 中没有包含,读取例如 `?redirect=...` 的网站也能被探测到。 ## 输出 对于每个有发现的 URL,会打印一个字典,包含: - `originurl` — 钩子初始化时捕获的 URL。 - `dom_url` — 原始 URL 加上任何 `uspRevealed` 键(以 `key=key` 形式追加),便于在包含所有已读取键的情况下重新运行。 - `uspRevealed` — 页面实际读取的参数键。 - `sinks` — 新的 sink 条目 `{sink, sources, code}`。 - `confirmed` — 来自阶段二的 payload,其 `alertfunc` 实际触发了。 - `reflected` — 在原始 HTML 中发现的服务端反映。 `stderr` 输出每个域名的错误计数和看门狗终止的信息。 ## 布局 - [mthook.py](mthook.py) — 协调器:队列、工作线程、看门狗、阶段一/二逻辑、去重。 - [js/preload.js](js/preload.js) — 阶段一钩子(`{{canary}}` 和 `{{topparams}}` 是模板化注入的)。 - [js/preload_inject.js](js/preload_inject.js) — 阶段二钩子,带 `payload_map` 替换。 - [config.yaml](config.yaml) — canary、UA、顶部参数、预加载路径。 ## 测试实验室 一个包含 DOM XSS 测试用例的配套 Flask 应用位于 https://github.com/rivalsec/domxsslab — 有助于对扫描器进行端到端测试。 ## 参考 - Playwright (Python): https://playwright.dev/python/docs/library
标签:特征检测, 请求拦截, 逆向工具