mirror of
https://github.com/shmilylty/OneForAll.git
synced 2026-08-26 04:47:48 +08:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d6b7c1b7b | |||
| bc9b5b0afe | |||
| a332d3bdc4 | |||
| c3f6f0b08d | |||
| 515bd34c7e | |||
| 32330fa8b2 | |||
| 16d3530ac3 | |||
| cc10ce78d3 | |||
| f35239de40 | |||
| daaf7891d6 | |||
| 46d447392c | |||
| b4432dfd47 | |||
| 1b9b9cb11d | |||
| f4b4f06333 | |||
| fca97c7d5c | |||
| 818af18355 | |||
| 69f94193f6 | |||
| 403a3fefcb | |||
| 8ce39a9127 | |||
| f3a1b2bada | |||
| 41422f4826 | |||
| 6189bc73ac | |||
| 45d9ae2f2d | |||
| c329f6c77e | |||
| 9fa77a16b6 | |||
| 2c581c31aa | |||
| 76fc12c365 | |||
| 3413869bf1 | |||
| 84aea67aa0 | |||
| 73d92a92e1 | |||
| 9c8d7e937e | |||
| b165670ed3 | |||
| 4e6dd23129 |
@@ -29,6 +29,7 @@ assignees: shmilylty
|
||||
**运行环境**
|
||||
- 系统:[例如Windows 10 x64]
|
||||
- Python版本:[例如3.7.1]
|
||||
- OneForAll版本:[例如0.0.6]
|
||||
|
||||
|
||||
**报错文本**
|
||||
|
||||
@@ -6,6 +6,13 @@ OneForAll的更新日志格式基于[Keep a Changelog](https://keepachangelog.co
|
||||
OneForAll遵守[语义化版本格式](https://semver.org/)。
|
||||
|
||||
## Unreleased
|
||||
## [0.0.6](https://github.com/shmilylty/oneforall/releases/tag/v0.0.6) - 2019-08-27
|
||||
- 修复一些已知问题
|
||||
- 添加PassiveDNS查询和Github子域搜索模块
|
||||
- 优化FoFa和BufferOver收集模块
|
||||
- 更新有关文档
|
||||
- 更新依赖
|
||||
|
||||
## [0.0.5](https://github.com/shmilylty/oneforall/releases/tag/v0.0.5) - 2019-08-19
|
||||
- 修复一些已知Bugs
|
||||
- 优化各子域收集接口并添加新的子域收集接口
|
||||
|
||||
+8
-2
@@ -6,6 +6,12 @@
|
||||
* **[Black Star](https://github.com/blackstar24)**
|
||||
* 模块贡献
|
||||
|
||||
* [**iceMatcha**](https://github.com/iceMatcha)
|
||||
* bug调试
|
||||
* **[Echocipher](https://github.com/Echocipher)**
|
||||
* 模块贡献
|
||||
|
||||
* **[iceMatcha](https://github.com/iceMatcha)**
|
||||
* 工具测试
|
||||
|
||||
* **Anyone**
|
||||
* 工具反馈
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ pysocks = "*"
|
||||
cloudscraper = "*"
|
||||
js2py = "*"
|
||||
tablib = "*"
|
||||
brotlipy = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.7"
|
||||
|
||||
Generated
+38
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "0e5757dad136b3c0900ba481fad3b90e1b346b8cf8974e94676890f603f2a452"
|
||||
"sha256": "9a29beced25222ff7c32a32aaa99c292ee43986700b280c6153e01245a5a71bc"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@@ -54,10 +54,10 @@
|
||||
},
|
||||
"aiomultiprocess": {
|
||||
"hashes": [
|
||||
"sha256:fd9b616d5145ac2b01f315725277231ffad7e56eb6675885598f6fe861ef9fa3"
|
||||
"sha256:c704383be74ccb806e2617cb3bb6a5faa1774b1c6643d62785c332eb6da9e742"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.6.0"
|
||||
"version": "==0.6.1"
|
||||
},
|
||||
"asn1crypto": {
|
||||
"hashes": [
|
||||
@@ -128,6 +128,41 @@
|
||||
],
|
||||
"version": "==1.0.7"
|
||||
},
|
||||
"brotlipy": {
|
||||
"hashes": [
|
||||
"sha256:07194f4768eb62a4f4ea76b6d0df6ade185e24ebd85877c351daa0a069f1111a",
|
||||
"sha256:091b299bf36dd6ef7a06570dbc98c0f80a504a56c5b797f31934d2ad01ae7d17",
|
||||
"sha256:09ec3e125d16749b31c74f021aba809541b3564e5359f8c265cbae442810b41a",
|
||||
"sha256:0be698678a114addcf87a4b9496c552c68a2c99bf93cf8e08f5738b392e82057",
|
||||
"sha256:0fa6088a9a87645d43d7e21e32b4a6bf8f7c3939015a50158c10972aa7f425b7",
|
||||
"sha256:1ea4e578241504b58f2456a6c69952c88866c794648bdc74baee74839da61d44",
|
||||
"sha256:2699945a0a992c04fc7dc7fa2f1d0575a2c8b4b769f2874a08e8eae46bef36ae",
|
||||
"sha256:2a80319ae13ea8dd60ecdc4f5ccf6da3ae64787765923256b62c598c5bba4121",
|
||||
"sha256:2e5c64522364a9ebcdf47c5744a5ddeb3f934742d31e61ebfbbc095460b47162",
|
||||
"sha256:36def0b859beaf21910157b4c33eb3b06d8ce459c942102f16988cca6ea164df",
|
||||
"sha256:3a3e56ced8b15fbbd363380344f70f3b438e0fd1fcf27b7526b6172ea950e867",
|
||||
"sha256:3c1d5e2cf945a46975bdb11a19257fa057b67591eb232f393d260e7246d9e571",
|
||||
"sha256:50ca336374131cfad20612f26cc43c637ac0bfd2be3361495e99270883b52962",
|
||||
"sha256:5de6f7d010b7558f72f4b061a07395c5c3fd57f0285c5af7f126a677b976a868",
|
||||
"sha256:637847560d671657f993313ecc6c6c6666a936b7a925779fd044065c7bc035b9",
|
||||
"sha256:653faef61241bf8bf99d73ca7ec4baa63401ba7b2a2aa88958394869379d67c7",
|
||||
"sha256:786afc8c9bd67de8d31f46e408a3386331e126829114e4db034f91eacb05396d",
|
||||
"sha256:79aaf217072840f3e9a3b641cccc51f7fc23037496bd71e26211856b93f4b4cb",
|
||||
"sha256:7e31f7adcc5851ca06134705fcf3478210da45d35ad75ec181e1ce9ce345bb38",
|
||||
"sha256:8b39abc3256c978f575df5cd7893153277216474f303e26f0e43ba3d3969ef96",
|
||||
"sha256:9448227b0df082e574c45c983fa5cd4bda7bfb11ea6b59def0940c1647be0c3c",
|
||||
"sha256:96bc59ff9b5b5552843dc67999486a220e07a0522dddd3935da05dc194fa485c",
|
||||
"sha256:a07647886e24e2fb2d68ca8bf3ada398eb56fd8eac46c733d4d95c64d17f743b",
|
||||
"sha256:af65d2699cb9f13b26ec3ba09e75e80d31ff422c03675fcb36ee4dabe588fdc2",
|
||||
"sha256:b4c98b0d2c9c7020a524ca5bbff42027db1004c6571f8bc7b747f2b843128e7a",
|
||||
"sha256:c6cc0036b1304dd0073eec416cb2f6b9e37ac8296afd9e481cac3b1f07f9db25",
|
||||
"sha256:d2c1c724c4ac375feb2110f1af98ecdc0e5a8ea79d068efb5891f621a5b235cb",
|
||||
"sha256:dc6c5ee0df9732a44d08edab32f8a616b769cc5a4155a12d2d010d248eb3fb07",
|
||||
"sha256:fd1d1c64214af5d90014d82cee5d8141b13d44c92ada7a0c0ec0679c6f15a471"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.7.0"
|
||||
},
|
||||
"bs4": {
|
||||
"hashes": [
|
||||
"sha256:36ecea1fd7cc5c0c6e4a1ff075df26d50da647b75376626cc186e2212886dd3a"
|
||||
|
||||
@@ -3,16 +3,20 @@
|
||||
[](https://travis-ci.org/shmilylty/OneForAll)
|
||||
[](https://codecov.io/gh/shmilylty/OneForAll)
|
||||
[](https://codeclimate.com/github/shmilylty/OneForAll/maintainability)
|
||||
[](./LICENSE)
|
||||
[](./)
|
||||
[](https://github.com/shmilylty/OneForAll/releases)
|
||||
[](https://github.com/shmilylty/OneForAll/tree/master/LICENSE)
|
||||
[](https://github.com/shmilylty/OneForAll/tree/master/)
|
||||
[](https://github.com/shmilylty/OneForAll/tree/master/releases)
|
||||
|
||||
👊**OneForAll是一款功能强大的子域收集工具** 📝[English Document](./README.en.md)
|
||||
👊**OneForAll是一款功能强大的子域收集工具** 📝[English Document](https://github.com/shmilylty/OneForAll/tree/master/README.en.md)
|
||||
|
||||

|
||||

|
||||
|
||||
## 🎉项目简介
|
||||
|
||||
项目主页:[https://shmilylty.github.io/OneForAll/](https://shmilylty.github.io/OneForAll/)
|
||||
|
||||
项目地址:[https://github.com/shmilylty/OneForAll](https://github.com/shmilylty/OneForAll)
|
||||
|
||||
在渗透测试中信息收集的重要性不言而喻,子域收集是信息收集中必不可少且非常重要的一环,目前网上也开源了许多子域收集的工具,但是总是存在以下部分问题:
|
||||
|
||||
* **不够强大**,子域收集的接口不够多,不能做到对批量子域自动收集,没有自动子域解析,验证,FUZZ以及信息拓展等功能。
|
||||
@@ -28,24 +32,26 @@
|
||||
|
||||
## 👍功能特性
|
||||
|
||||
* **收集能力强大**,详细模块请阅读[收集模块说明](./docs/collection_modules.md)。
|
||||
* **收集能力强大**,详细模块请阅读[收集模块说明](https://github.com/shmilylty/OneForAll/tree/master/docs/collection_modules.md)。
|
||||
1. 利用证书透明度收集子域(目前有6个模块:`censys_api`,`certdb_api`,`certspotter`,`crtsh`,`entrust`,`google`)
|
||||
|
||||
2. 常规检查收集子域(目前有4个模块:域传送漏洞利用`axfr`,检查跨域策略文件`cdx`,检查HTTPS证书`cert`,检查内容安全策略`csp`,检查robots文件`robots`,检查sitemap文件`sitemap`,后续会添加检查NSEC记录,NSEC3记录等模块)
|
||||
|
||||
3. 利用网上爬虫档案收集子域(目前有2个模块:`archivecrawl`,`commoncrawl`,此模块还在调试,该模块还有待添加和完善)
|
||||
|
||||
4. 利用DNS数据集收集子域(目前有17个模块:`binaryedge_api`, `circl_api`, `hackertarget`, `riddler`, `bufferover`, `dnsdb`, `ipv4info`, `robtex`, `chinaz`, `dnsdb_api`, `netcraft`, `securitytrails_api`, `chinaz_api`, `dnsdumpster`, `ptrarchive`, `sitedossier`,`threatcrowd`)
|
||||
4. 利用DNS数据集收集子域(目前有18个模块:`binaryedge_api`, `circl_api`, `hackertarget`, `riddler`, `bufferover`, `dnsdb`, `ipv4info`, `robtex`, `chinaz`, `dnsdb_api`, `netcraft`, `securitytrails_api`, `chinaz_api`, `dnsdumpster`, `passivedns_api`, `ptrarchive`, `sitedossier`,`threatcrowd`)
|
||||
|
||||
5. 利用DNS查询收集子域(目前有1个模块:通过枚举常见的SRV记录并做查询来收集子域`srv`,该模块还有待添加和完善)
|
||||
|
||||
6. 利用威胁情报平台数据收集子域(目前有5个模块:`riskiq_api`,`threatbook_api`,`threatminer`,`virustotal`,`virustotal_api`该模块还有待添加和完善)
|
||||
|
||||
7. 利用搜索引擎发现子域(目前有15个模块:`ask`, `bing_api`, `fofa_api`, `shodan_api`, `yahoo`, `baidu`, `duckduckgo`, `google`, `so`, `yandex`, `bing`, `exalead`, `google_api`, `sogou`, `zoomeye_api`),在搜索模块中除特殊搜索引擎,通用的搜索引擎都支持自动排除搜索,全量搜索,递归搜索。
|
||||
|
||||
* **处理功能强大**,发现的子域结果支持自动去除,自动DNS解析,HTTP请求探测,自动移除无效子域,拓展子域的Banner信息,最终支持的导出格式有`csv`, `tsv`, `json`, `yaml`, `html`, `xls`, `xlsx`, `dbf`, `latex`, `ods`。
|
||||
|
||||
* **速度极速**,[收集模块](./oneforall/collect.py)使用多线程调用,[爆破模块](./oneforall/aiobrute.py)使用异步多进程多协程,DNS解析和HTTP请求使用异步多协程。
|
||||
7. 利用搜索引擎发现子域(目前有16个模块:`ask`, `bing_api`, `fofa_api`, `shodan_api`, `yahoo`, `baidu`, `duckduckgo`, `github`, `google`, `so`, `yandex`, `bing`, `exalead`, `google_api`, `sogou`, `zoomeye_api`),在搜索模块中除特殊搜索引擎,通用的搜索引擎都支持自动排除搜索,全量搜索,递归搜索。
|
||||
* **支持子域爆破**,该模块有常规的字典爆破,也有自定义的fuzz模式,支持批量爆破和递归爆破,自动判断泛解析并处理。
|
||||
* **支持子域验证**,默认开启子域验证,自动解析子域DNS,自动请求子域获取title和banner,并综合判断子域存活情况。
|
||||
* **支持子域接管**,默认开启子域接管风险检查,支持子域自动接管(目前只有Github,有待完善),支持批量检查。
|
||||
* **处理功能强大**,发现的子域结果支持自动去除,自动DNS解析,HTTP请求探测,自动筛选出有效子域,拓展子域的Banner信息,最终支持的导出格式有`txt`, `rst`, `csv`, `tsv`, `json`, `yaml`, `html`, `xls`, `xlsx`, `dbf`, `latex`, `ods`。
|
||||
* **速度极快**,[收集模块](https://github.com/shmilylty/OneForAll/tree/master/oneforall/collect.py)使用多线程调用,[爆破模块](https://github.com/shmilylty/OneForAll/tree/master/oneforall/aiobrute.py)使用异步多进程多协程,子域验证中DNS解析和HTTP请求使用异步多协程,多线程检查[子域接管](https://github.com/shmilylty/OneForAll/tree/master/oneforall/takeover.py)风险。
|
||||
* **体验良好**,日志和终端输出全使用中文,各大模块都有进度条,异步保存各模块结果。
|
||||
|
||||
## 🚀上手指南
|
||||
|
||||
@@ -53,7 +59,7 @@
|
||||
|
||||
**🐍安装要求**
|
||||
|
||||
OneForAll是基于CPython开发的,所以你需要Python环境才能运行,如果你的系统还没有Pythin环境你可以参考[Python 3 安装指南](https://pythonguidecn.readthedocs.io/zh/latest/starting/installation.html#python-3),理论上Python 3.6,3.7和3.8都可以正常运行OneForAll,**但是**许多测试都是在Python 3.7上进行的,所以**推荐**你使用**Python 3.7**版本运行OneForAll。运行以下命令检查Python和pip3版本:
|
||||
OneForAll是基于CPython开发的,所以你需要Python环境才能运行,如果你的系统还没有Python环境你可以参考[Python 3 安装指南](https://pythonguidecn.readthedocs.io/zh/latest/starting/installation.html#python-3),理论上Python 3.6,3.7和3.8都可以正常运行OneForAll,**但是**许多测试都是在Python 3.7上进行的,所以**推荐**你使用**Python 3.7**版本运行OneForAll。运行以下命令检查Python和pip3版本:
|
||||
```bash
|
||||
python -V
|
||||
pip3 -V
|
||||
@@ -79,7 +85,7 @@ pip 19.2.2 from C:\Users\shmilylty\AppData\Roaming\Python\Python37\site-packages
|
||||
|
||||
2. **安装**
|
||||
首先运行以下命令
|
||||
你可以通过pip3安装OneForAll的依赖(如果你熟悉[pipenv](https://docs.pipenv.org/en/latest/),那么推荐你使用[pipenv安装依赖]((./docs/Installation_dependency.md))),以下为**Windows系统**下使用**pip3**安装依赖的示例:(注意:如果你的Python3安装在系统Program Files目录下,如:`C:\Program Files\Python37`,那么请以管理员身份运行命令提示符cmd执行以下命令!)
|
||||
你可以通过pip3安装OneForAll的依赖(如果你熟悉[pipenv](https://docs.pipenv.org/en/latest/),那么推荐你使用[pipenv安装依赖]((https://github.com/shmilylty/OneForAll/tree/master/docs/Installation_dependency.md))),以下为**Windows系统**下使用**pip3**安装依赖的示例:(注意:如果你的Python3安装在系统Program Files目录下,如:`C:\Program Files\Python37`,那么请以管理员身份运行命令提示符cmd执行以下命令!)
|
||||
|
||||
```bash
|
||||
cd OneForAll/
|
||||
@@ -88,7 +94,7 @@ pip 19.2.2 from C:\Users\shmilylty\AppData\Roaming\Python\Python37\site-packages
|
||||
cd oneforall/
|
||||
python oneforall.py --help
|
||||
```
|
||||
其他系统平台的请参考[依赖安装](./docs/installation_dependency.md),如果在安装依赖过程中发现编译某个依赖库失败时可以参考[编译失败解决方法](./docs/building_fail_solution.md),如果还没有解决欢迎加群反馈。
|
||||
其他系统平台的请参考[依赖安装](https://github.com/shmilylty/OneForAll/tree/master/docs/installation_dependency.md),如果在安装依赖过程中发现编译某个依赖库失败时可以参考[Q&A](https://github.com/shmilylty/OneForAll/tree/master/docs/Q&A.md)中解决方法,如果还没有解决欢迎加群反馈。
|
||||
|
||||
3. **更新**
|
||||
❗注意:如果你之前已经克隆了项目运行之前请**备份**自己修改过的文件到项目外的地方(如**config.py**),然后执行以下命令**更新**项目:
|
||||
@@ -117,13 +123,13 @@ pip 19.2.2 from C:\Users\shmilylty\AppData\Roaming\Python\Python37\site-packages
|
||||
|
||||
**🤔使用帮助**
|
||||
|
||||
命令行参数只提供了一些常用参数,更多详细的参数配置请见[config.py](./oneforall/config.py),如果你认为有些参数是命令界面经常使用到的或缺少了什么参数等问题非常欢迎反馈。由于众所周知的原因,如果要使用一些被墙的收集接口请先到[config.py](./oneforall/config.py)配置代理,有些收集模块需要提供API(大多都是可以注册账号免费获取),如果需要使用请到[config.py](./oneforall/config.py)配置API信息,如果不使用请忽略有关报错提示。(详细模块请阅读[收集模块说明](./docs/collection_modules.md))
|
||||
命令行参数只提供了一些常用参数,更多详细的参数配置请见[config.py](https://github.com/shmilylty/OneForAll/tree/master/oneforall/config.py),如果你认为有些参数是命令界面经常使用到的或缺少了什么参数等问题非常欢迎反馈。由于众所周知的原因,如果要使用一些被墙的收集接口请先到[config.py](https://github.com/shmilylty/OneForAll/tree/master/oneforall/config.py)配置代理,有些收集模块需要提供API(大多都是可以注册账号免费获取),如果需要使用请到[config.py](https://github.com/shmilylty/OneForAll/tree/master/oneforall/config.py)配置API信息,如果不使用请忽略有关报错提示。(详细模块请阅读[收集模块说明](https://github.com/shmilylty/OneForAll/tree/master/docs/collection_modules.md))
|
||||
|
||||
OneForAll命令行界面基于[Fire](https://github.com/google/python-fire/)实现,有关Fire更高级使用方法请参阅[使用Fire CLI](https://github.com/google/python-fire/blob/master/docs/using-cli.md),有任何使用疑惑欢迎加群交流。
|
||||
|
||||
oneforall.py是主程序入口,oneforall.py里有调用aiobrute.py和dbexport.py,为了方便进行子域爆破和数据库导出独立出了aiobrute.py和dbexport.py,这两个文件可以单独运行,并且所接受参数要更丰富一点。
|
||||
[oneforall.py](https://github.com/shmilylty/OneForAll/tree/master/oneforall/oneforall.py)是主程序入口,oneforall.py可以调用[aiobrute.py](https://github.com/shmilylty/OneForAll/tree/master/oneforall/aiobrute.py),[takerover.py](https://github.com/shmilylty/OneForAll/tree/master/oneforall/takerover.py)及[dbexport.py](https://github.com/shmilylty/OneForAll/tree/master/oneforall/dbexport.py)等模块,为了方便进行子域爆破独立出了aiobrute.py,为了方便进行子域接管风险检查独立出了takerover.py,为了方便数据库导出独立出了dbexport.py,这些模块都可以单独运行,并且所接受参数要更丰富一点。
|
||||
|
||||
❗注意:当你在使用过程中遇到一些问题或者疑惑时,请先到[Issues](https://github.com/shmilylty/OneForAll/issues)里使用搜索找找答案,还可以参阅[常见问题与回答](./docs/Q&A.md)。
|
||||
❗注意:当你在使用过程中遇到一些问题或者疑惑时,请先到[Issues](https://github.com/shmilylty/OneForAll/tree/master/issues)里使用搜索找找答案,还可以参阅[常见问题与回答](https://github.com/shmilylty/OneForAll/tree/master/docs/Q&A.md)。
|
||||
|
||||
1. **oneforall.py使用帮助**
|
||||
|
||||
@@ -138,7 +144,7 @@ oneforall.py是主程序入口,oneforall.py里有调用aiobrute.py和dbexport.
|
||||
oneforall.py --target=TARGET <flags>
|
||||
|
||||
DESCRIPTION
|
||||
Version: 0.0.5
|
||||
Version: 0.0.6
|
||||
Project: https://git.io/fjHT1
|
||||
|
||||
Example:
|
||||
@@ -184,9 +190,9 @@ oneforall.py是主程序入口,oneforall.py里有调用aiobrute.py和dbexport.
|
||||
|
||||
关于泛解析问题处理程序首先会访问一个随机的子域判断是否泛解析,如果使用了泛解析则是通过以下判断处理:
|
||||
- 一是主要是与泛解析的IP集合和TTL值做对比,可以参考[这篇文章](http://sh3ll.me/archives/201704041222.txt)。
|
||||
- 二是多次解析到同一IP集合次数(默认设置为10,可以在config.py设置大小)
|
||||
- 考虑爆破效率问题目前还没有加上HTTP响应体相似度对比和响应体内容判断
|
||||
经过测试在16核心的CPU,使用16进程64协程,100M带宽的环境下,设置任务分割为50000,跑两百万字典大概10分钟左右跑完,大概3333个子域每秒。
|
||||
- 二是多次解析到同一IP集合次数(默认设置为10,可以在config.py设置大小)。
|
||||
- 三是考虑爆破效率问题目前还没有加上HTTP响应体相似度对比和响应体内容判断,如果有必要后续添加。
|
||||
经过不严谨测试在16核心的CPU,使用16进程64协程,100M带宽的环境下,设置任务分割为50000,跑两百万字典大概10分钟左右跑完,大概3333个子域每秒。
|
||||
|
||||
```bash
|
||||
python aiobrute.py --help
|
||||
@@ -252,7 +258,7 @@ oneforall.py是主程序入口,oneforall.py里有调用aiobrute.py和dbexport.
|
||||
终端显示导出数据(默认False)
|
||||
```
|
||||
|
||||
3. 其他模块使用请参考[使用帮助](./docs/using_help.md)
|
||||
3. 其他模块使用请参考[使用帮助](https://github.com/shmilylty/OneForAll/tree/master/docs/using_help.md)
|
||||
|
||||
## 👏主要框架
|
||||
|
||||
@@ -310,18 +316,18 @@ D:.
|
||||
|
||||
## ⌛后续计划
|
||||
|
||||
- [ ] 子域收集模块优化
|
||||
- [ ] 子域接管功能实现
|
||||
- [ ] 子域收集爬虫实现
|
||||
- [ ] 操作强大交互人性的前端界面实现
|
||||
- [ ] 各模块支持优化和完善
|
||||
- [ ] 子域监控(标记每次新发现的子域)
|
||||
- [ ] 子域收集爬虫实现(包括从JS等静态资源文件中收集子域)
|
||||
- [ ] 操作强大交互人性的前端界面实现(暂定:前端:Element + 后端:Flask)
|
||||
|
||||
更多详细信息请阅读[TODO.md](./TODO.md)。
|
||||
更多详细信息请阅读[TODO.md](https://github.com/shmilylty/OneForAll/tree/master/TODO.md)。
|
||||
|
||||
## 🔖版本控制
|
||||
|
||||
该项目使用[SemVer](https://semver.org/)语言化版本格式进行版本管理,你可以在[Releases](https://github.com/shmilylty/OneForAll/releases)查看可用版本。
|
||||
|
||||
## 👨💻作者
|
||||
## 👨💻作者及贡献者
|
||||
|
||||
* **[Jing Ling](https://github.com/shmilylty)**
|
||||
* 核心开发
|
||||
@@ -329,14 +335,20 @@ D:.
|
||||
* **[Black Star](https://github.com/blackstar24)**
|
||||
* 模块贡献
|
||||
|
||||
* [**iceMatcha**](https://github.com/iceMatcha)
|
||||
* bug调试
|
||||
* **[Echocipher](https://github.com/Echocipher)**
|
||||
* 模块贡献
|
||||
|
||||
*你也可以在[CONTRIBUTORS.md](./CONTRIBUTORS.md)中参看所有参与该项目的开发者。*
|
||||
* **[iceMatcha](https://github.com/iceMatcha)**
|
||||
* 工具测试
|
||||
|
||||
* **Anyone**
|
||||
* 工具反馈
|
||||
|
||||
*你也可以在[CONTRIBUTORS.md](https://github.com/shmilylty/OneForAll/tree/master/CONTRIBUTORS.md)中参看所有参与该项目的开发者。*
|
||||
|
||||
## 📄版权
|
||||
|
||||
该项目签署了GPL-3.0授权许可,详情请参阅[LICENSE.md](./LICENSE.md)。
|
||||
该项目签署了GPL-3.0授权许可,详情请参阅[LICENSE.md](https://github.com/shmilylty/OneForAll/tree/master/LICENSE.md)。
|
||||
|
||||
## 😘鸣谢
|
||||
|
||||
@@ -346,4 +358,7 @@ D:.
|
||||
|
||||
## 📜免责声明 ##
|
||||
|
||||
本工具仅限于安全研究与教学使用,用户使用本工具所造成的所有后果,由用户承担全部法律及连带责任,本项目所有作者和贡献者不承担任何法律及连带责任。
|
||||
本工具仅限于合法授权的企业安全建设,在使用本工具过程中,您应确保自己所有行为符合当地的法律法规,并且已经取得了足够的授权。
|
||||
如您在使用本工具的过程中存在任何非法行为,您需自行承担所有后果,本工具所有作者和所有贡献者不承担任何法律及连带责任。
|
||||
除非您已充分阅读、完全理解并接受本协议所有条款,否则,请您不要安装并使用本工具。
|
||||
您的使用行为或者您以其他任何明示或者默示方式表示接受本协议的,即视为您已阅读并同意本协议的约束。
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
## 下一步计划
|
||||
|
||||
- [ ] 子域收集模块优化
|
||||
- [ ] 子域接管功能实现
|
||||
- [ ] 子域收集爬虫实现
|
||||
- [ ] 操作强大交互人性的前端界面实现
|
||||
- [ ] 各模块支持优化和完善
|
||||
- [ ] 子域监控(标记每次新发现的子域)
|
||||
- [ ] 子域收集爬虫实现(包括从JS等静态资源文件中收集子域)
|
||||
- [ ] 操作强大交互人性的前端界面实现(暂定:Element+Flask)
|
||||
|
||||
|
||||
+24
-5
@@ -1,12 +1,31 @@
|
||||
# 常见问题与回答
|
||||
|
||||
## 依赖问题
|
||||
|
||||
**Q: 在安装依赖过程遇到编译某个依赖库失败,怎么解决?**
|
||||
|
||||
A: 可以尝试以下方法:
|
||||
|
||||
1. 到提供编译好的whl文件的第三方平台,找到对应库手动下载安装。第三方平台平台有:
|
||||
* [https://www.lfd.uci.edu/~gohlke/pythonlibs](https://www.lfd.uci.edu/~gohlke/pythonlibs)
|
||||
* [https://pythonwheels.com/](https://pythonwheels.com/)
|
||||
|
||||
选择好对应版本执行以下命令手动安装。举个例子,当编译pycares时失败时,找到[https://www.lfd.uci.edu/~gohlke/pythonlibs/#pycares](https://www.lfd.uci.edu/~gohlke/pythonlibs/#pycares),由于我的系统是Windows 10 64位,使用的Python 3.7便下载`pycares‑3.0.0‑cp37‑cp37m‑win_amd64.whl`(一般来说下载最新版本的),然后手动安装:
|
||||
|
||||
```bash
|
||||
pip3 install pycares‑3.0.0‑cp37‑cp37m‑win_amd64.whl
|
||||
```
|
||||
|
||||
2. 到库的项目地址issues和wiki等找找有没有解决方法,如果没有就给他们提issues发邮件😜。
|
||||
|
||||
## 使用问题
|
||||
|
||||
1. 为什么运行OneForAll之后最终结果为空?
|
||||
**Q: 为什么运行OneForAll之后最终结果为空?**
|
||||
|
||||
有几种可能性:第一可能目标域名没有子域。第二由于OneForAll默认会自动验证子域,在导出是只会有效子域,所以存在导出时没有有效子域的情况,你可以在运行OneForAll使用--valid=None指定导出所有发现的子域,你也可以使用--verify=False指定不验证子域的有效性。
|
||||
A: 有几种可能性:第一可能目标域名没有子域。第二由于OneForAll默认会自动验证子域,在导出是只会有效子域,所以存在导出时没有有效子域的情况,你可以在运行OneForAll使用--valid=None指定导出所有发现的子域,你也可以使用--verify=False指定不验证子域的有效性。
|
||||
|
||||
2. 安装依赖时出现以下类似报错
|
||||
**Q: 安装依赖时出现以下类似报错,怎么解决?**
|
||||
Cannot uninstall 'PyYAML'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.
|
||||
|
||||
安装依赖时尝试加上--ignore-installed参数
|
||||
|
||||
A: 安装依赖时尝试加上--ignore-installed参数
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
如果在安装依赖过程遇到编译某个依赖库失败时可以尝试以下方法:
|
||||
|
||||
1. 到提供编译好的whl文件的第三方平台,找到对应库手动下载安装。第三方平台平台有:
|
||||
* [https://www.lfd.uci.edu/~gohlke/pythonlibs](https://www.lfd.uci.edu/~gohlke/pythonlibs)
|
||||
* [https://pythonwheels.com/](https://pythonwheels.com/)
|
||||
|
||||
选择好对应版本执行以下命令手动安装。举个例子,当编译pycares时失败时,找到[https://www.lfd.uci.edu/~gohlke/pythonlibs/#pycares](https://www.lfd.uci.edu/~gohlke/pythonlibs/#pycares),由于我的系统是Windows 10 64位,使用的Python 3.7便下载`pycares‑3.0.0‑cp37‑cp37m‑win_amd64.whl`(一般来说下载最新版本的),然后手动安装:
|
||||
|
||||
```bash
|
||||
pip3 install pycares‑3.0.0‑cp37‑cp37m‑win_amd64.whl
|
||||
```
|
||||
|
||||
2. 到库的项目地址issues和wiki等找找有没有解决方法,如果没有就给他们提issues发邮件😜。
|
||||
+21
-19
@@ -48,7 +48,7 @@ proxy_partial_module = ['GoogleQuery', 'AskSearch'] # 只代理GoogleQuery和As
|
||||
| archivecrawl | 否 | 否 | |
|
||||
| commoncrawl | 否 | 否 | |
|
||||
|
||||
4. 利用DNS数据集收集子域(目前有17个模块:`binaryedge_api`, `circl_api`, `hackertarget`, `riddler`, `bufferover`, `dnsdb`, `ipv4info`, `robtex`, `chinaz`, `dnsdb_api`, `netcraft`, `securitytrails_api`, `chinaz_api`, `dnsdumpster`, `ptrarchive`, `sitedossier`,`threatcrowd`)
|
||||
4. 利用DNS数据集收集子域(目前有18个模块:`binaryedge_api`, `circl_api`, `hackertarget`, `riddler`, `bufferover`, `dnsdb`, `ipv4info`, `robtex`, `chinaz`, `dnsdb_api`, `netcraft`, `securitytrails_api`, `chinaz_api`, `dnsdumpster`, `passivedns_api`, `ptrarchive`, `sitedossier`,`threatcrowd`)
|
||||
|
||||
| 模块名称 | 是否需要代理 | 是否需要API | 其他说明 |
|
||||
| ------------------ | ------------ | ----------- | -------------------------------------------------- |
|
||||
@@ -63,6 +63,7 @@ proxy_partial_module = ['GoogleQuery', 'AskSearch'] # 只代理GoogleQuery和As
|
||||
| hackertarget | 否 | 否 | |
|
||||
| ipv4info | 否 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
| netcraft | 否 | 否 | |
|
||||
| passivedns_api | 否 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
| ptrarchive | 否 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
| riddler | 否 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
| robtex | 否 | 否 | |
|
||||
@@ -83,24 +84,25 @@ proxy_partial_module = ['GoogleQuery', 'AskSearch'] # 只代理GoogleQuery和As
|
||||
| threatminer | 否 | 否 | |
|
||||
| virustotal | 否 | 否 | |
|
||||
| virustotal_api | 否 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
7. 利用搜索引擎发现子域(目前有15个模块:`ask`, `bing_api`, `fofa_api`, `shodan_api`, `yahoo`, `baidu`, `duckduckgo`, `google`, `so`, `yandex`, `bing`, `exalead`, `google_api`, `sogou`, `zoomeye_api`)
|
||||
7. 利用搜索引擎发现子域(目前有16个模块:`ask`, `bing_api`, `fofa_api`, `shodan_api`, `yahoo`, `baidu`, `duckduckgo`, `github`, `google`, `so`, `yandex`, `bing`, `exalead`, `google_api`, `sogou`, `zoomeye_api`)
|
||||
|
||||
除特殊搜索引擎,通用的搜索引擎都支持自动排除搜索,全量搜索,递归搜索。
|
||||
|
||||
| 模块 | 是否需要代理 | 是否需要API | 其他说明 |
|
||||
| ----------- | ---------------------- | ----------- | -------------------------------------------------- |
|
||||
| ask | 是 | 否 | |
|
||||
| baidu | 否 | 否 | |
|
||||
| bing | 否 | 否 | |
|
||||
| bing_api | 否 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
| duckduckgo | 是 | 否 | |
|
||||
| exalead | 否,最好使用国外代理。 | 否 | |
|
||||
| fofa_api | 否 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
| google | 是 | 否 | |
|
||||
| google_api | 是 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
| shodan_api | 否,最好使用国外代理。 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
| so | 否 | 否 | |
|
||||
| sogou | 否 | 否 | |
|
||||
| yahoo | 是 | 否 | |
|
||||
| yandex | 是 | 否 | |
|
||||
| zoomeye_api | 否 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
| 模块 | 是否需要代理 | 是否需要API | 其他说明 |
|
||||
| ----------- | ---------------------- | ----------- | ----------------------------------------------------------- |
|
||||
| ask | 是 | 否 | |
|
||||
| baidu | 否 | 否 | |
|
||||
| bing | 否 | 否 | |
|
||||
| bing_api | 否 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
| duckduckgo | 是 | 否 | |
|
||||
| exalead | 否,最好使用国外代理。 | 否 | |
|
||||
| fofa_api | 否 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
| github | 否 | 否 | 在[config.py](../oneforall/config.py)设置Github邮件名和密码 |
|
||||
| google | 是 | 否 | |
|
||||
| google_api | 是 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
| shodan_api | 否,最好使用国外代理。 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
| so | 否 | 否 | |
|
||||
| sogou | 否 | 否 | |
|
||||
| yahoo | 是 | 否 | |
|
||||
| yandex | 是 | 否 | |
|
||||
| zoomeye_api | 否 | 是 | API使用和申请见[config.py](../oneforall/config.py) |
|
||||
@@ -160,14 +160,14 @@ class AIOBrute(Module):
|
||||
:param str rule: fuzz模式使用的正则规则(默认使用config.py配置)
|
||||
:param bool export: 是否导出爆破结果(默认True)
|
||||
:param int valid: 导出子域的有效性(默认None)
|
||||
:param str format: 导出格式(默认xls)
|
||||
:param str format: 导出格式(默认csv)
|
||||
:param str path: 导出路径(默认None)
|
||||
:param bool show: 终端显示导出数据(默认False)
|
||||
"""
|
||||
|
||||
def __init__(self, target, process=None, coroutine=64, wordlist=None,
|
||||
segment=500, recursive=False, depth=2, namelist=None,
|
||||
fuzz=False, rule=None, export=True, valid=None, format='xls',
|
||||
fuzz=False, rule=None, export=True, valid=None, format='csv',
|
||||
path=None, show=False):
|
||||
Module.__init__(self)
|
||||
self.domains = set()
|
||||
@@ -211,6 +211,8 @@ class AIOBrute(Module):
|
||||
|
||||
def deal_results(self, results):
|
||||
for result in results:
|
||||
if result is None:
|
||||
continue
|
||||
if isinstance(result, Exception):
|
||||
# logger.log('DEBUG', f'爆破{subdomain}时出错 {str(answers)}')
|
||||
continue
|
||||
|
||||
@@ -17,7 +17,7 @@ class Collect(object):
|
||||
self.collect_func = []
|
||||
self.path = None
|
||||
self.export = export
|
||||
self.format = 'xls'
|
||||
self.format = 'csv'
|
||||
|
||||
def get_mod(self):
|
||||
"""
|
||||
|
||||
@@ -31,9 +31,9 @@ class Domain(object):
|
||||
"""
|
||||
域名导出
|
||||
|
||||
>>>d = Domain('www.example.com')
|
||||
>>> d = Domain('www.example.com')
|
||||
<domain.Domain object>
|
||||
>>>d.extract()
|
||||
>>> d.extract()
|
||||
ExtractResult(subdomain='www', domain='example', suffix='com')
|
||||
|
||||
:return: 导出结果
|
||||
@@ -50,9 +50,9 @@ class Domain(object):
|
||||
"""
|
||||
获取注册域名
|
||||
|
||||
>>>d = Domain('www.example.com')
|
||||
>>> d = Domain('www.example.com')
|
||||
<domain.Domain object>
|
||||
>>>d.registered()
|
||||
>>> d.registered()
|
||||
example.com
|
||||
|
||||
:return: 注册域名
|
||||
|
||||
+37
-13
@@ -78,10 +78,45 @@ async def fetch(session, url, semaphore):
|
||||
return resp, text
|
||||
|
||||
|
||||
def get_title(markup):
|
||||
"""
|
||||
获取标题
|
||||
|
||||
:param markup: html标签
|
||||
:return: 标题
|
||||
"""
|
||||
soup = BeautifulSoup(markup, 'lxml')
|
||||
|
||||
title = soup.title
|
||||
if title:
|
||||
return title.text.strip()
|
||||
|
||||
h1 = soup.h1
|
||||
if h1:
|
||||
return h1.text.strip()
|
||||
|
||||
h2 = soup.h2
|
||||
if h2:
|
||||
return h2.text.strip()
|
||||
|
||||
desc = soup.find('meta', attrs={'name': 'description'})
|
||||
if desc:
|
||||
return desc['content'].strip()
|
||||
|
||||
word = soup.find('meta', attrs={'name': 'keywords'})
|
||||
if word:
|
||||
return word['content'].strip()
|
||||
|
||||
if len(markup) <= 200:
|
||||
return markup.strip()
|
||||
|
||||
return soup.text.strip()
|
||||
|
||||
|
||||
def request_callback(future, index, datas):
|
||||
try:
|
||||
result = future.result()
|
||||
except Exception as e:
|
||||
except BaseException as e:
|
||||
logger.log('DEBUG', e.args)
|
||||
datas[index]['reason'] = str(e.args)
|
||||
datas[index]['valid'] = 0
|
||||
@@ -98,18 +133,7 @@ def request_callback(future, index, datas):
|
||||
'Via': headers.get('Via'),
|
||||
'X-Powered-By': headers.get('X-Powered-By')})
|
||||
datas[index]['banner'] = banner
|
||||
soup = BeautifulSoup(text, 'lxml')
|
||||
title = soup.title
|
||||
desc = soup.find('meta', attrs={'name': 'description'})
|
||||
head = soup.head
|
||||
if title:
|
||||
datas[index]['title'] = title.text.strip()
|
||||
elif desc:
|
||||
datas[index]['title'] = desc['content'].strip()
|
||||
elif head:
|
||||
datas[index]['title'] = head.text.strip()
|
||||
elif len(text) <= 200:
|
||||
datas[index]['title'] = text.strip()
|
||||
datas[index]['title'] = get_title(text)
|
||||
|
||||
|
||||
async def bulk_get_request(datas, port):
|
||||
|
||||
@@ -51,12 +51,20 @@ async def aiodns_query_a(hostname, semaphore=None):
|
||||
"""
|
||||
if semaphore is None:
|
||||
resolver = aiodns_resolver()
|
||||
answers = await resolver.query(hostname, 'A')
|
||||
try:
|
||||
answers = await resolver.query(hostname, 'A')
|
||||
except BaseException as e:
|
||||
logger.log('DEBUG', e.args)
|
||||
answers = None
|
||||
return hostname, answers
|
||||
else:
|
||||
async with semaphore:
|
||||
resolver = aiodns_resolver()
|
||||
answers = await resolver.query(hostname, 'A')
|
||||
try:
|
||||
answers = await resolver.query(hostname, 'A')
|
||||
except BaseException as e:
|
||||
logger.log('DEBUG', e.args)
|
||||
answers = None
|
||||
return hostname, answers
|
||||
|
||||
|
||||
@@ -69,7 +77,7 @@ def resolve_callback(future, index, datas):
|
||||
"""
|
||||
try:
|
||||
result = future.result()
|
||||
except Exception as e:
|
||||
except BaseException as e:
|
||||
datas[index]['ips'] = str(e.args)
|
||||
datas[index]['valid'] = 0
|
||||
else:
|
||||
|
||||
+14
-2
@@ -5,6 +5,8 @@ OneForAll配置
|
||||
import os
|
||||
import sys
|
||||
import pathlib
|
||||
|
||||
import requests
|
||||
from loguru import logger
|
||||
|
||||
# 路径设置
|
||||
@@ -53,8 +55,8 @@ proxy_partial_module = ['GoogleQuery', 'AskSearch', 'DuckDuckGoSearch',
|
||||
'ContentSecurityPolicy'] # 代理自定义的模块
|
||||
proxy_pool = [{'http': 'http://127.0.0.1:1080',
|
||||
'https': 'https://127.0.0.1:1080'}] # 代理池
|
||||
# proxy_pool = [{'http': 'socks5://127.0.0.1:10808',
|
||||
# 'https': 'socks5://127.0.0.1:10808'}] # 代理池
|
||||
# proxy_pool = [{'http': 'socks5h://127.0.0.1:10808',
|
||||
# 'https': 'socks5h://127.0.0.1:10808'}] # 代理池
|
||||
|
||||
|
||||
# 网络请求设置
|
||||
@@ -62,6 +64,7 @@ enable_fake_header = True # 启用伪造请求头
|
||||
request_delay = 1 # 请求时延
|
||||
request_timeout = 30 # 请求超时
|
||||
request_verify = True # 请求SSL验证
|
||||
requests.packages.urllib3.disable_warnings() # 禁用安全警告信息
|
||||
|
||||
# 搜索模块设置
|
||||
enable_recursive_search = False # 递归搜索子域
|
||||
@@ -169,9 +172,18 @@ dnsdb_api_key = ''
|
||||
# 免费的API有效期只有2天,到期之后可以再次生成,每天可以查询50次。
|
||||
ipv4info_api_key = ''
|
||||
|
||||
# https://github.com/360netlab/flint
|
||||
# passivedns_api_addr默认空使用http://api.passivedns.cn
|
||||
# passivedns_api_token可为空
|
||||
passivedns_api_addr = ''
|
||||
passivedns_api_token = ''
|
||||
|
||||
# Github Token可以访问https://github.com/settings/tokens生成,user为Github用户名
|
||||
github_api_user = ''
|
||||
github_api_token = ''
|
||||
# github子域收集模块使用
|
||||
github_email = ''
|
||||
github_password = ''
|
||||
|
||||
subdomains_common = {'i', 'w', 'm', 'en', 'us', 'zh', 'w3', 'app', 'bbs',
|
||||
'web', 'www', 'job', 'docs', 'news', 'blog', 'data',
|
||||
|
||||
@@ -13,7 +13,7 @@ from common import utils
|
||||
from common.database import Database
|
||||
|
||||
|
||||
def export(table, db=None, valid=None, dpath=None, format='xls', show=False):
|
||||
def export(table, db=None, valid=None, dpath=None, format='csv', show=False):
|
||||
"""
|
||||
OneForAll数据库导出模块
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import time
|
||||
import cloudscraper
|
||||
from common.query import Query
|
||||
from config import logger
|
||||
|
||||
|
||||
class BufferOver(Query):
|
||||
@@ -8,20 +10,26 @@ class BufferOver(Query):
|
||||
self.domain = self.register(domain)
|
||||
self.module = 'Dataset'
|
||||
self.source = 'BufferOverQuery'
|
||||
self.addr = 'https://dns.bufferover.run/dns'
|
||||
self.addr = 'https://dns.bufferover.run/dns?q='
|
||||
|
||||
def query(self):
|
||||
"""
|
||||
向接口查询子域并做子域匹配
|
||||
"""
|
||||
time.sleep(self.delay)
|
||||
self.header = self.get_header()
|
||||
self.proxy = self.get_proxy(self.source)
|
||||
params = {'q': self.domain}
|
||||
resp = self.get(self.addr, params)
|
||||
# 绕过cloudFlare验证
|
||||
scraper = cloudscraper.create_scraper()
|
||||
scraper.interpreter = 'js2py'
|
||||
scraper.proxies = self.get_proxy(self.source)
|
||||
url = self.addr + self.domain
|
||||
try:
|
||||
resp = scraper.get(url, timeout=self.timeout)
|
||||
except Exception as e:
|
||||
logger.log('ERROR', e.args)
|
||||
return
|
||||
if not resp:
|
||||
return
|
||||
subdomains = self.match(self.domain, resp.text)
|
||||
subdomains = self.match(self.domain, str(resp.json()))
|
||||
# 合并搜索子域名搜索结果
|
||||
self.subdomains = self.subdomains.union(subdomains)
|
||||
|
||||
|
||||
@@ -25,10 +25,9 @@ class DNSdbAPI(Query):
|
||||
resp = self.get(url)
|
||||
if not resp:
|
||||
return
|
||||
if resp.status_code == 200:
|
||||
subdomains = utils.match_subdomain(self.domain, resp.text)
|
||||
# 合并搜索子域名搜索结果
|
||||
self.subdomains = self.subdomains.union(subdomains)
|
||||
subdomains = utils.match_subdomain(self.domain, resp.text)
|
||||
# 合并搜索子域名搜索结果
|
||||
self.subdomains = self.subdomains.union(subdomains)
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import time
|
||||
import config
|
||||
from common.query import Query
|
||||
|
||||
|
||||
class PassiveDnsAPI(Query):
|
||||
def __init__(self, domain):
|
||||
Query.__init__(self)
|
||||
self.domain = self.register(domain)
|
||||
self.module = 'Dataset'
|
||||
self.source = 'PassiveDnsQuery'
|
||||
self.addr = config.passivedns_api_addr or 'http://api.passivedns.cn'
|
||||
self.token = config.passivedns_api_token
|
||||
|
||||
def query(self):
|
||||
"""
|
||||
向接口查询子域并做子域匹配
|
||||
"""
|
||||
time.sleep(self.delay)
|
||||
self.header = self.get_header()
|
||||
self.header.update({'X-AuthToken': self.token})
|
||||
self.proxy = self.get_proxy(self.source)
|
||||
url = self.addr + '/flint/rrset/*.' + self.domain
|
||||
resp = self.get(url)
|
||||
if not resp:
|
||||
return
|
||||
subdomains = self.match(self.domain, str(resp.json()))
|
||||
# 合并搜索子域名搜索结果
|
||||
self.subdomains = self.subdomains.union(subdomains)
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
类执行入口
|
||||
"""
|
||||
if not self.check(self.addr):
|
||||
return
|
||||
self.begin()
|
||||
self.query()
|
||||
self.finish()
|
||||
self.save_json()
|
||||
self.gen_result()
|
||||
self.save_db()
|
||||
|
||||
|
||||
def do(domain): # 统一入口名字 方便多线程调用
|
||||
"""
|
||||
类统一调用入口
|
||||
|
||||
:param str domain: 域名
|
||||
"""
|
||||
query = PassiveDnsAPI(domain)
|
||||
query.run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
do('example.com')
|
||||
@@ -22,7 +22,7 @@ class FoFa(Search):
|
||||
发送搜索请求并做子域匹配
|
||||
"""
|
||||
self.page_num = 1
|
||||
subdomain_encode = f'subdomain={self.domain}'.encode('utf-8')
|
||||
subdomain_encode = f'domain={self.domain}'.encode('utf-8')
|
||||
query_data = base64.b64encode(subdomain_encode)
|
||||
while True:
|
||||
time.sleep(self.delay)
|
||||
@@ -31,14 +31,19 @@ class FoFa(Search):
|
||||
query = {'email': self.email,
|
||||
'key': self.key,
|
||||
'qbase64': query_data,
|
||||
'page': self.page_num}
|
||||
'page': self.page_num,
|
||||
'size': 10000}
|
||||
resp = self.get(self.addr, query)
|
||||
if not resp:
|
||||
return
|
||||
subdomains = self.match(self.domain, resp.text)
|
||||
resp_json = resp.json()
|
||||
subdomains = self.match(self.domain, str(resp_json))
|
||||
if not subdomains: # 搜索没有发现子域名则停止搜索
|
||||
break
|
||||
self.subdomains = self.subdomains.union(subdomains)
|
||||
size = resp_json.get('size')
|
||||
if size < 10000:
|
||||
break
|
||||
self.page_num += 1
|
||||
|
||||
def run(self):
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
import re
|
||||
import time
|
||||
import requests
|
||||
import config
|
||||
from bs4 import BeautifulSoup
|
||||
from common.search import Search
|
||||
from config import logger
|
||||
|
||||
|
||||
class Github(Search):
|
||||
def __init__(self, domain):
|
||||
Search.__init__(self)
|
||||
self.source = 'GithubSearch'
|
||||
self.module = 'Search'
|
||||
self.addr = 'https://github.com/search'
|
||||
self.domain = self.register(domain)
|
||||
self.header = self.get_header()
|
||||
self.session = requests.Session()
|
||||
self.login_url = 'https://github.com/login'
|
||||
self.post_url = 'https://github.com/session'
|
||||
self.email = config.github_email
|
||||
self.password = config.github_password
|
||||
|
||||
def login_github(self):
|
||||
"""
|
||||
登录github
|
||||
|
||||
:return: 登录失败返回False 成功返回True
|
||||
"""
|
||||
token = self.get_token()
|
||||
if token is None:
|
||||
logger.log('ERROR', f'{self.source}模块获取token失败')
|
||||
return False
|
||||
post_data = {
|
||||
'commit': 'Sign in',
|
||||
'utf8': '✓',
|
||||
'authenticity_token': token,
|
||||
'login': self.email,
|
||||
'password': self.password
|
||||
}
|
||||
resp = self.session.post(self.post_url, data=post_data)
|
||||
if resp.status_code != 200:
|
||||
return False
|
||||
match = re.search(r'"user-login" content="(.*?)"', resp.text)
|
||||
if match:
|
||||
return True
|
||||
|
||||
def get_token(self):
|
||||
"""
|
||||
获取github登录token
|
||||
|
||||
:return: 获取失败返回None,成功返回token
|
||||
"""
|
||||
resp = self.session.get(self.login_url)
|
||||
if resp.status_code != 200:
|
||||
return None
|
||||
match = re.search(
|
||||
r'name="authenticity_token" value="(.*?)"', resp.text)
|
||||
if not match:
|
||||
return None
|
||||
return match.group(1)
|
||||
|
||||
def search(self, full_search=True):
|
||||
"""
|
||||
向接口查询子域并做子域匹配
|
||||
"""
|
||||
self.session.headers = self.get_header()
|
||||
self.session.proxies = self.get_proxy(self.source)
|
||||
self.session.verify = self.verify
|
||||
if not self.login_github():
|
||||
logger.log('ERROR', f'{self.session}模块登录失败')
|
||||
return
|
||||
page_num = 1
|
||||
while True:
|
||||
time.sleep(self.delay)
|
||||
params = {'p': page_num, 'q': f'"{self.domain}"', 'type': 'Code'}
|
||||
resp = self.session.get(self.addr, params=params)
|
||||
if resp.status_code != 200:
|
||||
logger.log('ERROR', f'{self.session}模块搜索出错')
|
||||
break
|
||||
soup = BeautifulSoup(resp.text, 'lxml')
|
||||
subdomains = self.match(self.domain, soup.text)
|
||||
print(subdomains)
|
||||
self.subdomains = self.subdomains.union(subdomains)
|
||||
if not subdomains:
|
||||
break
|
||||
if not full_search:
|
||||
# 搜索中发现搜索出的结果有完全重复的结果就停止搜索
|
||||
if subdomains.issubset(self.subdomains):
|
||||
break
|
||||
if 'class="next_page disabled"' in resp.text:
|
||||
break
|
||||
if page_num > 100:
|
||||
break
|
||||
page_num += 1
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
类执行入口
|
||||
"""
|
||||
if not self.check(self.email, self.password):
|
||||
return
|
||||
self.begin()
|
||||
self.search()
|
||||
self.finish()
|
||||
self.save_json()
|
||||
self.gen_result()
|
||||
self.save_db()
|
||||
|
||||
|
||||
def do(domain): # 统一入口名字 方便多线程调用
|
||||
"""
|
||||
类统一调用入口
|
||||
|
||||
:param str domain: 域名
|
||||
"""
|
||||
query = Github(domain)
|
||||
query.run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
do('mi.com')
|
||||
@@ -28,7 +28,7 @@ blue = '\033[01;34m'
|
||||
red = '\033[1;31m'
|
||||
end = '\033[0m'
|
||||
|
||||
version = white + '{' + red + 'v0.0.5#dev' + white + '}'
|
||||
version = white + '{' + red + 'v0.0.6#dev' + white + '}'
|
||||
|
||||
banner = f"""{yellow}
|
||||
___ _ _
|
||||
@@ -42,7 +42,7 @@ class OneForAll(object):
|
||||
"""
|
||||
OneForAll是一款功能强大的子域收集工具
|
||||
|
||||
Version: 0.0.5
|
||||
Version: 0.0.6
|
||||
Project: https://git.io/fjHT1
|
||||
|
||||
Example:
|
||||
@@ -68,11 +68,11 @@ class OneForAll(object):
|
||||
:param bool verify: 验证子域有效性(默认True)
|
||||
:param str port: 请求验证的端口范围(默认medium)
|
||||
:param int valid: 导出子域的有效性(默认1)
|
||||
:param str format: 导出格式(默认xls)
|
||||
:param str format: 导出格式(默认csv)
|
||||
:param bool show: 终端显示导出数据(默认False)
|
||||
"""
|
||||
def __init__(self, target, brute=None, verify=None, port='medium', valid=1,
|
||||
format='xls', takeover=True, show=False):
|
||||
format='csv', takeover=True, show=False):
|
||||
self.target = target
|
||||
self.port = port
|
||||
self.domains = set()
|
||||
|
||||
+35
-32
@@ -60,10 +60,10 @@ class Takeover(Module):
|
||||
|
||||
:param str target: 单个子域或者每行一个子域的文件路径(必需参数)
|
||||
:param int thread: 线程数(默认100)
|
||||
:param str format: 导出格式(默认xls)
|
||||
:param str format: 导出格式(默认csv)
|
||||
:param str dpath: 导出目录(默认None)
|
||||
"""
|
||||
def __init__(self, target, thread=100, dpath=None, format='xls'):
|
||||
def __init__(self, target, thread=100, dpath=None, format='csv'):
|
||||
Module.__init__(self)
|
||||
self.subdomains = set()
|
||||
self.module = 'Check'
|
||||
@@ -74,7 +74,6 @@ class Takeover(Module):
|
||||
self.format = format
|
||||
self.fingerprints = None
|
||||
self.subdomainq = Queue()
|
||||
self.bar = tqdm()
|
||||
self.cnames = list()
|
||||
self.results = Dataset()
|
||||
|
||||
@@ -99,26 +98,37 @@ class Takeover(Module):
|
||||
self.results.append([subdomain, cname])
|
||||
break
|
||||
|
||||
def worker(self, subdomain):
|
||||
cname = get_cname(subdomain)
|
||||
if cname is None:
|
||||
return
|
||||
maindomain = get_maindomain(cname)
|
||||
for fingerprint in self.fingerprints:
|
||||
cnames = fingerprint.get('cname')
|
||||
if maindomain not in cnames:
|
||||
continue
|
||||
responses = fingerprint.get('response')
|
||||
self.compare(subdomain, cname, responses)
|
||||
|
||||
def check(self):
|
||||
while not self.subdomainq.empty(): # 保证域名队列遍历结束后能退出线程
|
||||
subdomain = self.subdomainq.get() # 从队列中获取域名
|
||||
cname = get_cname(subdomain)
|
||||
maindomain = get_maindomain(cname)
|
||||
if cname is None:
|
||||
continue
|
||||
for fingerprint in self.fingerprints:
|
||||
cnames = fingerprint.get('cname')
|
||||
if maindomain not in cnames:
|
||||
continue
|
||||
responses = fingerprint.get('response')
|
||||
self.compare(subdomain, cname, responses)
|
||||
self.worker(subdomain)
|
||||
self.subdomainq.task_done()
|
||||
|
||||
def progress(self):
|
||||
while not self.subdomainq.empty():
|
||||
done = self.bar.total - self.subdomainq.qsize()
|
||||
self.bar.n = done
|
||||
self.bar.update()
|
||||
self.bar.close()
|
||||
# 设置进度
|
||||
bar = tqdm()
|
||||
bar.total = len(self.subdomains)
|
||||
bar.desc = 'Progress'
|
||||
bar.ncols = True
|
||||
while True:
|
||||
done = bar.total - self.subdomainq.qsize()
|
||||
bar.n = done
|
||||
bar.update()
|
||||
if done == bar.total: # 完成队列中所有子域的检查退出
|
||||
break
|
||||
bar.close()
|
||||
|
||||
def run(self):
|
||||
start = time.time()
|
||||
@@ -133,22 +143,15 @@ class Takeover(Module):
|
||||
# 创建待检查的子域队列
|
||||
for domain in self.subdomains:
|
||||
self.subdomainq.put(domain)
|
||||
# 设置进度
|
||||
self.bar.total = self.subdomainq.qsize()
|
||||
self.bar.desc = 'Progress'
|
||||
self.bar.ncols = True
|
||||
# 进度线程
|
||||
threads = []
|
||||
thread = Thread(target=self.progress, daemon=True)
|
||||
thread.start()
|
||||
threads.append(thread)
|
||||
# 检查线程
|
||||
for _ in range(self.thread):
|
||||
thread = Thread(target=self.check, daemon=True)
|
||||
thread.start()
|
||||
threads.append(thread)
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
check_thread = Thread(target=self.check, daemon=True)
|
||||
check_thread.start()
|
||||
# 进度线程
|
||||
progress_thread = Thread(target=self.progress, daemon=True)
|
||||
progress_thread.start()
|
||||
|
||||
self.subdomainq.join()
|
||||
self.save()
|
||||
else:
|
||||
logger.log('FATAL', f'获取域名失败')
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user