xcull/xcull

GitHub: xcull/xcull

一个安全感知的URL去重工具,用于侦察流水线中清理攻击面并保留可利用模式。

Stars: 0 | Forks: 0

xcull

用于侦察流水线的安全感知 URL 去重工具。

将嘈杂的侦察 URL 折叠为干净的攻击面,同时保留可利用的模式。

ci release contributions welcome

功能 · 安装说明 · 使用方法 · 运行 xcull · 示例 · 标志用例 · 输出 · 流水线集成 · 基准测试 · 问题报告 · 赞助 · 许可证

xcull demo

## 功能 - 单一静态 C 二进制文件,无运行时依赖。 - 流式去重,在 780,200 个 URL 上峰值 RSS 恒定为 22 MB。 - 保留每个不同的对象标识符(数字、UUID、十六进制)用于 IDOR 和 BOLA 枚举。 - 保留每个不同的会话令牌,用于会话绑定的授权测试。 - 基于查询参数形状进行去重,而非原始查询字符串。 - 保留重复的参数名(`?id=1&id=2`)作为不同的 HTTP 参数污染攻击面。 - 路径模板化折叠重复的 slug 变体,而不合并不同的端点。 - 默认过滤二进制资产、wayback 噪音和扫描器探测 URL。 ## 安装说明 ### 快速安装 (Linux x86_64 / arm64) ``` curl -fsSL https://raw.githubusercontent.com/xcull/xcull/main/install.sh | sh ``` 下载最新发行版,验证其 `sha256`,并安装到 `/usr/local/bin`。遵循 `PREFIX`(例如 `PREFIX=$HOME/.local`)和 `XCULL_VERSION=vX.Y.Z` 以锁定标签。更喜欢在运行前查看? 先执行 `curl -fsSL .../install.sh | less`;它获取的二进制文件与下方 校验和相同的发行压缩包相同。 ### Docker 拉取预构建的多架构镜像 (linux/amd64 + arm64),无需构建: ``` gau example.com | docker run -i --rm ghcr.io/xcull/xcull > urls.txt ``` `docker run` 首次使用时会拉取 `ghcr.io/xcull/xcull:latest`;使用 `:2.1.0` 锁定版本。 更喜欢自己构建: ``` docker build -t xcull . gau example.com | docker run -i --rm xcull > urls.txt ``` 无论哪种方式,它都是一个静态 musl 构建,被复制到一个 `scratch` 镜像中:里面 只有二进制文件,因此可以在任何地方运行且保持极小体积。 ### 预编译二进制文件 从 [github.com/xcull/xcull/releases](https://github.com/xcull/xcull/releases) 下载您平台对应的最新发行版, 然后: ``` tar xzf xcull-*-linux-x86_64.tar.gz sudo install -m755 xcull /usr/local/bin/xcull ``` 发行版包含 `linux-x86_64` 和 `linux-arm64`。每个压缩包旁边都有一个 `.sha256` 文件。
验证校验和 ``` curl -LO https://github.com/xcull/xcull/releases/latest/download/xcull-v1.0.1-linux-x86_64.tar.gz curl -LO https://github.com/xcull/xcull/releases/latest/download/xcull-v1.0.1-linux-x86_64.tar.gz.sha256 sha256sum -c xcull-v1.0.1-linux-x86_64.tar.gz.sha256 ```
### 从源码构建 ``` git clone https://github.com/xcull/xcull cd xcull make sudo make install ```
构建选项 (PREFIX, DESTDIR, CC, CFLAGS) `make install` 遵循 `PREFIX`(默认 `/usr/local`)和用于打包的 `DESTDIR`。man 手册页以及 bash 和 zsh 补全文件与二进制文件一起安装,因此安装后 `man xcull` 有效,且 Tab 补全会识别标志。`make test` 运行黄金输出回归测试套件;`make benchmark` 额外构建 `runstat`,即基准测试使用的 fork + wait4 + getrusage 测试工具。 ``` # 安装到自定义路径 make install PREFIX=$HOME/.local # 打包到分阶段 DESTDIR(供发行版打包者使用) make install DESTDIR=/tmp/staging PREFIX=/usr # 使用 clang 构建 make CC=clang # 构建时启用额外警告 make CFLAGS="-O3 -march=native -flto -Wall -Wextra" ```
卸载 ``` sudo make uninstall ``` 删除由 `make install` 安装的二进制文件、man 手册页和 shell 补全文件。遵循相同的 `PREFIX` 和 `DESTDIR` 变量。
## 使用方法 xcull 从 stdin 读取 URL,并将去重后的集合写入 stdout。 通常情况是无标志的单行管道。 ``` cat urls.txt | xcull ``` 运行 `xcull --help` 查看选项列表,`xcull --help all` 查看使用示例和退出代码,或 `man xcull` 获取完整参考。完整的标志列表: ``` usage: xcull [-F fold-ids][-x keep-invalid][-a keep-assets] [-s case-sensitive][-L N subset-cmp cap] [-k][-p][-W][-r][-v] xcull {-h | --help [all]} xcull {-V | --version} -F fold object-ids (numeric/UUID/hex/stem-id segments collapse to one witness). Default keeps every distinct id; -F is the aggressive endpoint-discovery mode. -x keep invalid URLs, fully raw, no cleaning. -a keep all assets (do not filter images/fonts/css/audio/video like .css/.png/.woff/.mp4/.mp3/.m4p/...). -s case-sensitive path matching. -L N cap subset-merge comparisons per inserted record (0 = off, the default). Safety valve for adversarial multi-cardinality antichains; when it trips, the record is kept un-merged so output may differ from a full run. -k keep param values and every distinct query key-set as its own line (dedup on the full query; disables the default query-subset merge and restores streaming output). -p no path templating at all (also drops the title-slug fold). -W opt out of wayback-noise handling. -r opt out of URL canonicalization. -v, --verbose print "xcull: -> (peak RSS KB)" to stderr. -h, --help print the option list (--help all adds examples and exit codes). -V, --version print version, build info, and license, then exit. ``` ## 运行 xcull xcull 始终从 stdin 逐行读取 URL,并将清理后的集合写入 stdout。没有 `-l` 或 `-u` 标志;输入形状由 shell 控制。容忍空行和前导/尾随空格。 ### 管道输入 (stdin) ``` gau example.com | xcull ``` 这是典型用法:侦察源将其输出直接管道传输给 xcull,xcull 将去重后的集合流式传输给下游。 ### 文件输入 ``` xcull < urls.txt ``` 等同于 `cat urls.txt | xcull`。使用您的流水线读取更自然的方式。 ### 多源输入 ``` cat gau.txt waybackurls.txt katana.txt | xcull > urls.txt ``` xcull 对并集进行去重,因此组合多个侦察源的成本与运行一次相同。对于默认模式,顺序无关紧要:xcull 延迟发送,因此后面的记录如果其模板化路径相同,可以追溯地取消发送先前的记录。 ### 预排序输入 xcull 从不假定输入已排序;输出顺序相对于给定标志集下的首次出现是确定性的。对相同输入的两次运行会产生字节完全相同的输出。 ## 示例 一些常见的形状;每个标志的用例将在下一节中介绍。 ``` # 从归档源清理侦察面 gau example.com | xcull > surface.txt ``` ``` # 合并多个来源并进行一次性去重 cat gau.txt waybackurls.txt katana.txt | xcull | tee urls.txt ``` ``` # 为参数模糊测试管道提供数据 gau example.com | xcull | qsreplace FUZZ | anew params.txt ``` ``` # 展示缩减情况(统计信息输出到 stderr,数据仍输出到 stdout) cat urls.txt | xcull -v > deduped.txt ``` ## 标志用例 每个标志都有特定的用途。默认模式解决了 90% 的情况;仅在适用其特定用例时才使用标志。 ### 默认(无标志) **适用场景:** 正常的侦察过程。将存档源或爬虫器输出通过 xcull 进行流式处理,并将清理后的集合管道传输给下一个消费 URL 的工具。 ``` gau example.com | xcull > urls.txt ``` 在默认模式下,每个不同的对象 ID(`/user/41`、`/user/42`)、会话令牌(`;jsessionid=...`)和 GraphQL 操作(`?query={me{id}}`)都会保留,查询 URL 仅通过子集关系合并,渲染噪音资产会被丢弃,wayback/扫描器探测垃圾会被过滤。查询顺序被规范化,因此 `?id=1&token=a` 和 `?token=b&id=2` 会合并,但重复的参数名(`?id=1&id=2`)会作为不同的 HTTP 参数污染攻击面保留。 ### `-F` 折叠对象 ID(路由发现) **适用场景:** 您希望每个端点模式有一个见证,而不是每个对象。对于具体 ID 是噪音的路由扫描过程很有用。 输入: ``` https://example.com/user/41 https://example.com/user/42 https://example.com/user/43 https://example.com/file/550e8400-e29b-41d4-a716-446655440000 https://example.com/file/6ba7b810-9dad-11d1-80b4-00c04fd430c8 ``` 默认输出(全部五个保留,因此 IDOR/BOLA 枚举可以看到每个 ID): ``` https://example.com/user/41 https://example.com/user/42 https://example.com/user/43 https://example.com/file/550e8400-e29b-41d4-a716-446655440000 https://example.com/file/6ba7b810-9dad-11d1-80b4-00c04fd430c8 ``` 使用 `-F`(每个 ID 类折叠为一个见证): ``` https://example.com/user/41 https://example.com/file/550e8400-e29b-41d4-a716-446655440000 ``` 标准侦察模式:首先为 IDOR 过程运行默认模式,然后使用 `-F` 重新运行以获得路由覆盖。 ``` gau example.com | xcull -F > routes.txt ``` ### `-x` 保留无效 URL(取证/调试) **适用场景:** 您怀疑默认清理器丢弃了本应保留的内容,或者您想在没有任何合理性检查的情况下审核原始结构去重。 输入: ``` https://example.com/api/v1/users https://example.com/ https://example.com/api/v1/users/../../etc/passwd https://example.com/api/v1/users?cmd=ls ``` 默认输出(垃圾过滤器丢弃了 XSS 负载和路径遍历;裸端点折叠到其装饰后的同级): ``` https://example.com/api/v1/users?cmd=ls ``` 使用 `-x`(一切都保留,只运行结构去重): ``` https://example.com/api/v1/users https://example.com/ https://example.com/api/v1/users/../../etc/passwd https://example.com/api/v1/users?cmd=ls ``` 与默认运行并排使用,以查看哪些行被归类为垃圾: ``` diff <(cat dirty.txt | xcull) <(cat dirty.txt | xcull -x) | less ``` ### `-a` 保留所有资产(源映射、JS、静态文件中的密钥) **适用场景:** 您正在寻找 JS 包、源映射或静态配置文件中的密钥,而默认渲染噪音过滤器会将其丢弃。 输入: ``` https://example.com/index.html https://example.com/static/app.js https://example.com/static/style.css https://example.com/img/logo.png https://example.com/fonts/main.woff2 ``` 默认输出(CSS、PNG、WOFF2 作为渲染噪音被丢弃;`.js` 和规范化的根保留): ``` https://example.com/ https://example.com/static/app.js ``` 使用 `-a`(每个静态资产都保留): ``` https://example.com/ https://example.com/static/app.js https://example.com/static/style.css https://example.com/img/logo.png https://example.com/fonts/main.woff2 ``` `.map` URL 在默认情况下已保留(源映射泄露未压缩的源代码,并且是一个常见的侦察发现),因此主要为其他静态类使用 `-a`。 ``` gau example.com | xcull -a | grep -E '\.(js|json|env)$' ``` ### `-s` 区分大小写的路径匹配 **适用场景:** 目标运行在大小写敏感的后端上(Java/JSP、某些 Python/Node 框架),其中 `/Admin` 和 `/admin` 是不同的路由。 输入: ``` https://example.com/Login https://example.com/login https://example.com/Admin/panel https://example.com/admin/panel ``` 默认输出(大小写折叠,先到先得): ``` https://example.com/Login https://example.com/Admin/panel ``` 使用 `-s`(每个大小写变体都保留): ``` https://example.com/Login https://example.com/login https://example.com/Admin/panel https://example.com/admin/panel ``` 在 Apache、IIS 和 PHP 目标上,默认值就是您想要的;仅当您有理由认为后端将大小写视为重要时才使用 `-s`。 ### `-L N` 限制子集合并比较次数(对抗性输入) **适用场景:** 输入中有一个端点累积了数千个不同的查询键集(模糊器转储、遥测日志、缓存清除器垃圾邮件)。默认的子集合并每个插入桶的成本是 O(K);一个对抗性的多基数反链仍然可能花费实际时间。 ``` cat fuzzer_dump.txt | xcull -L 100 -v ``` `-L N` 将每个插入记录的比较次数上限设为 `N`。当达到上限时,该记录将保持未合并状态(输出可能与完整运行不同;这是一个安全阀,而不是质量旋钮)。`0`(默认)表示无上限。 这里没有小的前后对比:在正常输入上,上限永远不会触发,因此 `-L N` 产生与默认字节完全相同的输出。差异仅在单个路径累积了超过 `N` 个不同键集时出现,此时超过上限的记录将未合并地发出,而不是被折叠。 ### `-k` 保留参数值和每个不同的键集(值挖掘) **适用场景:** 您正在挖掘参数值,而不是端点。您希望看到 `?role=`、`?env=`、`?debug=` 的每个具体值,并且不希望 xcull 的查询子集合并折叠任何内容。 输入: ``` https://example.com/page?id=1 https://example.com/page?id=2 https://example.com/page?id=3 https://example.com/page?role=admin https://example.com/page?debug=true ``` 默认输出(每个不同的键集有一个见证;三个 `?id=` 变体因为键集相同而折叠): ``` https://example.com/page?id=1 https://example.com/page?role=admin https://example.com/page?debug=true ``` 使用 `-k`(每个值都保留): ``` https://example.com/page?id=1 https://example.com/page?id=2 https://example.com/page?id=3 https://example.com/page?role=admin https://example.com/page?debug=true ``` 作为副作用,`-k` 还会恢复流式输出(无延迟发送),因此它是最低 RSS 的模式。 ``` # 查找管理/调试/暂存环境的参数值 gau example.com | xcull -k | grep -iE '\?(role|env|debug|admin)=' ``` ### `-p` 无路径模板化(字面路径) **适用场景:** 目标的路径段是有意义的,而不是模板化的。文档站点、内容门户、知识库,其中每个 slug 是不同的内容,而不是同一路由的变体。 输入: ``` https://example.com/blog/post-title-1 https://example.com/blog/post-title-2 https://example.com/blog/post-title-3 https://example.com/blog/post-title-4 https://example.com/blog/post-title-5 https://example.com/blog/post-title-6 https://example.com/blog/post-title-7 https://example.com/blog/post-title-8 https://example.com/docs/install https://example.com/docs/config ``` 默认输出(博客 slug 组折叠为一个见证;两个文档页保持不同,因为未达到 slug 类阈值): ``` https://example.com/blog/post-title-1 https://example.com/docs/install https://example.com/docs/config ``` 使用 `-p`(每个不同的路径都保留): ``` https://example.com/blog/post-title-1 https://example.com/blog/post-title-2 https://example.com/blog/post-title-3 https://example.com/blog/post-title-4 https://example.com/blog/post-title-5 https://example.com/blog/post-title-6 https://example.com/blog/post-title-7 https://example.com/blog/post-title-8 https://example.com/docs/install https://example.com/docs/config ``` 当您更愿意将完整的路径清单交给支持文档的扫描器时使用。 ``` gau docs.example.com | xcull -p > docs_paths.txt ``` ### `-W` 退出 wayback 噪音处理 **适用场景:** 输入来自 wayback,但您希望主机保持与存档记录的完全一致。默认情况下,xcull 会去除 wayback 附加到主机前的开头百分号编码胶(`2f`、`3a`、`25252f` 等),因此 `2fexample.com` 会折叠到 `example.com`。`-W` 保留这些原始主机,以便您可以研究存档是如何损坏它们的。 输入: ``` https://2fexample.com/login https://example.com/login https://3aexample.com/admin https://example.com/admin ``` 默认输出(去除了开头的 wayback 胶,因此损坏的主机折叠到干净的主机上): ``` https://example.com/login https://example.com/admin ``` 使用 `-W`(原始主机,无折叠): ``` https://2fexample.com/login https://example.com/login https://3aexample.com/admin https://example.com/admin ``` ``` # 保留归档的原始主机关联信息(用于威胁情报/取证工作) waybackurls example.com | xcull -W ``` ### `-r` 退出 URL 规范化 **适用场景:** 您需要与其他工具进行字节精确比较,输入已经是 RFC 3986 规范化的,或者您正在调试编码问题,而 xcull 的规范化器可能隐藏了该问题。 输入: ``` https://example.com:443/api/users https://example.com/login%2Fadmin http://example.com:80/page ``` 默认输出(去除默认端口,百分号编码的斜杠保留为字面字符): ``` https://example.com/api/users https://example.com/login%2Fadmin http://example.com/page ``` 使用 `-r`(无规范化;保留默认端口): ``` https://example.com:443/api/users https://example.com/login%2Fadmin http://example.com:80/page ``` ``` cat urls.txt | xcull -r | diff - <(cat urls.txt | xcull) ``` ### `-v`, `--verbose` 统计信息(CI、监控) **适用场景:** 您想要一行运行摘要(输入行数、输出行数、峰值 RSS)用于日志、CI 或快速合理性检查。区别在 stderr 上;stdout 与默认运行字节完全相同,因此 `-v` 可以安全地在生产流水线中保留。 默认(无 `-v`)不向 stderr 写入任何内容: ``` $ cat urls.txt | xcull > /dev/null $ ``` 使用 `-v`,运行结束后一行摘要会写入 stderr: ``` $ cat urls.txt | xcull -v > /dev/null xcull: 782143 -> 55920 (peak RSS 22612 KB) ``` ``` gau example.com | xcull -v > urls.txt 2>> xcull.log ``` ``` # CI 断言:去重比率至少应达到 5 倍 in=$(wc -l < urls.txt) out=$(xcull -v < urls.txt 2>&1 > deduped.txt | awk '{print $4}') test $(( in / out )) -ge 5 || { echo "dedup too weak"; exit 1; } ``` ### `-V`, `--version` 构建信息 **适用场景:** 您需要记录具体是哪个构建产生了结果,或者提交错误报告。像 `wget --version` 一样,它会打印版本、平台、编译时的功能、实际的构建和链接标志、默认策略和许可证,然后退出。 ``` $ xcull --version xcull 2.1.0 built on Linux x86_64. Capabilities (all compiled in, libc only, no runtime dependencies): +idor-preserve +session-preserve +hpp-preserve +query-shape-dedup +subset-merge +garbage-gate +wayback-clean +case-fold +canonical Build: -O3 -march=native -flto gcc 14.2.0 built May 28 2026 ... ``` `-V` 和 `--version` 是等效的。 ## 输出 xcull 将清理后的 URL 写入 stdout,每行一个,按首次出现的确定性顺序。stderr 保留用于诊断信息。 ### stdout 去重后的 URL 集。将其管道传输到文件、从 stdin 读取的工具(`qsreplace`、`nuclei`、`ffuf`、`httpx`、`gf`),或使用 `tee` 同时传输两者。 ``` cat urls.txt | xcull > deduped.txt ``` ### stderr (`-v`) 使用 `-v`(或 `--verbose`)时,xcull 在运行结束后向 stderr 打印一行摘要: ``` xcull: 782143 -> 55920 (peak RSS 22612 KB) ``` 数字含义为:读取的输入行数、发出的输出行数、峰值驻留集大小(千字节)。stdout 不受影响,因此 `-v` 可以安全地添加到生产流水线中。 ``` cat urls.txt | xcull -v > deduped.txt # stderr: xcull: 782143 -> 55920(峰值 RSS 22612 KB) ``` ### 退出代码 | 代码 | 含义 | |------|------| | 0 | 成功。已写入输出。 | | 1 | stdin 或 stdout 上的 I/O 错误。 | | 2 | 未知标志或格式错误的参数。 | ## 流水线集成 xcull 是一个 stdin-stdout 过滤器。上游任何发出 URL 的源都可以为其提供输入;下游任何消费 URL 的源都可以从它读取。 ### 与存档源配合 ``` # gau (https://github.com/lc/gau) gau example.com | xcull > urls.txt # waybackurls (https://github.com/tomnomnom/waybackurls) waybackurls example.com | xcull > urls.txt # 两者合并,进行一次性去重 ( gau example.com; waybackurls example.com ) | xcull > urls.txt ``` ### 与主动爬虫器配合 ``` # katana (https://github.com/projectdiscovery/katana) katana -u https://example.com -silent | xcull > urls.txt # hakrawler (https://github.com/hakluke/hakrawler) echo https://example.com | hakrawler | xcull > urls.txt ``` ### 为参数模糊器提供输入 ``` # qsreplace + ffuf 风格的参数模糊测试 gau example.com | xcull | qsreplace FUZZ | sort -u > params.txt # 仅包含查询字符串的 URL cat urls.txt | xcull | grep '?' > queried.txt ``` ### 为漏洞扫描器提供输入 ``` # nuclei (https://github.com/projectdiscovery/nuclei) cat urls.txt | xcull | nuclei -t exposures/ # 扫描前进行 httpx 存活检查 cat urls.txt | xcull | httpx -silent | nuclei ``` ### 与 anew 组合 ``` # 仅保留之前未见过的 URL gau example.com | xcull | anew urls.txt ``` ## 基准测试 在单个标记的 780,200 URL 输入(`D_unified.full`,55,920 个真实规范端点组)上,与 `urldedupe`、`uro`、`urless` 和 `uddup` 进行可复现的直接对比。峰值 RSS、吞吐量、完成时间、错误合并率、每个类别的 PRF 以及支持每个主张的所有 CSV 数据都位于一个单独的仓库中: **[github.com/xcull/xcull-benchmark](https://github.com/xcull/xcull-benchmark)** 一个 99 行的并排演示(侦察工程师一眼就能注意到的差异类型:对象 ID、会话令牌、slug 折叠、查询键集合并)位于 **[xcull-benchmark/COMPARISON.md](https://github.com/xcull/xcull-benchmark/blob/main/COMPARISON.md)**。 ## 问题报告 为保持问题跟踪器专注于可操作的项目,请: - **错误报告** 通过 [问题模板](https://github.com/xcull/xcull/issues/new?template=bug_report.yml) 提交。 包括最小重现器:命令行、触发问题的最小输入、预期输出、实际输出。五行重现器处理最快。 - **功能请求** 通过 [功能模板](https://github.com/xcull/xcull/issues/new?template=feature_request.yml) 提交。 如果提案合并了当前保留的 URL,请论证为什么合并后的 URL 不代表不同的攻击面。 - **安全漏洞** 不得作为公开问题提交。请使用 GitHub 私有漏洞报告功能,地址为 [github.com/xcull/xcull/security/advisories/new](https://github.com/xcull/xcull/security/advisories/new)。 范围请参见 [SECURITY.md](SECURITY.md)。 - **使用问题** 和流水线集成帮助欢迎在 [讨论区](https://github.com/xcull/xcull/discussions) 提问。 有关补丁门槛和发布流程,请参见 [CONTRIBUTING.md](CONTRIBUTING.md)。 ## 赞助
Sponsor xcull 如果您想支持此项目,可以在 **[github.com/sponsors/xcull](https://github.com/sponsors/xcull)** 成为赞助者。
## 许可证 源代码在 **Xcull Source Available License (XSAL) v1.0** 下可用。 个人使用、漏洞赏金研究和非商业安全工作免费。完整条款请参见 [LICENSE](LICENSE.md)。 ### 商业和 OEM 许可 在商业产品、托管服务、SaaS 平台或设备中嵌入 xcull 需要单独的许可。定价层级和联系方式在 [XCOL.md](XCOL.md) 中。 ## 更新日志 发布日志请参见 [CHANGELOG.md](CHANGELOG.md)。
标签:BOLA枚举, IDOR枚举, URL去重, 会话令牌测试, 侦察工具, 侦察管道, 内存优化, 安全感知, 客户端加密, 授权测试, 流式处理, 网络安全, 请求拦截, 隐私保护, 静态二进制