├── 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、访问公司网站首页

2、备案归属查询截图

3、验证漏洞,步骤如下
①漏洞所在URL:{url}
②直接访问上述漏洞URL,查看左下角下载文件

'''
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 |
--------------------------------------------------------------------------------