├── README.md ├── user_config.txt ├── 补天自动化提交最终版.py └── 说明.txt /README.md: -------------------------------------------------------------------------------- 1 | # vul_submit 2 | 补天敏感信息自动化脚本提交 3 | -------------------------------------------------------------------------------- /user_config.txt: -------------------------------------------------------------------------------- 1 | { 2 | "username":"", 3 | "password":"", 4 | "cookie":["PHPSESSID",""], 5 | "appkey":"", 6 | "key":"" 7 | } 8 | 9 | 10 | -------------------------------------------------------------------------------- /补天自动化提交最终版.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf8 -*- 2 | # by 孤桜懶契 3 | # 补天刷洞脚本 by 2022.1.13 4 | ''' 5 | 0、所有初始化类中集合 6 | 1、session保存cookies,若cookies为null则使用发包和校验进行账号密码登陆 7 | 2、模拟浏览器,selenium浏览器drive,进行截图 8 | 3、发包获取上传图片链接 9 | 4、极验绕过验证码获取校验码 10 | 5、集成包体进行提交漏洞 11 | ''' 12 | 13 | from selenium import webdriver 14 | from urllib.parse import urlparse 15 | import requests 16 | import time 17 | # import ast 18 | import json 19 | import httplib2 20 | import urllib3 21 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 22 | requests.packages.urllib3.disable_warnings() 23 | from PIL import ImageGrab 24 | import random 25 | 26 | 27 | 28 | class auto_init_butian: 29 | 30 | def __init__(self): 31 | ''' 32 | 初始化配置文件 33 | ''' 34 | # Chrome的启动项参数,并实例化 35 | self.chromedriver_options = webdriver.ChromeOptions() 36 | self.chromedriver_options.add_experimental_option('useAutomationExtension', False) 37 | self.chromedriver_options.add_experimental_option("excludeSwitches", ['enable-automation']) 38 | self.chromedriver_options.add_argument('--incognito') 39 | self.chromedriver_options.add_argument('--ignore-certificate-errors') 40 | self.chromedriver_options.add_argument(r"--user-data-dir=C:\Users\23242\AppData\Local\Google\Chrome\User Data\Default"); 41 | 42 | # 代理抓包测试配置 43 | self.proxies = { 44 | "http": 'http://127.0.0.1:8080', 45 | "https": 'http://127.0.0.1:8080' 46 | } 47 | 48 | # 滑块配置 49 | self.login_gt_url = "https://user.butian.net/register_geetest" 50 | self.submit_gt_url = "https://www.butian.net/Loo/startCaptcha" 51 | 52 | # 设定当前页面Cookie 和 登陆账号和密码 53 | self.session = requests.session() 54 | with open('user_config.txt' , 'r') as user_info: 55 | user_info = user_info.read() 56 | user_info = json.loads(user_info) 57 | # print(user_info) 58 | self.username = user_info["username"] 59 | self.password = user_info["password"] 60 | # 滑块 APikey 61 | self.appkey = user_info["appkey"] 62 | # 备案 APikey 63 | self.key = user_info["key"] 64 | 65 | # 判断是否设置了Cookie 设置了就用Cookie访问,如果没设置 就根据设置的账号和密码登陆 66 | if "null" not in user_info["cookie"][0]: 67 | print("[+] Cookies设置完毕,具体情况看结果!") 68 | self.session.cookies.set(user_info["cookie"][0],user_info["cookie"][1]) 69 | else: 70 | self.login_user_pass() 71 | 72 | 73 | def submit_vul(self, url): 74 | ''' 75 | 将传入的url进行提交 76 | :param url: 77 | :return: 78 | ''' 79 | company_vul_name=self.company_record_inquiry(url) 80 | # 当查询结果为个人,或无,都结束当前url的运行,继续下一个 81 | if company_vul_name == "failed": 82 | print("[-] 查询下一个") 83 | return 84 | 85 | # 截图 86 | self.screen_shot(url) 87 | 88 | # 分割 89 | url_parse = urlparse(url) 90 | host_name = url_parse.scheme+"://"+url_parse.netloc 91 | 92 | # 获取截图对应链接 93 | print("[*] ————主页截图————") 94 | image_first = self.upload_image('主页.png') 95 | print("[*] ————归属证明截图————") 96 | image_second = self.upload_image('归属证明.png') 97 | print("[*] ————信息泄露页面————") 98 | image_third = self.upload_image('信息泄露页面.png') 99 | 100 | # 详细描述过程 101 | detail = f'''

1、访问公司网站首页


image.png



2、备案归属查询截图


image.png


3、验证漏洞,步骤如下

