diff --git a/README.en.md b/README.en.md index 9dffe73..878ca72 100644 --- a/README.en.md +++ b/README.en.md @@ -1,196 +1,86 @@ -# :rooster:0x00 Preface +![image-20220703203021188](images/image-20220703203021188.png) -![image-20220529132925098](images/image-20220529132925098.png) - -> March 7, 2022 -> -> I think the documentation is not very clear, wait for the time to update the full documentation of the use of tutorials -> March 8, 2022 -> -> May 29, 2022 -> -> 1. updated the aws storage bucket detection feature -> -> 2. feel that the update is a bit slow, this is a busy time, in fact, the new local version is written, has not been push - -**Using tutorial**: [Using tutorial](使用教程.md) - -**Language** - -English README: [English](README.en.md) - -I want to write a storage bucket utilization, first draw a pie for myself - -+ Aliyun Cloud (Aliyun Cloud Oss) -+ Tencent Cloud COS -+ Huawei Cloud (HuaWei Cloud OBS) -+ AWS (Amazon S3 Bucket) -+ Azure (Azure Blob) -+ GCP (Google Cloud Bucket) - -I don't even think about the name of the tool, I believe the big guys will know when they see the project name... King of machine flip - -If you think it works fine, you can raise an issue to give the tool a name? :sos: - -:waning_crescent_moon:**painting pie progress** - -1, Ali cloud storage bucket use - -Not too good with Git, code writing also sucks, there are bugs directly mention Issue can (as if I may not even use issue to understand) - -> Good thing the second master recommended to me GitHub Desktop second master YYDS - -2, AWS storage bucket use - -# :pill:0x01 dependency - -+ pip3 install oss2 -+ pip3 install colorlog -+ pip3 install argparse -+ pip3 install boto3 - -# :gun:0x02 Usage +# :rooster:Tutorial ```bash git clone https://github.com/UzJu/Cloud-Bucket-Leak-Detection-Tools.git +cd Cloud-Bucket-Leak-Detection-Tools/ +pip3 install -r requirements.txt python3 main.py -h ``` -Then write your own Aliyun AK in config/conf.py, the role is as follows +![image-20220716140707903](images/image-20220716140707903.png) -1, if you can hijack, will use the AK to create a storage bucket of the same name +You need to configure your corresponding cloud vendor AK in the `config/conf.py` file before using it. -2, used to verify the legitimate user +![image-20220716140934866](images/image-20220716140934866.png) -![image-20220304184757595](images/UzJuMarkDownImageimage-20220304184757595.png) +## 1、Ariyun storage bucket -## 1. When storage bucket Policy permission is available +### 1.1, single storage bucket detection -![images/20220304185015693](images/UzJuMarkDownImageimage-20220304185015693.png) +```bash +python3 main.py -aliyun [BucketURL] +``` -## 2. When the storage bucket does not exist (automatically created and hijacked) +![image-20220716141132931](images/image-20220716141132931.png) -![image](images/156925718-9a3dc236-0ef6-4afa-8d26-a2946fe876b2.png) +### 1.2. Automatic bucket hijacking -## 3、Batch detection of storage buckets +Automatically hijack a bucket when it is detected as not existing -New detection function of batch storage bucket, recommend fofa to export all assets with one click +![image-20220703202339058](images/image-20220703202339058.png) -**fofa** +### 1.3. Bulk bucket address detection ```bash +# fofa syntax domain="aliyuncs.com" -server="AliyunOSS" domain="aliyuncs.com" #This syntax is not recommended +server="AliyunOSS" domain="aliyuncs.com" ``` ```bash -python3 main.py -f aws/aliyun filepath - -# For example -python3 main.py -f aws . /url.tx\\\\\\\`````````````````````````````````````````````````````````````````````````` +# Use -faliyun +python3 main.py -faliyun url.txt ``` -Then just wait, the scan results will be in the results directory with the date of the day as the filename - -![image](images/156925744-3c012b86-6449-4cf1-a790-b2c1282f76bd.png) - -![image](images/156925758-36a8fcba-8bc8-4d1a-8863-d8110dbe0b71.png) - -Only buckets that have permission to operate will be saved -![image](images/156925766-15d415d3-d573-4b54-ab0f-5c79bc1966ad.png) - -Input the storage bucket address to detect automatically, the function is as follows - -+ 1. detect whether the current bucket can be hijacked - + If it can be hijacked, automatically create a bucket with the same name on the AK account written in the config and open all permissions -+ 2. detect whether the current bucket can list Object -+ 3. Check if the current bucket can get ACL -+ 4、Check if the current bucket can get Policy policy table -+ 5、Detect whether the bucket can upload Objects -+ 6、Batch detection function - -## 4、Domain name detection function - -Many storage buckets have resolved the domain name, the new judgment of the domain name CNAME, and then take the CNAME to detect - -** can now directly import a large number of domain name assets for detection, will automatically determine the CNAME of the domain name ** - -![image-20220307231827585](images/UzJuMarkDownImageimage-20220307231827585.png) +![image-20220716141356518](images/image-20220716141356518.png) -# 0x03 Ali cloud storage bucket utilization - -### 1、Implementation ideas - -First implement the `OssBucketCheckFromSDK` class - -+ AliyunOssBucketDoesBucketExist - - + AliyunOssBucketDoesBucketExist is used to determine whether the current bucket exists, first if the bucket exists then return a True, continue with the following process, if the bucket does not exist, then call the OssBucketExploitFromSDK class, create the bucket, and set ACL permissions, upload access policy, then upload a file for verification, if the bucket exists at this time or AccessDenied, continue with the following process - -+ AliyunOssGetBucketObjectList - - + determine if the contents of the bucket can be traversed, and if so, the first 3 contents will be selected for traversal and displayed - - > If you want to iterate through more content, you can check the AliyunOssGetBucketObjectList method in aliyunOss.py - -+ AliyunOssGetBucketAcl - - + determine if the current Bucket's ACL can be accessed, if so, return the current Bucket's ACL, if not, continue with the following Check process - -+ AliyunOssGetBucketPolicy - - + Determine if the policy of the current Bucket can be accessed, if so, the ACL of the current Bucket will be returned, if not, continue with the following Check process - -+ AliyunOssGetBucketObject - - + Try to upload a file, whether it can be successfully uploaded - -# 0x04 Aws storage bucket utilization +## 2. Tencent cloud storage bucket ```bash -python3 main.py -aws xxxx +python3 main.py -tcloud [storage bucket address] ``` -![image-20220529094124272](images/image-20220529094124272.png) +![image-20220716141554856](images/image-20220716141554856.png) -# 0x05 Explanation of the results file after use +## 3. Huawei cloud storage bucket -You can see the problematic bucket in the results directory - -![image-20220529134339645](images/image-20220529134339645.png) - -1, ListObject means the contents of the bucket can be listed - -2、PutObject means that the bucket can upload any file - -3、NoSuchBucket means the bucket can be taken over - -4、GetBucketACL means you can get the ACL of the bucket - -5、GetBucketPolicy means you can get the policy configuration of the bucket - -# :older_man:0x040001 Update Log +```bash +python3 main.py -hcloud [storage bucket address] +``` -**March 6, 2022** +![image-20220716141948046](images/image-20220716141948046.png) -+ Add batch scan function -+ Fix the Fake_UserAgent error reporting problem +## 4. AWS storage bucket -> actually just delete this library, don't use it ^ ^ +```bash +python3 main.py -aws [storage bucket address] +``` -**March 7, 2022** +![image-20220716142431142](images/image-20220716142431142.png)images/image-20220716142431142.png) -+ Added domain detection +## 5. Scan results saving -**May 29, 2022** +The scan results will be stored in the `results` directory -- Added AWS storage bucket scan +![image-20220716142617997](images/image-20220716142617997.png) -# :cop:0xffffffff Disclaimer +![image-20220716142641883](images/image-20220716142641883.png) -Disclaimers +# :cop:0xFFFFFFFF Disclaimer -1、This tool is for academic exchange only, it is forbidden to use the tool to do illegal things +1、This tool is only for academic exchange, it is forbidden to use the tool to do illegal things 2, just writing for fun @@ -198,8 +88,13 @@ Disclaimers > If you have a better suggestion or make a friend -![image](images/157070417-dbb7886f-1bb8-412f-a30b-0f85bc8ffa10.png) +image + +4、Blog: UzzJu.com +5、Public + +![image-20220716143619529](images/image-20220716143619529.png) # Curve chart -[![Stargazers over time](https://starchart.cc/UzJu/Cloud-Bucket-Leak-Detection-Tools.svg)](https://starchart.cc/UzJu/Cloud-Bucket-Leak-Detection-Tools) \ No newline at end of file +[![Stargazers over time](images/Cloud-Bucket-Leak-Detection-Tools.svg)](https://starchart.cc/UzJu/Cloud-Bucket-Leak-Detection-Tools) \ No newline at end of file diff --git a/README.md b/README.md index 7ed1c46..29a2a91 100644 --- a/README.md +++ b/README.md @@ -1,162 +1,86 @@ -# :rooster:0x00 前言 - ![image-20220703203021188](images/image-20220703203021188.png) -**使用教程**: [使用教程](使用教程.md) - -**语言/Language** - -English README: [English](README.en.md) - -# :pill:0x01 依赖 - -```bash -pip3 install -r requirements.txt -``` - -# :gun:0x02 使用方法 +# :rooster:使用教程 ```bash git clone https://github.com/UzJu/Cloud-Bucket-Leak-Detection-Tools.git +cd Cloud-Bucket-Leak-Detection-Tools/ +# 安装依赖 建议使用Python3.8以上的版本 我的版本: Python 3.9.13 (main, May 24 2022, 21:28:31) +pip3 install huaweicloud-sdk-python +pip3 install -r requirements.txt python3 main.py -h ``` -随后在config/conf.py中写入自己的AK,作用如下 +![image-20220716140707903](images/image-20220716140707903.png) -1、如果可以劫持,会用该AK创建同名的存储桶 +使用之前需要在`config/conf.py`文件配置自己对应的云厂商AK -2、用来验证合法用户 +![image-20220716140934866](images/image-20220716140934866.png) -![image-20220703201835328](images/image-20220703201835328.png) +## 1、阿里云存储桶 -## 1、当存储桶Policy权限可获取时 +### 1.1、单个存储桶检测 -![image-20220703202049560](images/image-20220703202049560.png) +```bash +python3 main.py -aliyun [存储桶URL] +``` -## 2、当存储桶不存在时(自动创建并劫持) +![image-20220716141132931](images/image-20220716141132931.png) -![image-20220703202339058](images/image-20220703202339058.png) +### 1.2、自动存储桶劫持 -## 3、批量检测存储桶 +当如果检测存储桶不存在时会自动劫持该存储桶 -新增批量存储桶的检测功能,推荐fofa一键导出所有资产 +![image-20220703202339058](images/image-20220703202339058.png) -**fofa** +### 1.3、批量存储桶地址检测 ```bash +# fofa语法 domain="aliyuncs.com" -server="AliyunOSS"domain="aliyuncs.com" #不推荐该语法 +server="AliyunOSS"domain="aliyuncs.com" ``` ```bash - python3 main.py -faliyun url.txt +# 使用-faliyun +python3 main.py -faliyun url.txt ``` -随后等待即可,扫描结果会在results目录下,文件名为当天的日期 - -![image-20220703202518187](images/image-20220703202518187.png) - -随后会将结果保存至csv -![image-20220703202635171](images/image-20220703202635171.png) - -输入存储桶地址即可自动检测,功能如下 - -+ 1、检测当前存储桶是否可劫持 - + 如果可劫持,自动在config中写入的AK账号上创建同命名的存储桶并开放所有权限 -+ 2、检测当前存储桶是否可列出Object -+ 3、检测当前存储桶是否可获取ACL -+ 4、检测当前存储桶是否可获取Policy策略表 -+ 5、检测存储桶是否可上传Object -+ 6、批量检测功能 - -## 4、域名检测功能(v0.3.0暂未支持) - -很多存储桶都解析了域名,新增判断域名的CNAME,然后取CNAME来进行检测 - -**现在可以直接导入大量域名资产来进行检测,会自动判断域名的CNAME** - -![image-20220307231827585](images/UzJuMarkDownImageimage-20220307231827585.png) - -# 0x03 阿里云存储桶利用 - -### 1、实现思路 - -首先实现了`OssBucketCheckFromSDK`类 - -+ AliyunOssBucketDoesBucketExist +![image-20220716141356518](images/image-20220716141356518.png) - + 用来判断当前存储桶是否存在,首先如果存储桶存在那么就返回一个True,继续走下面的流程,如果存储桶不存在,那么就调用OssBucketExploitFromSDK类,创建存储桶,并且设置ACL权限,上传访问策略,随后上传一个文件进行验证,如果存储桶此时存在或者为AccessDenied,继续走下面的流程 - -+ AliyunOssGetBucketObjectList - - + 判断是否可以遍历存储桶中的内容,如果可以,则会选择前3个内容进行遍历并显示 - - > 如果想遍历更多的内容,可以查看aliyunOss.py中的AliyunOssGetBucketObjectList方法 - -+ AliyunOssGetBucketAcl - - + 判断能否访问当前Bucket的ACL,如果可以的话,就返回当前Bucket的ACL,如果不可以就继续走下面的Check流程 - -+ AliyunOssGetBucketPolicy - - + 判断能否访问当前Bucket的Policy,如果可以的话,就会返回当前Bucket的ACL,如果不可以就继续走下面的Check - -+ AliyunOssGetBucketObject - - + 尝试上传一个文件,是否可以成功上传 - -# 0x04 Aws存储桶利用 +## 2、腾讯云存储桶 ```bash -python3 main.py -aws xxxx +python3 main.py -tcloud [存储桶地址] ``` -![image-20220529094124272](images/image-20220529094124272.png) - -# 0x05 利用后results文件解释 - -在results目录下可以看到存在问题的存储桶 - -![image-20220529134339645](images/image-20220529134339645.png) +![image-20220716141554856](images/image-20220716141554856.png) -1、ListObject 代表该存储桶的内容可以列出来 +## 3、华为云存储桶 -2、PutObject 代表该存储桶可以上传任意的文件 - -3、NoSuchBucket 代表该存储桶可以接管 - -4、GetBucketACL 代表可以获取该存储桶的ACL - -5、GetBucketPolicy 代表可以获取该存储桶的策略配置 - -# :older_man:0x040001 更新日志 - -**2022年3月6日** - -+ 新增批量扫描功能 -+ 修复Fake_UserAgent报错的问题 +```bash +python3 main.py -hcloud [存储桶地址] +``` -> 其实是直接把这个库删了,不用了^ ^ +![image-20220716141948046](images/image-20220716141948046.png) -**2022年3月7日** +## 4、AWS存储桶 -+ 新增域名检测 +```bash +python3 main.py -aws [存储桶地址] +``` -**2022年5月29日** +![image-20220716142431142](images/image-20220716142431142.png) -- 新增AWS存储桶扫描 +## 5、扫描结果保存 -**2022年7月3日** +扫描结果会存放在`results`目录下 -- 重构项目 - - aliyunoss模块 - - aws模块 - - main模块 - - 扫描模块 +![image-20220716142617997](images/image-20220716142617997.png) -# :cop:0xffffffff 免责声明 +![image-20220716142641883](images/image-20220716142641883.png) -免责声明 +# :cop:0xFFFFFFFF 免责声明 1、本工具只作为学术交流,禁止使用工具做违法的事情 @@ -166,9 +90,13 @@ python3 main.py -aws xxxx > 如果你有更好的建议或者交个朋友 -![image](images/157070417-dbb7886f-1bb8-412f-a30b-0f85bc8ffa10.png) +image -# 曲线图 +4、博客: UzzJu.com +5、公众号 + +![image-20220716143619529](images/image-20220716143619529.png) -[![Stargazers over time](https://starchart.cc/UzJu/Cloud-Bucket-Leak-Detection-Tools.svg)](https://starchart.cc/UzJu/Cloud-Bucket-Leak-Detection-Tools) +# 曲线图 +[![Stargazers over time](images/Cloud-Bucket-Leak-Detection-Tools.svg)](https://starchart.cc/UzJu/Cloud-Bucket-Leak-Detection-Tools) \ No newline at end of file diff --git a/UPDATE.md b/UPDATE.md deleted file mode 100644 index d3caa50..0000000 --- a/UPDATE.md +++ /dev/null @@ -1,17 +0,0 @@ -# 阿里云 -## **已完成** -1、GetObjectList ✅ -2、GetBucketPolicy ✅ -3、PutBucketPolicy ✅ -4、GetBucketAcl ✅ -5、PutBucketAcl ✅ -6、PutBucketObject✅ -7、批量检测✅ - -8、批量获取域名的CNAME来进行检测✅ - -## **待完成[画饼,反正画了也不一定写]** -1、存储桶名称爆破/Object爆破 - -> 不过感觉还是有点问题,感觉可以试试 - diff --git a/config/conf.py b/config/conf.py index 360e7b8..f62b83d 100644 --- a/config/conf.py +++ b/config/conf.py @@ -18,8 +18,15 @@ AWS_ACCESS_KEY = "" AWS_SECRET_KEY = "" +# tencent +tencent_cam_id = "" +tencent_cam_key = "" -version = "v.0.3.0" +# huawei +huawei_access_key_id = "" +huawei_access_key_key = "" + +version = "v.0.4.0" author = "UzJu" email = "UzJuer@163.com" github = "GitHub.com/UzJu" diff --git a/core/__init__.py b/core/__init__.py new file mode 100644 index 0000000..77bd5fc --- /dev/null +++ b/core/__init__.py @@ -0,0 +1,7 @@ +#!/usr/bin/python3.8.4 (python版本) +# -*- coding: utf-8 -*- +# @Author : UzJu@菜菜狗 +# @Email : UzJuer@163.com +# @Software: PyCharm +# @Time : 2022/7/15 14:25 +# @File : __init__.py.py diff --git a/core/aliyun/__init__.py b/core/aliyun/__init__.py new file mode 100644 index 0000000..90d82e7 --- /dev/null +++ b/core/aliyun/__init__.py @@ -0,0 +1,7 @@ +#!/usr/bin/python3.8.4 (python版本) +# -*- coding: utf-8 -*- +# @Author : UzJu@菜菜狗 +# @Email : UzJuer@163.com +# @Software: PyCharm +# @Time : 2022/7/15 14:24 +# @File : __init__.py.py diff --git a/core/aliyunOss.py b/core/aliyun/oss.py similarity index 99% rename from core/aliyunOss.py rename to core/aliyun/oss.py index 08c0ec6..50e91f1 100644 --- a/core/aliyunOss.py +++ b/core/aliyun/oss.py @@ -4,7 +4,7 @@ # @Email : UzJuer@163.com # @Software: PyCharm # @Time : 2022/7/2 14:22 -# @File : aliyunOss.py +# @File : oss.py import json import os from itertools import islice diff --git a/core/aws/__init__.py b/core/aws/__init__.py new file mode 100644 index 0000000..77bd5fc --- /dev/null +++ b/core/aws/__init__.py @@ -0,0 +1,7 @@ +#!/usr/bin/python3.8.4 (python版本) +# -*- coding: utf-8 -*- +# @Author : UzJu@菜菜狗 +# @Email : UzJuer@163.com +# @Software: PyCharm +# @Time : 2022/7/15 14:25 +# @File : __init__.py.py diff --git a/core/aws.py b/core/aws/aws.py similarity index 100% rename from core/aws.py rename to core/aws/aws.py diff --git a/core/huaweiyun/__init__.py b/core/huaweiyun/__init__.py new file mode 100644 index 0000000..77bd5fc --- /dev/null +++ b/core/huaweiyun/__init__.py @@ -0,0 +1,7 @@ +#!/usr/bin/python3.8.4 (python版本) +# -*- coding: utf-8 -*- +# @Author : UzJu@菜菜狗 +# @Email : UzJuer@163.com +# @Software: PyCharm +# @Time : 2022/7/15 14:25 +# @File : __init__.py.py diff --git a/core/huaweiyun/obs.py b/core/huaweiyun/obs.py new file mode 100644 index 0000000..5de8e22 --- /dev/null +++ b/core/huaweiyun/obs.py @@ -0,0 +1,55 @@ +#!/usr/bin/python3.8.4 (python版本) +# -*- coding: utf-8 -*- +# @Author : UzJu@菜菜狗 +# @Email : UzJuer@163.com +# @Software: PyCharm +# @Time : 2022/7/15 14:22 +# @File : obs.py + +from obs import ObsClient +from config import conf +from config.logs import logger + + +class HuaWeiCloud_OBS_Check: + def __init__(self, target, location): + self.target = target + self.client = ObsClient( + access_key_id=conf.huawei_access_key_id, + secret_access_key=conf.huawei_access_key_key, + server=f'https://obs.{location}.myhuaweicloud.com' + ) + + def ListObject(self): + try: + resp = self.client.listObjects(self.target, max_keys=3) + for content in resp.body.contents: + logger.log("INFOR", + f"ObjectKey: {content.key}, owner_id: {content.owner.owner_id}, owner_name: {content.owner.owner_name}") + return True + except Exception as e: + logger.log("ALERT", f"BucketName: {self.target}> ListObject权限不足") + logger.log("ERROR", f"BucketName: {self.target}> ListObject > {repr(e)}") + + def PutObject(self): + try: + resp = self.client.putFile(self.target, objectKey="UzJu.html", file_path="./config/UzJu.html") + if resp['status'] == 403: + logger.log("ALERT", f"BucketName: {self.target}> PutObject权限不足") + else: + logger.log("INFOR", f"BucketName: {self.target}> PutObject成功, 访问UzJu.html查看") + return True + except Exception as e: + logger.log("ERROR", repr(e)) + + def GetBucketACL(self): + try: + resp = self.client.getBucketAcl(self.target) + if resp['status'] == 200: + logger.log("INFOR", f"BucketName: {self.target}> GetBucketACL成功, {resp}") + return True + elif resp['status'] == 403: + logger.log("ALERT", f"BucketName: {self.target}> GetBucketACL权限不足") + except Exception as e: + logger.log("ERROR", repr(e)) + diff --git a/core/main.py b/core/main.py index 401ad10..a2f2c6a 100644 --- a/core/main.py +++ b/core/main.py @@ -7,25 +7,28 @@ # @File : main.py from config.logs import logger -from plugins.results import aliyun_save_file -from core import aliyunOss -from core import aws +from plugins.results import * import urllib.parse import prettytable as pt import multiprocessing +from core.aliyun import oss +from core.aws import aws +from core.tencent import cos +from core.huaweiyun import obs -def aliyun_file_scan(filename): + +def Aliyun_file_scan(filename): target_file = open(filename, mode='r', encoding='utf-8') p = multiprocessing.Pool(processes=3) for i in target_file.read().splitlines(): - p.apply_async(aliyun, args=(i,)) + p.apply_async(Aliyun_OSS, args=(i,)) p.close() p.join() p.terminate() -def aliyun(target): +def Aliyun_OSS(target): """ :desc: aliyun Bucket Scan function @@ -36,14 +39,23 @@ def aliyun(target): aliyun_print_table_header = pt.PrettyTable( ['Bucket', 'BucketHijack', 'GetBucketObjectList', 'PutBucketObject', 'GetBucketAcl', 'PutBucketAcl', 'GetBucketPolicy']) - aliyun_scan_results = {} + aliyun_scan_results = { + "BucketName": target, + "BucketDoesBucketExist": False, + "BucketHijack": False, + "GetBucketObjectList": False, + "PutBucketObject": False, + "GetBucketAcl": False, + "PutBucketAcl": False, + "GetBucketPolicy": False, + } get_domain = urllib.parse.urlparse(target).netloc if get_domain == "": get_target_list = target.split('.') - aliyunOss_Check_init = aliyunOss.Aliyun_Oss_Bucket_Check(target=get_target_list[0], - location=get_target_list[1]) - aliyunOss_Exploit_init = aliyunOss.Aliyun_Oss_Bucket_Exploit(target=get_target_list[0], - location=get_target_list[1]) + aliyunOss_Check_init = oss.Aliyun_Oss_Bucket_Check(target=get_target_list[0], + location=get_target_list[1]) + aliyunOss_Exploit_init = oss.Aliyun_Oss_Bucket_Exploit(target=get_target_list[0], + location=get_target_list[1]) if aliyunOss_Check_init.Aliyun_Oss_BucketDoesBucketExist(): logger.log("INFOR", f"{target}> 当前存储桶不存在, 尝试劫持存储桶") if aliyunOss_Exploit_init.Aliyun_Oss_CreateBucket_Exp(): @@ -53,45 +65,38 @@ def aliyun(target): aliyunOss_Exploit_init.Aliyun_Oss_PutBucketPolicy_Exp() aliyunOss_Exploit_init.Aliyun_Oss_GetBucketPolicy_Exp() aliyunOss_Exploit_init.Aliyun_Oss_PutBucketAcl_Exp() - aliyun_scan_results.update({"BucketDoesBucketExist": "true"}) else: - aliyun_scan_results.update({"BucketDoesBucketExist": "false"}) if aliyunOss_Check_init.Aliyun_Oss_GetBucketObject_List(): logger.log("INFOR", f"{target}> 存储桶对象可遍历") - aliyun_scan_results.update({"GetBucketObject": "true"}) + aliyun_scan_results['GetBucketObject'] = True else: logger.log("ALERT", f"{target}> 存储桶对象不可遍历") - aliyun_scan_results.update({"GetBucketObject": "false"}) if aliyunOss_Check_init.Aliyun_Oss_PutBucketObject(): logger.log("INFOR", f"{target}> 可未授权上传对象至存储桶(可导致覆盖已有对象)") - aliyun_scan_results.update({"PutBucketObject": "true"}) + aliyun_scan_results['PutBucketObject'] = True else: logger.log("ALERT", f"{target}> 不可未授权上传对象至存储桶") - aliyun_scan_results.update({"PutBucketObject": "false"}) if aliyunOss_Check_init.Aliyun_Oss_GetBucketAcl(): logger.log("INFOR", f"{target}> 可公开访问存储桶ACL策略") - aliyun_scan_results.update({"GetBucketAcl": "true"}) + aliyun_scan_results['GetBucketAcl'] = True else: logger.log("ALERT", f"{target}> 不可公开访问存储桶ACL策略") - aliyun_scan_results.update({"GetBucketAcl": "false"}) if aliyunOss_Check_init.Aliyun_Oss_PutBucketAcl(): logger.log("INFOR", f"{target}> 可上传覆盖存储桶ACL策略") - aliyun_scan_results.update({"PutBucketAcl": "true"}) + aliyun_scan_results['PutBucketAcl'] = True else: logger.log("ALERT", f"{target}> 不可上传覆盖存储桶ACL策略") - aliyun_scan_results.update({"PutBucketAcl": "false"}) results_policy = aliyunOss_Check_init.Aliyun_Oss_GetBucketPolicy() if results_policy: logger.log("INFOR", f"{target}> 可公开获取存储桶Policy策略组") logger.log("INFOR", f"{target}Policy> {results_policy}") - aliyun_scan_results.update({"GetBucketPolicy": "true"}) + aliyun_scan_results['GetBucketPolicy'] = True else: logger.log("ALERT", f"{target}> 不可公开获取存储桶Policy策略") - aliyun_scan_results.update({"GetBucketPolicy": "false"}) aliyun_print_table_header.add_row([target, aliyun_scan_results['BucketDoesBucketExist'], @@ -107,9 +112,83 @@ def aliyun(target): aliyun_scan_results['GetBucketAcl'], aliyun_scan_results['PutBucketAcl'], aliyun_scan_results['GetBucketPolicy']) - print(aliyun_print_table_header, "\n") + print(aliyun_print_table_header) + else: + Aliyun_OSS(get_domain) + + +def Tencent_Cloud_Cos(target): + tencent_cloud_print_table_header = pt.PrettyTable( + ['Bucket', 'ListObject', 'PutObject', 'GetBucketACL']) + tencent_cloud_results = { + "BucketName": target, + "ListObject": False, + "PutObject": False, + "GetBucketACL": False + } + get_domain = urllib.parse.urlparse(target).netloc + if get_domain == "": + if "cos" not in target: + logger.log("ALERT", f"当前{target}非COS存储桶地址") + return + logger.log("INFOR", f"开始扫描> {target}") + get_target_list = target.split(".") + tencent_check_init = cos.TenCent_Cloud_OBS_Check(target=get_target_list[0], + location=get_target_list[2]) + if tencent_check_init.ListObject(): + tencent_cloud_results['ListObject'] = True + if tencent_check_init.PutObject(): + tencent_cloud_results['PutObject'] = True + if tencent_check_init.GetBucketACL(): + tencent_cloud_results['GetBucketACL'] = True + else: + Tencent_Cloud_Cos(target) + tencent_cloud_print_table_header.add_row([target, + tencent_cloud_results['ListObject'], + tencent_cloud_results['PutObject'], + tencent_cloud_results['GetBucketACL']]) + tencent_save_file(target, + tencent_cloud_results['ListObject'], + tencent_cloud_results['PutObject'], + tencent_cloud_results['GetBucketACL']) + print(tencent_cloud_print_table_header) + + +def Huawei_Cloud_OBS(target): + huawei_cloud_print_table_header = pt.PrettyTable( + ['Bucket', 'ListObject', 'PutObject', 'GetBucketACL']) + huawei_cloud_results = { + "BucketName": target, + "ListObject": False, + "PutObject": False, + "GetBucketACL": False + } + get_domain = urllib.parse.urlparse(target).netloc + if get_domain == "": + if "obs" not in target: + logger.log("ALERT", f"当前{target}非OBS存储桶地址") + return + logger.log("INFOR", f"开始扫描> {target}") + get_target_list = target.split(".") + huaweiyun_check_init = obs.HuaWeiCloud_OBS_Check(target=get_target_list[0], + location=get_target_list[2]) + if huaweiyun_check_init.ListObject(): + huawei_cloud_results['ListObject'] = True + if huaweiyun_check_init.PutObject(): + huawei_cloud_results['PutObject'] = True + if huaweiyun_check_init.GetBucketACL(): + huawei_cloud_results['GetBucketACL'] = True else: - aliyun(get_domain) + Huawei_Cloud_OBS(target) + huawei_cloud_print_table_header.add_row([target, + huawei_cloud_results['ListObject'], + huawei_cloud_results['PutObject'], + huawei_cloud_results['GetBucketACL']]) + huawei_save_file(target, + huawei_cloud_results['ListObject'], + huawei_cloud_results['PutObject'], + huawei_cloud_results['GetBucketACL']) + print(huawei_cloud_print_table_header) def AmazoneS3(target): @@ -119,6 +198,14 @@ def AmazoneS3(target): :param target: bucket url :return: """ + aws_print_table_header = pt.PrettyTable( + ['Bucket', 'ListObject', 'PutObject', 'GetBucketACL']) + aws_results = { + "BucketName": target, + "ListObject": False, + "PutObject": False, + "GetBucketACL": False + } get_domain = urllib.parse.urlparse(target).netloc if get_domain == "": logger.log("INFOR", f"开始扫描> {target}") @@ -127,17 +214,29 @@ def AmazoneS3(target): location=get_target_list[1]) if aws_check_init.Check_Bucket_ListObject(): logger.log("INFOR", f"{target}> 存储桶对象可遍历") + aws_results['ListObject'] = True else: logger.log("ALERT", f"{target}> 存储桶对象不可遍历") if aws_check_init.Check_Bucket_PutObject(): logger.log("INFOR", f"{target}> 可未授权上传对象至存储桶(可覆盖存储桶已有对象)") + aws_results['PutObject'] = True else: logger.log("ALERT", f"{target}> 不可未授权上传对象至存储桶(可覆盖存储桶已有对象)") if aws_check_init.Check_Bucket_GetBucketAcl(): logger.log("INFOR", f"{target}> 存储桶ACL策略可公开获取") + aws_results['GetBucketACL'] = True else: logger.log("ALERT", f"{target}> 存储桶ACL策略不可公开") else: AmazoneS3(get_domain) + aws_print_table_header.add_row([target, + aws_results['ListObject'], + aws_results['PutObject'], + aws_results['GetBucketACL']]) + aws_save_file(target, + aws_results['ListObject'], + aws_results['PutObject'], + aws_results['GetBucketACL']) + print(aws_print_table_header) diff --git a/core/tencent/__init__.py b/core/tencent/__init__.py new file mode 100644 index 0000000..90d82e7 --- /dev/null +++ b/core/tencent/__init__.py @@ -0,0 +1,7 @@ +#!/usr/bin/python3.8.4 (python版本) +# -*- coding: utf-8 -*- +# @Author : UzJu@菜菜狗 +# @Email : UzJuer@163.com +# @Software: PyCharm +# @Time : 2022/7/15 14:24 +# @File : __init__.py.py diff --git a/core/tencent/cos.py b/core/tencent/cos.py new file mode 100644 index 0000000..9c33e81 --- /dev/null +++ b/core/tencent/cos.py @@ -0,0 +1,61 @@ +#!/usr/bin/python3.8.4 (python版本) +# -*- coding: utf-8 -*- +# @Author : UzJu@菜菜狗 +# @Email : UzJuer@163.com +# @Software: PyCharm +# @Time : 2022/7/15 11:58 +# @File : cos.py + +from qcloud_cos import CosConfig +from qcloud_cos import CosS3Client +from config import conf +from config.logs import logger + + +class TenCent_Cloud_OBS_Check: + def __init__(self, target, location): + self.target = target + config = CosConfig(Region=location, SecretId=conf.tencent_cam_id, SecretKey=conf.tencent_cam_key) + self.client = CosS3Client(config) + + def ListObject(self): + try: + resp = self.client.list_objects(Bucket=self.target) + if 'Contents' in resp: + for content in resp['Contents']: + logger.log("INFOR", f"ListObject> {content['Key']}") + return True + except Exception as e: + if "Access Denied." in repr(e): + logger.log("ALERT", f"{self.target}> ListObject权限不足") + else: + logger.log("ERROR", repr(e)) + return False + + def PutObject(self): + try: + self.client.upload_file(Bucket=self.target, + Key="index.html", + LocalFilePath="./config/UzJu.html", + ACL="public-read", + ContentType="text/html") + logger.log("INFOR", f"{self.target}> PutObject成功 访问index.html查看结果") + return True + except Exception as e: + if "Access Denied." in repr(e): + logger.log("ALERT", f"{self.target}> PutObject权限不足") + else: + logger.log("ERROR", repr(e)) + return False + + def GetBucketACL(self): + try: + resp = self.client.get_bucket_acl(Bucket=self.target) + logger.log("INFOR", f"{self.target}> GetBucketACL成功, 策略: {resp}") + return True + except Exception as e: + if "Access Denied." in repr(e): + logger.log("ALERT", f"{self.target}> GetBucketACL权限不足") + else: + logger.log("ERROR", repr(e)) + return False diff --git a/images/Cloud-Bucket-Leak-Detection-Tools.svg b/images/Cloud-Bucket-Leak-Detection-Tools.svg new file mode 100644 index 0000000..b100662 --- /dev/null +++ b/images/Cloud-Bucket-Leak-Detection-Tools.svg @@ -0,0 +1,572 @@ +\n2022-02-222022-03-122022-03-292022-04-162022-05-042022-05-222022-06-082022-06-262022-07-14Time069138207275344413482550Stargazers \ No newline at end of file diff --git a/images/image-20220703202549284.png b/images/image-20220703202549284.png new file mode 100644 index 0000000..29d0516 Binary files /dev/null and b/images/image-20220703202549284.png differ diff --git a/images/image-20220716140707903.png b/images/image-20220716140707903.png new file mode 100644 index 0000000..dea5f54 Binary files /dev/null and b/images/image-20220716140707903.png differ diff --git a/images/image-20220716140934866.png b/images/image-20220716140934866.png new file mode 100644 index 0000000..5f25eb2 Binary files /dev/null and b/images/image-20220716140934866.png differ diff --git a/images/image-20220716141132931.png b/images/image-20220716141132931.png new file mode 100644 index 0000000..6ebff15 Binary files /dev/null and b/images/image-20220716141132931.png differ diff --git a/images/image-20220716141356518.png b/images/image-20220716141356518.png new file mode 100644 index 0000000..c08c8ad Binary files /dev/null and b/images/image-20220716141356518.png differ diff --git a/images/image-20220716141554856.png b/images/image-20220716141554856.png new file mode 100644 index 0000000..ffd6d02 Binary files /dev/null and b/images/image-20220716141554856.png differ diff --git a/images/image-20220716141948046.png b/images/image-20220716141948046.png new file mode 100644 index 0000000..337f848 Binary files /dev/null and b/images/image-20220716141948046.png differ diff --git a/images/image-20220716142431142.png b/images/image-20220716142431142.png new file mode 100644 index 0000000..ff8e8f4 Binary files /dev/null and b/images/image-20220716142431142.png differ diff --git a/images/image-20220716142617997.png b/images/image-20220716142617997.png new file mode 100644 index 0000000..eeb7a38 Binary files /dev/null and b/images/image-20220716142617997.png differ diff --git a/images/image-20220716142641883.png b/images/image-20220716142641883.png new file mode 100644 index 0000000..076f324 Binary files /dev/null and b/images/image-20220716142641883.png differ diff --git a/images/image-20220716143619529.png b/images/image-20220716143619529.png new file mode 100644 index 0000000..0e67179 Binary files /dev/null and b/images/image-20220716143619529.png differ diff --git a/main.py b/main.py index 07d35ab..4e3bdc5 100644 --- a/main.py +++ b/main.py @@ -17,12 +17,18 @@ parser = argparse.ArgumentParser() parser.add_argument('-aliyun', dest='aliyun', help='python3 main.py -aliyun Bucketurl') parser.add_argument('-faliyun', dest='faliyun', help='python3 main.py -faliyun filename') + parser.add_argument('-tcloud', dest='tencent_cloud', help='python3 main.py -tcloud BucketUrl') + parser.add_argument('-hcloud', dest='huawei_cloud', help='python3 main.py -hcloud BucketUrl') parser.add_argument('-aws', dest='aws', help='python3 main.py -aws bucketurl') args = parser.parse_args() if args.aliyun: - main.aliyun(args.aliyun) + main.Aliyun_OSS(args.aliyun) elif args.faliyun: - main.aliyun_file_scan(args.faliyun) + main.Aliyun_file_scan(args.faliyun) + elif args.tencent_cloud: + main.Tencent_Cloud_Cos(args.tencent_cloud) + elif args.huawei_cloud: + main.Huawei_Cloud_OBS(args.huawei_cloud) elif args.aws: main.AmazoneS3(args.aws) diff --git a/plugins/results.py b/plugins/results.py index f722a96..cea1d75 100644 --- a/plugins/results.py +++ b/plugins/results.py @@ -12,9 +12,11 @@ from config.conf import NowTime -def aliyun_save_file(target, BucketHijack, GetBucketObjectList, PutBucketObject, GetBucketAcl, PutBucketAcl, GetBucketPolicy): - headers = ['Bucket', 'BucketHijack', 'GetBucketObjectList', 'PutBucketObject', 'GetBucketAcl', 'PutBucketAcl', 'GetBucketPolicy'] - filepath = f'{os.getcwd()}/results/{NowTime}.csv' +def aliyun_save_file(target, BucketHijack, GetBucketObjectList, PutBucketObject, GetBucketAcl, PutBucketAcl, + GetBucketPolicy): + headers = ['Bucket', 'BucketHijack', 'GetBucketObjectList', 'PutBucketObject', 'GetBucketAcl', 'PutBucketAcl', + 'GetBucketPolicy'] + filepath = f'{os.getcwd()}/results/aliyun_{NowTime}.csv' rows = [ [f"{target}", BucketHijack, GetBucketObjectList, PutBucketObject, GetBucketAcl, PutBucketAcl, GetBucketPolicy] ] @@ -28,3 +30,53 @@ def aliyun_save_file(target, BucketHijack, GetBucketObjectList, PutBucketObject, f_csv = csv.writer(f) f_csv.writerows(rows) + +def tencent_save_file(target, ListObject, PutObject, GetBucketACL): + headers = ['Bucket', 'ListObject', 'PutObject', 'GetBucketACL'] + filepath = f'{os.getcwd()}/results/tencentcloud_{NowTime}.csv' + rows = [ + [f"{target}", ListObject, PutObject, GetBucketACL] + ] + if not os.path.isfile(filepath): + with open(filepath, 'a+', newline='') as f: + f = csv.writer(f) + f.writerow(headers) + f.writerows(rows) + else: + with open(filepath, 'a+', newline='') as f: + f_csv = csv.writer(f) + f_csv.writerows(rows) + + +def huawei_save_file(target, ListObject, PutObject, GetBucketACL): + headers = ['Bucket', 'ListObject', 'PutObject', 'GetBucketACL'] + filepath = f'{os.getcwd()}/results/huaweicloud_{NowTime}.csv' + rows = [ + [f"{target}", ListObject, PutObject, GetBucketACL] + ] + if not os.path.isfile(filepath): + with open(filepath, 'a+', newline='') as f: + f = csv.writer(f) + f.writerow(headers) + f.writerows(rows) + else: + with open(filepath, 'a+', newline='') as f: + f_csv = csv.writer(f) + f_csv.writerows(rows) + + +def aws_save_file(target, ListObject, PutObject, GetBucketACL): + headers = ['Bucket', 'ListObject', 'PutObject', 'GetBucketACL'] + filepath = f'{os.getcwd()}/results/aws_{NowTime}.csv' + rows = [ + [f"{target}", ListObject, PutObject, GetBucketACL] + ] + if not os.path.isfile(filepath): + with open(filepath, 'a+', newline='') as f: + f = csv.writer(f) + f.writerow(headers) + f.writerows(rows) + else: + with open(filepath, 'a+', newline='') as f: + f_csv = csv.writer(f) + f_csv.writerows(rows) diff --git a/requirements.txt b/requirements.txt index 50b3933..19c1053 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,36 @@ -boto3==1.23.9 -colorama==0.4.4 +aliyun-python-sdk-core==2.13.36 +aliyun-python-sdk-kms==2.15.0 +boto3==1.24.31 +botocore==1.27.31 +certifi==2022.6.15 +cffi==1.15.1 +charset-normalizer==2.1.0 +colorama==0.4.5 +crcmod==1.7 +cryptography==37.0.4 +deprecation==2.1.0 dnspython==2.2.1 -loguru==0.5.3 +huaweicloud-sdk-python==1.0.28 +idna==3.3 +iso8601==1.0.2 +jmespath==0.10.0 +keystoneauth1==3.4.0 +loguru==0.6.0 +numpy==1.23.1 oss2==2.15.0 +packaging==21.3 pandas==1.4.3 -prettytable==3.2.0 +pbr==5.9.0 +prettytable==3.3.0 +pycparser==2.21 +pycryptodome==3.15.0 +pyparsing==3.0.9 +python-dateutil==2.8.2 +pytz==2022.1 +qcloud-cos==1.0.3 +requests==2.28.1 +s3transfer==0.6.0 +six==1.16.0 +stevedore==4.0.0 +urllib3==1.26.10 +wcwidth==0.2.5