def audit(self): method = self.requests.command # 请求方式 GET or POST headers = self.requests.get_headers() # 请求头 dict类型 url = self.build_url() # 请求完整URL resp_data = self.response.get_body_data() # 返回数据 byte类型 resp_str = self.response.get_body_str() # 返回数据 str类型 自动解码 resp_headers = self.response.get_headers() # 返回头 dict类型 p = self.requests.urlparse params = self.requests.params netloc = self.requests.netloc combine = '^\S+\(\{.*?\}\)' domain = "{}://{}".format(p.scheme, p.netloc) + random_str( 4, string.ascii_lowercase + string.digits) + ".com/" sensitive_params = [ 'mail', 'user', 'name', 'ip', 'pass', 'add', 'phone' ] if re.match(combine, resp_str, re.I | re.S): # 判断是否为jsonp headers["Referer"] = domain if method == 'GET': r = requests.get(url, headers=headers) if GetRatio(resp_str, r.text) >= 0.8: for i in sensitive_params: if i in r.text.lower(): res = { "Referer": domain, "keyword": i, "Content-Type": r.headers.get("Content-Type", "") } response = self.jsonp_load(r.text) if response: res["response"] = response if len(response) > 500: res["response"] = "数据太多,自行访问" out.success(url, self.name, **res) elif re.match(JSON_RECOGNITION_REGEX, resp_str, re.I | re.S) and 'callback' not in url: # 不是jsonp,是json headers["Referer"] = domain params["callback"] = random_str(2) if method == 'GET': r = requests.get(netloc, params=params, headers=headers) if r.text.startswith(params["callback"] + "({"): res = { "Referer": domain, "Content-Type": r.headers.get("Content-Type", ""), "callback": params["callback"], } response = self.jsonp_load(r.text) if response: res["response"] = response if len(response) > 500: res["response"] = "数据太多,自行访问" out.success(r.url, self.name, **res)
def audit(self): method = self.requests.command # 请求方式 GET or POST headers = self.requests.get_headers() # 请求头 dict类型 url = self.build_url() # 请求完整URL resp_data = self.response.get_body_data() # 返回数据 byte类型 resp_str = self.response.get_body_str() # 返回数据 str类型 自动解码 resp_headers = self.response.get_headers() # 返回头 dict类型 p = self.requests.urlparse params = self.requests.params netloc = self.requests.netloc domain = "{}://{}/".format(p.scheme, p.netloc) + random_str(6) + ".jsp" re_list = { "ASPNETPathDisclosure": "<title>Invalid\sfile\sname\sfor\smonitoring:\s'([^']*)'\.\sFile\snames\sfor\smonitoring\smust\shave\sabsolute\spaths\,\sand\sno\swildcards\.<\/title>", "Struts2DevMod": "You are seeing this page because development mode is enabled. Development mode, or devMode, enables extra", "Django DEBUG MODEL": "You're seeing this error because you have <code>DEBUG = True<\/code> in", "RailsDevMode": "<title>Action Controller: Exception caught<\/title>", "RequiredParameter": "Required\s\w+\sparameter\s'([^']+?)'\sis\snot\spresent", "Thinkphp3 Debug": '<p class="face">:\(</p>' } r = requests.get(domain, headers=headers) for k, v in re_list.items(): if re.search(v, r.text, re.S | re.I): out.success(domain, self.name, name=k) break
def audit(self): method = self.requests.command # 请求方式 GET or POST headers = self.requests.get_headers() # 请求头 dict类型 url = self.build_url() # 请求完整URL resp_data = self.response.get_body_data() # 返回数据 byte类型 resp_str = self.response.get_body_str() # 返回数据 str类型 自动解码 resp_headers = self.response.get_headers() # 返回头 dict类型 p = self.requests.urlparse params = self.requests.params netloc = self.requests.netloc if method == 'GET': if p.query == '': return exi = os.path.splitext(p.path)[1] if exi not in acceptedExt: return for k, v in params.items(): if k.lower() in ignoreParams: continue data = copy.deepcopy(params) randint1 = random.randint(100, 900) randint2 = random.randint(100, 900) randstr = random_str(4) payloads = { "{ranstr}${{{int1}*{int2}}}{ranstr}".format(ranstr=randstr, int1=randint1, int2=randint2), "{ranstr}#{{{int1}*{int2}}}{ranstr}".format(ranstr=randstr, int1=randint1, int2=randint2) } flag = "{ranstr}.?{{?{int}}}?{ranstr}".format(ranstr=randstr, int=randint1 * randint2) for payload in payloads: data[k] = v + payload r = requests.get(netloc, params=data, headers=headers) if re.search(flag, r.text): out.success(url, self.name, payload="{}:{}".format(k, data[k], raw=r.raw))
def audit(self): method = self.requests.command # 请求方式 GET or POST headers = self.requests.get_headers() # 请求头 dict类型 url = self.build_url() # 请求完整URL resp_data = self.response.get_body_data() # 返回数据 byte类型 resp_str = self.response.get_body_str() # 返回数据 str类型 自动解码 resp_headers = self.response.get_headers() # 返回头 dict类型 p = self.requests.urlparse params = self.requests.params netloc = self.requests.netloc if self.response.language == "PHP" or self.response.language is None: domain = "{}://{}/".format(p.scheme, p.netloc) payload = md5(random_str().encode()) payload2 = base64.b64encode(payload.encode()).decode() headers["Accept-Encoding"] = "gzip,deflate" headers["Accept-Charset"] = payload2 r = requests.get(domain, headers=headers) if r.status_code == 200 and payload in r.text: out.success(payload, self.name, desc=self.desc)
def init(self, flag, k, data): # 判断是否是内网IP,内网IP可以将延时调高,判断该url是否合适使用sql 时间盲注 self.time1 = 0 self.time2 = 0 self.time3 = 0 self.time4 = 0 self.timeOutCounter = 0 self.zeroTimeOut = 0 # send a invalid value(-1) newValue = random_str(8) data[k] = newValue r3 = requests.get(self.netloc, params=data, headers=self.headers) time3 = r3.elapsed.total_seconds() _min = min(self.min, time3) _max = max(self.max, time3) if (_max - _min) > self.shortDuration: return False if self.shortDuration > 5: return False return True
def audit(self): method = self.requests.command # 请求方式 GET or POST self.headers = headers = self.requests.get_headers() # 请求头 dict类型 url = self.build_url() # 请求完整URL resp_data = self.response.get_body_data() # 返回数据 byte类型 self.resp_str = self.response.get_body_str() # 返回数据 str类型 自动解码 resp_headers = self.response.get_headers() # 返回头 dict类型 p = self.requests.urlparse params = self.requests.params self.netloc = self.requests.netloc if method == 'GET': # 从源码中获取更多链接 if p.query == '': return exi = os.path.splitext(p.path)[1] if exi not in acceptedExt: return count = 0 ratio = 0 # 动态内容替换 while ratio <= 0.98: if count > self.retry: return r = requests.get(url, headers=headers) html = self.removeDynamicContent(r.text) self.resp_str = self.removeDynamicContent(self.resp_str) try: self.seqMatcher.set_seq1(self.resp_str) self.seqMatcher.set_seq2(html) ratio = round(self.seqMatcher.quick_ratio(), 3) except MemoryError: return self.findDynamicContent(self.resp_str, html) count += 1 sql_flag = [ "<--isdigit-->", "'&&'{0}'='{1}", '"&&"{0}"="{1}', ] for k, v in params.items(): if k.lower() in ignoreParams: continue temp_sql_flag = sql_flag.copy() # test order by if v == "desc" or v == "asc": _sql_flag = ",if('{0}'='{1}',1,(select 1 from information_schema.tables))" temp_sql_flag.append(_sql_flag) for flag in temp_sql_flag: is_num = False if flag == "<--isdigit-->": if str(v).isdigit(): is_num = True else: continue if is_num: payload_false = "{}/0".format(v) else: payload_false = v + flag.format( random_str(1) + 'a', random_str(1) + 'b') rand_str = random_str(2) if is_num: payload_true = "{}*1".format(v) else: payload_true = v + flag.format(rand_str, rand_str) ret1 = self.inject(params, k, payload_false, payload_true) if ret1: if is_num: payload_false = "{}^1".format(v) else: payload_false = v + flag.format( random_str(1) + 'c', random_str(1) + 'a') rand_str = random_str(2) if is_num: payload_true = "{}^0".format(v) else: payload_true = v + flag.format(rand_str, rand_str) ret2 = self.inject(params, k, payload_false, payload_true) if ret2: out.success(url, self.name, raw=ret2["requests"], payload_true=k + ":" + payload_true, payload_false=k + ":" + payload_false, infoMsg=ret2["info"]) return True
def audit(self): method = self.requests.command # 请求方式 GET or POST headers = self.requests.get_headers() # 请求头 dict类型 url = self.build_url() # 请求完整URL resp_data = self.response.get_body_data() # 返回数据 byte类型 resp_str = self.response.get_body_str() # 返回数据 str类型 自动解码 resp_headers = self.response.get_headers() # 返回头 dict类型 post_hint = self.requests.post_hint post_data = self.requests.post_data p = self.requests.urlparse params = self.requests.params netloc = self.requests.netloc if method == 'POST': if post_hint == POST_HINT.NORMAL: sql_flag = [ "/**/and'{0}'='{1}'", "'and'{0}'='{1}", '"and"{0}"="{1}', ] for k, v in post_data.items(): if k.lower() in ignoreParams: continue data = copy.deepcopy(post_data) for flag in sql_flag: # true page rand_str = random_str(2) payload1 = v + flag.format(rand_str, rand_str) data[k] = payload1 r = requests.post(url, data=data, headers=headers) html1 = r.text radio = GetRatio(resp_str, html1) if radio < 0.88: continue # false page payload2 = v + flag.format(random_str(2), random_str(2)) data[k] = payload2 r2 = requests.post(url, data=data, headers=headers) html2 = r2.text radio2 = GetRatio(resp_str, html2) if radio < 0.78: condition = [ '{k}:{v} 与原页面 {k}:{v1} 的相似度{radio} 页面大小:{size1}' .format(k=k, v=payload1, v1=v, radio=radio, size1=len(html1)), '{k}:{v} 与原页面 {k}:{v1} 的相似度{radio} 页面大小:{size2}' .format(k=k, v=payload2, v1=v, radio=radio2, size2=len(html2)) ] # out.log(msg) out.success(url, self.name, payload=k, condition=condition, data=str(data), raw=[r.raw, r2.raw]) break
def audit(self): method = self.requests.command # 请求方式 GET or POST headers = self.requests.get_headers() # 请求头 dict类型 url = self.build_url() # 请求完整URL resp_data = self.response.get_body_data() # 返回数据 byte类型 resp_str = self.response.get_body_str() # 返回数据 str类型 自动解码 resp_headers = self.response.get_headers() # 返回头 dict类型 p = self.requests.urlparse params = self.requests.params netloc = self.requests.netloc if method == 'GET': # 从源码中获取更多链接 if p.query == '': return exi = os.path.splitext(p.path)[1] if exi not in acceptedExt: return # 重新请求一次获取一次网页 r = requests.get(url, headers=headers) try: self.seqMatcher.set_seq1(resp_str) self.seqMatcher.set_seq2(r.text) ratio = round(self.seqMatcher.quick_ratio(), 3) except MemoryError: return if ratio <= 0.98: return False self.findDynamicContent(resp_str, r.text) count = 0 while 1: count += 1 if count > self.retry: return r = requests.get(url, headers=headers) self.findDynamicContent(resp_str, self.removeDynamicContent(r.text)) sql_flag = [ "<--isdigit-->", "'&&'{0}'='{1}", '"&&"{0}"="{1}', ] for k, v in params.items(): if k.lower() in ignoreParams: continue data = copy.deepcopy(params) for flag in sql_flag: is_inject = False is_num = False if flag == "<--isdigit-->": if str(v).isdigit(): is_num = True else: continue if is_num: payload_false = "{}/0".format(v) else: payload_false = v + flag.format( random_str(1) + 'a', random_str(1) + 'b') data[k] = payload_false r2 = requests.get(netloc, params=data, headers=headers) falsePage = self.removeDynamicContent(r2.text) try: self.seqMatcher.set_seq1(resp_str) self.seqMatcher.set_seq2(falsePage) ratio_false = round(self.seqMatcher.quick_ratio(), 3) # ratio *= GetRatio(resp_str, html1) if ratio_false == 1.0: continue except (MemoryError, OverflowError): continue # true page rand_str = random_str(2) if is_num: payload_true = "{}*1".format(v) else: payload_true = v + flag.format(rand_str, rand_str) data[k] = payload_true r = requests.get(netloc, params=data, headers=headers) truePage = self.removeDynamicContent(r.text) if truePage == falsePage: continue try: self.seqMatcher.set_seq1(resp_str or "") self.seqMatcher.set_seq2(truePage or "") ratio_true = round(self.seqMatcher.quick_ratio(), 3) except (MemoryError, OverflowError): continue if ratio_true > self.UPPER_RATIO_BOUND or ( 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 abs( ratio_true - ratio_false) > 0.05: originalSet = set( getFilteredPageContent(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: out.success(url, self.name, raw=[r2.raw, r.raw], payload_true=k + ":" + payload_true, payload_false=k + ":" + payload_false) break
def audit(self): method = self.requests.command # 请求方式 GET or POST headers = self.requests.get_headers() # 请求头 dict类型 url = self.build_url() # 请求完整URL resp_data = self.response.get_body_data() # 返回数据 byte类型 resp_str = self.response.get_body_str() # 返回数据 str类型 自动解码 resp_headers = self.response.get_headers() # 返回头 dict类型 p = self.requests.urlparse params = self.requests.params netloc = self.requests.netloc if method == 'GET': if p.query == '': return exi = os.path.splitext(p.path)[1] if exi.strip('.') in notAcceptedExt: return rndStr = 9000 + random.randint(1, 999) tag = random_str(4) html_payload = "<{tag}>{randint}</{tag}>".format( tag=tag, randint=rndStr) # html xss attr_payload = [ '" oNsOmeEvent="console.log(233)', # 双引号payload "' oNsOmeEvent='console.log(2333)", # 单引号payload ] url_payload = "javascript:{randint}".format(randint=rndStr) javascript_payload = "{randint}".format(randint=rndStr) dom_xss = ['location.hash', 'location.href', 'location.search'] for k, v in params.items(): if k.lower() in ignoreParams: continue # check v is in content if v.lower() not in resp_str.lower(): continue data = copy.deepcopy(params) ranstr = random_str(5) data[k] = v + ranstr r = requests.get(url, headers=headers, params=data) html1 = r.text if ranstr not in html1: continue in_script = False may_dom_xss = False script_group = re.findall('<script.*?>(.*?)</script>', html1, re.I | re.S | re.M) if script_group: for i in script_group: if ranstr in i: in_script = True break for item in dom_xss: if item in i: may_dom_xss = item break if may_dom_xss: out.success(url, self.name, descipt="可能的[dom xss]在<script> 变量{}中".format( may_dom_xss)) if in_script: if ('"' + ranstr) in html1: data[k] = v + javascript_payload + '"' r = requests.get(url, headers=headers, params=data) if (javascript_payload + '"') in r.text: out.success( url, self.name, payload="{}:{}".format(k, data[k]), raw=r.raw, descript="探测字符在<script>脚本内被解析,且双引号未被转义", type="javascript xss") elif ("'" + ranstr) in html1: data[k] = v + javascript_payload + "'" r = requests.get(url, headers=headers, params=data) if (javascript_payload + "'") in r.text: out.success( url, self.name, payload="{}:{}".format(k, data[k]), raw=r.raw, descript="探测字符在<script>脚本内被解析,且单引号未被转义", type="javascript xss") # test domxss in javascript string if re.search( '(innerHTML|document\.write)\s*=\s*[\'"].*{}'. format(ranstr), html1) or re.search( "\)\.html\(.*{}.*\)".format(ranstr), html1): data[ k] = v + javascript_payload + '\\u003c\\x3c' + javascript_payload r = requests.get(url, headers=headers, params=data) middle = get_middle_text(r.text, javascript_payload, javascript_payload) if '\\u003c' in middle: out.success( url, self.name, payload="{}:{}".format(k, data[k]), descript= "字符在(innerHTML|document.write|$(xx).html())标签中且\\u003c未过滤", bug_link= "https://shuimugan.com/bug/view?bug_no=16041") elif '\\x3c' in middle: out.success( url, self.name, payload="{}:{}".format(k, data[k]), descript= "字符在(innerHTML|document.write|$(xx).html())标签中且\\x3c未过滤", bug_link= "https://shuimugan.com/bug/view?bug_no=16041") else: # check html xss data[k] = v + html_payload r = requests.get(url, headers=headers, params=data) html1 = r.text if html_payload in html1: out.success(url, self.name, payload="{}:{}".format(k, data[k]), raw=r.raw, descript="探测tag被解析", type="html xss") break # check attr xss for payload in attr_payload: data[k] = v + payload r = requests.get(url, headers=headers, params=data) html1 = r.text if payload[0] == '"': if payload + '"' in html1: out.success(url, self.name, payload="{}:{}".format(k, data[k]), raw=r.raw, type="标签属性xss") break elif payload[0] == "'": if payload + "'" in html1: out.success(url, self.name, payload="{}:{}".format(k, data[k]), raw=r.raw, type="标签属性xss") break # check url payload re_parren = r'''[src|href|action]=['"]''' data[k] = v + url_payload r = requests.get(url, headers=headers, params=data) html1 = r.text if re.search(re_parren + url_payload, html1): out.success(url, self.name, payload="{}:{}".format(k, data[k]), raw=r.raw, type="url xss") break
def audit(self): method = self.requests.command # 请求方式 GET or POST headers = self.requests.get_headers() # 请求头 dict类型 url = self.build_url() # 请求完整URL resp_data = self.response.get_body_data() # 返回数据 byte类型 resp_str = self.response.get_body_str() # 返回数据 str类型 自动解码 resp_headers = self.response.get_headers() # 返回头 dict类型 p = self.requests.urlparse params = self.requests.params netloc = self.requests.netloc if method == 'GET': if p.query == '': return exi = os.path.splitext(p.path)[1] if exi not in acceptedExt: return rndStr = 9000 + random.randint(1, 999) tag = random_str(4) html_payload = "<{tag}>{randint}</{tag}>".format( tag=tag, randint=rndStr) # html xss attr_payload = [ '" oNsOmeEvent="console.log(233)', # 双引号payload "' oNsOmeEvent='console.log(2333)", # 单引号payload ] url_payload = "javascript:{randint}".format(randint=rndStr) javascript_payload = "{randint}".format(randint=rndStr) for k, v in params.items(): if k.lower() in ignoreParams: continue data = copy.deepcopy(params) ranstr = random_str(5) data[k] = v + ranstr r = requests.get(url, headers=headers, params=data) html1 = r.text if ranstr not in html1: continue in_script = False script_group = re.findall('<script.*?>(.*?)</script>', html1, re.I | re.S | re.M) if script_group: for i in script_group: if ranstr in i: in_script = True break if in_script: if ('"' + ranstr) in html1: data[k] = v + javascript_payload + '"' r = requests.get(url, headers=headers, params=data) if (javascript_payload + '"') in r.text: out.success( url, self.name, payload="{}:{}".format(k, data[k]), raw=r.raw, descript="探测字符在<script>脚本内被解析,且双引号未被转义", type="javascript xss") if ("'" + ranstr) in html1: data[k] = v + javascript_payload + "'" r = requests.get(url, headers=headers, params=data) if (javascript_payload + "'") in r.text: out.success( url, self.name, payload="{}:{}".format(k, data[k]), raw=r.raw, descript="探测字符在<script>脚本内被解析,且单引号未被转义", type="javascript xss") else: # check html xss data[k] = v + html_payload r = requests.get(url, headers=headers, params=data) html1 = r.text if html_payload in html1: out.success(url, self.name, payload="{}:{}".format(k, data[k]), raw=r.raw, descript="探测tag被解析", type="html xss") break # check attr xss for payload in attr_payload: data[k] = v + payload r = requests.get(url, headers=headers, params=data) html1 = r.text if payload[0] == '"': if payload + '"' in html1: out.success(url, self.name, payload="{}:{}".format(k, data[k]), raw=r.raw, type="标签属性xss") break elif payload[0] == "'": if payload + "'" in html1: out.success(url, self.name, payload="{}:{}".format(k, data[k]), raw=r.raw, type="标签属性xss") break # check url payload re_parren = r'''[src|href|action]=['"]''' data[k] = v + url_payload r = requests.get(url, headers=headers, params=data) html1 = r.text if re.search(re_parren + url_payload, html1): out.success(url, self.name, payload="{}:{}".format(k, data[k]), raw=r.raw, type="url xss") break