①漏洞所在URL:{url}


②直接访问上述漏洞URL,查看左下角下载文件


image.png

''' 102 | 103 | # 极验数据返回值 slider_dict['data']['challenge'], slider_dict['data']['validate'] 104 | submit_challenge, submit_validate = self.pass_slider(sub_referer='https://www.butian.net/Loo/submit',sub_gt_url=self.submit_gt_url) 105 | 106 | # 元组表示表单上传的data数据 107 | 108 | files = { 109 | 'attachment':(None,''), 110 | 'attachment_name':(None,''), 111 | 'url':(None,url), 112 | 'attribute':(None,'1'), #漏洞类型,1:事件 2:通用 113 | 'company_name':(None,company_vul_name), 114 | 'host':(None,host_name), 115 | 'origin':(None,'1'), 116 | 'title':(None,company_vul_name+'当前网站存在信息泄露'), 117 | 'type':(None,'10'),#漏洞类型, 2、sql注入 10、信息泄露 118 | 'level':(None,'1'),#漏洞等级 1、中危 2、高危 119 | 'description':(None,company_vul_name+'旗下网站存在信息泄露,攻击者可利用该漏洞获取大量敏感信息或源码对新的漏洞进行审计,从而进行更深入的攻击,导致更多的信息伤害。'), 120 | 'detail':(None,detail), 121 | 'repair_suggest':(None,'直接在该网站目录删除备份或敏感文件'), 122 | 'tag3':(None,'class1|18,class2|19,class2|24'),# 标签选项 123 | 'province':(None,'湖北省'), 124 | 'city':(None,'武汉市'), 125 | 'county':(None,'市辖区'), 126 | 'company_contact':(None,''), 127 | 'anonymous':(None,'1'),# 匿名提交 128 | 'agree':(None,'1'),# 是否同意用户协议 129 | 'id':(None,''), 130 | 'geetest_challenge':(None,submit_challenge),#验证码 131 | 'geetest_validate':(None,submit_validate),#验证码 132 | 'geetest_seccode':(None,submit_validate+'|jordan'),#验证码 133 | } 134 | respon = self.session.post(url="https://www.butian.net/Home/Loo/submit",files=files,verify=False,timeout=5) 135 | sucess_result=json.loads(respon.text) 136 | sucess_message = str(sucess_result['info']) 137 | if sucess_result['status'] == 1: 138 | print("[+] 提交完成!") 139 | print("[*] 返回消息:",sucess_message) 140 | print("[+] 防止提交过快 随机延时 60-120 秒 请等待~~") 141 | start_time=time.time() 142 | time.sleep(random.randint(60, 120)) 143 | end_time=time.time() 144 | print(f"[+] 已随机延时 { end_time - start_time:.2f} 秒,继续工作!\n") 145 | else: 146 | print("[-] 提交失败") 147 | print("[*] 返回消息:", sucess_message) 148 | print("[+] 防止提交过快 随机延时 60-120 秒 请等待~~") 149 | start_time=time.time() 150 | time.sleep(random.randint(60, 120)) 151 | end_time=time.time() 152 | print(f"[+] 已随机延时 { end_time - start_time:.2f} 秒,继续工作!\n") 153 | 154 | 155 | 156 | 157 | # 图片上传 158 | def upload_image(self,image_path): 159 | ''' 160 | 对传上来的路径进行上传 161 | :param image_path: 162 | :return: 163 | ''' 164 | read_binary_image = open(image_path, 'rb') 165 | files = {'upfile': read_binary_image} 166 | respon = requests.post("https://www.butian.net/Public/ueditor/php/controller.php?action=uploadimage", 167 | files=files, verify=False, timeout=5) 168 | image_url = json.loads(respon.text) 169 | print("[+] 图片上传成功:", image_url['url']) 170 | return image_url['url'] 171 | 172 | # 屏幕截图 173 | def screen_shot(self, url): 174 | ''' 175 | 访问对应url进行取证截图 176 | :param url: 177 | :return: 178 | ''' 179 | 180 | # 浏览器启动 181 | self.chrome_browser = webdriver.Chrome(options=self.chromedriver_options) 182 | # 若上方报错,则如下采用路径形式 183 | # self.chrome_browser = webdriver.Chrome(executable_path=r'C:\python30\chromedriver.exe', options=self.chromedriver_options) 184 | # 窗口和加载设置 185 | self.chrome_browser.implicitly_wait(6) # 隐式等待 186 | self.chrome_browser.maximize_window() #窗口最大化 187 | 188 | # 截图大小 189 | screen_shot_size = (0, 0 , 1920, 1080) 190 | url_split = urlparse(url) 191 | # 访问归属 192 | self.chrome_browser.get("https://icp.chinaz.com/" + url_split.netloc) 193 | time.sleep(2) 194 | self.chrome_browser.execute_script("window.scrollTo(0,200);") 195 | screen_shot_image = ImageGrab.grab(screen_shot_size) 196 | screen_shot_image.save('归属证明.png') 197 | 198 | # 访问主页 199 | self.chrome_browser.get("http://"+url_split.netloc) 200 | time.sleep(2) 201 | screen_shot_image = ImageGrab.grab(screen_shot_size) 202 | screen_shot_image.save('主页.png') 203 | 204 | # 访问信息泄露的url 205 | self.chrome_browser.get(url) 206 | time.sleep(2) 207 | screen_shot_image = ImageGrab.grab(screen_shot_size) 208 | screen_shot_image.save('信息泄露页面.png') 209 | self.chrome_browser.close() 210 | 211 | 212 | # 备案信息收集 ↓ 213 | def company_record_inquiry(self,url): 214 | ''' 215 | 备案查询 216 | :param url: 217 | :return: 218 | ''' 219 | print("[*] 查询备案公司信息:"+url) 220 | url_domain=urlparse(url).netloc 221 | # Api备案查询 ↓ http://api.chinaz.com/ApiDetails/Domain 积分购买 222 | api_information=f"https://apidatav2.chinaz.com/single/icp?key={self.key}&domain="+url_domain 223 | respon=requests.get(url=api_information,timeout=5) 224 | # if ('null' in rsp.text): 225 | # return "shibai" 226 | # Json转字典——Json.loads(respon.text) 227 | # 将数据转换成能够转换的类型 ast.literal_eval(respon.text) 当域名错误时会报错 弃用 228 | dict_convert=json.loads(respon.text) 229 | if "null" in respon.text: 230 | print("[-] 数据未查询到") 231 | return "failed" 232 | elif dict_convert["Result"]["CompanyType"] == "个人": # 当网站为个人时 数据用处不大 233 | print("[*] 当前域名用户为个人产业") 234 | print("[-] 无法提交漏洞") 235 | return "failed" 236 | elif dict_convert["StateCode"] == 1: # 查询成功,不是个人返回 237 | print("[+] 查询成功") 238 | print("[+] 数据为:",dict_convert["Result"]["CompanyName"]) 239 | return dict_convert["Result"]["CompanyName"] 240 | return "failed" 241 | 242 | # 付费过任何滑块 243 | def pass_slider(self,sub_referer,sub_gt_url): 244 | ''' 245 | 滑块方法 246 | :param sub_referer: 247 | :param sub_gt_url: 248 | :return: 249 | ''' 250 | # 用户appkey 251 | appkey = self.appkey # https://www.kancloud.cn/rrocr/rrocr/2294925 获取apk 252 | # 判断获取challenge 和 gt的位置是否能够访问 253 | 254 | try: 255 | # 获取gt 和 challenge 256 | gt_url = sub_gt_url 257 | gt_rep = requests.get(url=gt_url, verify=False) 258 | gt_dict = json.loads(gt_rep.text) 259 | gt = gt_dict['gt'] 260 | challenge = gt_dict["challenge"] 261 | print("[+] 获取成功 gt:", gt, " challenge:", challenge) 262 | except: 263 | print('[-] 正在尝试访问获取gt和challenge页面') 264 | self.pass_slider(sub_referer,sub_gt_url) 265 | # 查询当前api剩余积分 266 | try: 267 | slider_req_score = f"http://api.rrocr.com/api/integral.html?appkey={appkey}" 268 | slider_rep_score = requests.get(url=slider_req_score) 269 | print("[+] 当前极验剩余Api积分:", json.loads(slider_rep_score.text)['integral']) 270 | except: 271 | print("[-] 积分无法查询,请确认appkey正确!") 272 | exit(1) 273 | 274 | slider_data = { 275 | 'appkey': appkey, 276 | 'gt': gt_dict['gt'], 277 | 'challenge': gt_dict['challenge'], 278 | 'referer': sub_referer 279 | } 280 | # 传参判断返回值 281 | try: 282 | slider_rep = requests.post(url='http://api.rrocr.com/api/recognize.html', data=slider_data) 283 | if "识别成功" in slider_rep.text: 284 | slider_dict = json.loads(slider_rep.text) 285 | # print(slider_dict) 286 | print("[+] 校验成功 challenge:",slider_dict['data']['challenge'], "validate:",slider_dict['data']['validate']) 287 | return slider_dict['data']['challenge'], slider_dict['data']['validate'] 288 | else: 289 | print("[-] 识别失败,请确认是否还剩余积分!") 290 | except: 291 | print("[-] 无法访问 api对应网站") 292 | 293 | def login_user_pass(self): 294 | ''' 295 | 账号密码登陆 296 | :return: 297 | ''' 298 | print("[*] 正在尝试账号密码登陆~") 299 | # 获取请求包体 300 | requests_headers = httplib2.Http('.cache') 301 | url = 'https://user.butian.net/user/sign-in?next=https://www.butian.net/login.html&style=1' 302 | response, content = requests_headers.request(url, 'GET') 303 | response = dict(response) 304 | # 从包体中获取csrf形成字典形式 305 | set_cookie_split = response['set-cookie'].split(';') 306 | csrf_split = set_cookie_split[0].split('=') 307 | print("[+] csrf_token保护获取成功:", csrf_split[1]) 308 | suc_challenge, suc_validate = self.pass_slider(sub_referer='https://user.butian.net/user/sign-in?next=https://www.butian.net/login.html&style=1',sub_gt_url=self.login_gt_url) 309 | print("[+] 识别成功,challenge:", suc_challenge, "validate:", suc_validate) 310 | login_url = "https://user.butian.net/api/v1/sign-in" 311 | login_data = { 312 | "account": self.username, 313 | "password": self.password, 314 | "geetest_challenge": suc_challenge, 315 | "geetest_validate": suc_validate, 316 | "geetest_seccode": suc_validate + "|jordan", 317 | "next": "https://www.butian.net/login.html", 318 | "csrf_token": csrf_split[1] 319 | } 320 | login_headers = { 321 | 'Cookie': 'next=https%3A//www.butian.net/login.html; User-Center=17507e8a-c16a-40c1-b401-f0f1c9658a11; style=1; csrf_token=' + 322 | csrf_split[1], 323 | 'Sec-Ch-Ua': '"Chromium";v="91", " Not;A Brand";v="99"', 324 | 'Accept': 'application/json', 325 | 'Sec-Ch-Ua-Mobile': '?0', 326 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 327 | 'Content-Type': 'application/json', 328 | 'Origin': 'https://user.butian.net', 329 | 'Sec-Fetch-Site': 'same-origin', 330 | 'Sec-Fetch-Mode': 'cors', 331 | 'Sec-Fetch-Dest': 'empty', 332 | 'Referer': 'https://user.butian.net/user/sign-in?next=https://www.butian.net/login.html&style=1', 333 | 'Accept-Encoding': 'gzip, deflate', 334 | 'Accept-Language': 'zh-CN,zh;q=0.9', 335 | 'Connection': 'close', 336 | } 337 | login_rep = self.session.post(url=login_url, data=json.dumps(login_data), headers=login_headers, 338 | verify=False) 339 | if r"\u6210\u529f" in login_rep.text: 340 | print("[+] 登陆成功!\n") 341 | else: 342 | print("[-] 密码错误!请重新输入或者更换成Cookie方式!\n") 343 | 344 | 345 | 346 | 347 | if __name__ == '__main__': 348 | auto_start = auto_init_butian() # 初始化数据,登陆和cookie设置 349 | with open("url.txt", "r") as file: 350 | file_line_list = file.read().split("\n") 351 | count = 1 352 | for vul_url in file_line_list: 353 | print("[*] 剩下数量:", count, "/", len(file_line_list)) 354 | auto_start.submit_vul(vul_url) 355 | count += 1 356 | -------------------------------------------------------------------------------- /说明.txt: -------------------------------------------------------------------------------- 1 | 使用教程如下: 2 | 首先安装好chrom浏览器和其对应版本的驱动,将驱动所在位置添加到环境变量,具体步骤请百度:selenium配置谷歌 3 | 4 | 配置apikey: 5 | 找到脚本第36行替换上站长api备案查询的key 6 | 获取地址如下:http://api.chinaz.com/ApiDetails/Domain 7 | 购买后在站长api中心获取key 8 | appkey获取地址如下:https://www.rrocr.com/ 9 | 访问网址后注册用户登录,用户中心有appkey,最低充值10元,此接口为过滑块识别 10 | 11 | 12 | 获取session: 13 | 随后访问补天登录,获取登录后的cookie中的PHPSESSID的值 14 | 格式为:PHPSESSID,o8m5vkhqfbi9knp8gdr32e1c77 15 | 16 | 17 | 漏洞放入url.txt里保存,运行脚本即可 18 | 19 | 20 | --------------------------------------------------------------------------------