main.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. #!/usr/bin/python
  2. # -*- coding: iso-8859-15 -*-
  3. """
  4. This file is part of the cintruder project, http://cintruder.03c8.net
  5. Copyright (c) 2012/2019 psy <epsylon@riseup.net>
  6. cintruder is free software; you can redistribute it and/or modify it under
  7. the terms of the GNU General Public License as published by the Free
  8. Software Foundation version 3 of the License.
  9. cintruder is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  12. details.
  13. You should have received a copy of the GNU General Public License along
  14. with cintruder; if not, write to the Free Software Foundation, Inc., 51
  15. Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. """
  17. import os, traceback, hashlib, sys, time, socket, urlparse
  18. import platform, subprocess, re, webbrowser
  19. from core.options import CIntruderOptions
  20. from core.crack import CIntruderCrack
  21. from core.ocr import CIntruderOCR
  22. from core.curl import CIntruderCurl
  23. from core.xml_export import CIntruderXML
  24. from core.update import Updater
  25. from urlparse import urlparse
  26. # set to emit debug messages about errors (0 = off).
  27. DEBUG = 0
  28. class cintruder():
  29. """
  30. CIntruder application class
  31. """
  32. def __init__(self):
  33. self.captcha = ""
  34. self.optionOCR = []
  35. self.optionCrack = []
  36. self.optionParser = None
  37. self.optionCurl = None
  38. self.options = None
  39. self.word_sug = None
  40. self.train == 0
  41. self.crack == 0
  42. self.ignoreproxy = 1
  43. self.isurl = 0
  44. self.os_sys = platform.system()
  45. self._webbrowser = webbrowser
  46. def set_options(self, options):
  47. """
  48. Set cintruder options
  49. """
  50. self.options = options
  51. def create_options(self, args=None):
  52. """
  53. Create the program options for OptionParser.
  54. """
  55. self.optionParser = CIntruderOptions()
  56. self.options = self.optionParser.get_options(args)
  57. if not self.options:
  58. return False
  59. return self.options
  60. def set_webbrowser(self, browser):
  61. self._webbrowser = browser
  62. def banner(self):
  63. print '='*75
  64. print ""
  65. print " o8%8888, "
  66. print " o88%8888888. "
  67. print " 8'- -:8888b "
  68. print " 8' 8888 "
  69. print " d8.-=. ,==-.:888b "
  70. print " >8 `~` :`~' d8888 "
  71. print " 88 ,88888 "
  72. print " 88b. `-~ ':88888 "
  73. print " 888b \033[1;31m~==~\033[1;m .:88888 "
  74. print " 88888o--:':::8888 "
  75. print " `88888| :::' 8888b "
  76. print " 8888^^' 8888b "
  77. print " d888 ,%888b. "
  78. print " d88% %%%8--'-. "
  79. print " /88:.__ , _%-' --- - "
  80. print " '''::===..-' = --. `\n"
  81. print self.optionParser.description, "\n"
  82. print '='*75
  83. @classmethod
  84. def try_running(cls, func, error, args=None):
  85. """
  86. Try running a function and print some error if it fails and exists with
  87. a fatal error.
  88. """
  89. args = args or []
  90. try:
  91. return func(*args)
  92. except Exception:
  93. print(error, "error")
  94. if DEBUG:
  95. traceback.print_exc()
  96. def get_attack_captchas(self):
  97. """
  98. Get captchas to brute force
  99. """
  100. captchas = []
  101. options = self.options
  102. p = self.optionParser
  103. if options.train:
  104. print('='*75)
  105. print(str(p.version))
  106. print('='*75)
  107. print("Starting to 'train'...")
  108. print('='*75)
  109. captchas = [options.train]
  110. if options.crack:
  111. print('='*75)
  112. print(str(p.version))
  113. print('='*75)
  114. print("Starting to 'crack'")
  115. print('='*75)
  116. captchas = [options.crack]
  117. if options.track:
  118. print('='*75)
  119. print(str(p.version))
  120. print('='*75)
  121. print("Tracking captchas from url...")
  122. print('='*75+"\n")
  123. captchas = [options.track]
  124. return captchas
  125. def train(self, captchas):
  126. """
  127. Learn mode:
  128. + Add words to the brute forcing dictionary
  129. """
  130. self.train_captcha(captchas)
  131. def train_captcha(self, captcha):
  132. """
  133. Learn mode:
  134. 1- Apply OCR to captcha/image and split into unities
  135. 2- Human-Recognize that unities like alphanumeric words (gui supported)
  136. 3- Move that words into dictionary (gui supported)
  137. """
  138. options = self.options
  139. # step 1: applying OCR techniques
  140. if options.name: # with a specific OCR module
  141. print "[Info] Using module: [", options.name, "]"
  142. try:
  143. sys.path.append('mods/%s/'%(options.name))
  144. exec("from " + options.name + "_ocr" + " import CIntruderOCR") # import module
  145. except Exception:
  146. print "\n[Error] '"+ options.name+ "' module not found!\n"
  147. return #sys.exit(2)
  148. if options.setids: # with a specific colour ID
  149. setids = int(options.setids)
  150. if setids >= 0 and setids <= 255:
  151. self.optionOCR = CIntruderOCR(captcha, options)
  152. else:
  153. print "\n[Error] You must enter a valid RGB colour ID number (between 0 and 255)\n"
  154. return #sys.exit(2)
  155. else:
  156. self.optionOCR = CIntruderOCR(captcha, options)
  157. else: # using general OCR algorithm
  158. if options.setids: # with a specific colour ID
  159. setids = int(options.setids)
  160. if setids >= 0 and setids <= 255:
  161. self.optionOCR = CIntruderOCR(captcha, options)
  162. else:
  163. print "\n[Error] You must enter a valid RGB colour ID number (between 0 and 255)\n"
  164. return #sys.exit(2)
  165. else:
  166. self.optionOCR = CIntruderOCR(captcha, options)
  167. def crack(self, captchas):
  168. """
  169. Crack mode:
  170. + Brute force target's captcha against a dictionary
  171. """
  172. self.crack_captcha(captchas)
  173. def crack_captcha(self, captcha):
  174. """
  175. Crack mode: bruteforcing...
  176. """
  177. options = self.options
  178. if options.name:
  179. print "Loading module:", options.name
  180. print "==============="
  181. try:
  182. sys.path.append('mods/%s/'%(options.name))
  183. exec("from " + options.name + "_crack" + " import CIntruderCrack")
  184. except Exception:
  185. print "\n[Error] '"+ options.name+ "' module not found!\n"
  186. return #sys.exit(2)
  187. self.optionCrack = CIntruderCrack(captcha)
  188. w = self.optionCrack.crack(options)
  189. self.word_sug = w
  190. else:
  191. self.optionCrack = CIntruderCrack(captcha)
  192. w = self.optionCrack.crack(options)
  193. self.word_sug = w
  194. def remote(self, captchas, proxy):
  195. """
  196. Get remote captchas
  197. """
  198. l = []
  199. if not os.path.exists("inputs/"):
  200. os.mkdir("inputs/")
  201. for captcha in captchas:
  202. c = self.remote_captcha(captcha, proxy)
  203. l.append(c)
  204. return l
  205. def remote_captcha(self, captcha, proxy):
  206. """
  207. Get remote captcha
  208. """
  209. if proxy:
  210. self.ignoreproxy=0
  211. self.optionCurl = CIntruderCurl(captcha, self.ignoreproxy, proxy)
  212. buf = self.optionCurl.request()
  213. if buf != "exit":
  214. m = hashlib.md5()
  215. m.update(captcha)
  216. c = "%s.gif"%(m.hexdigest())
  217. h = "inputs/" + c
  218. f = open(h, 'wb')
  219. f.write(buf.getvalue())
  220. f.close
  221. buf.close
  222. return h
  223. else:
  224. return #sys.exit(2)
  225. def export(self, captchas):
  226. """
  227. Export results
  228. """
  229. if self.options.xml and not (self.options.train):
  230. self.optionXML = CIntruderXML(captchas)
  231. if self.word_sug == None:
  232. print "[Info] XML NOT created!. There are not words to suggest..."
  233. else:
  234. self.optionXML.print_xml_results(captchas, self.options.xml, self.word_sug)
  235. print "[Info] XML created:", self.options.xml, "\n"
  236. def track(self, captchas, proxy, num_tracks):
  237. """
  238. Download captchas from url
  239. """
  240. for captcha in captchas:
  241. self.track_captcha(captcha, proxy, num_tracks)
  242. def track_captcha(self, captcha, proxy, num_tracks):
  243. """
  244. This technique is useful to create a dictionary of 'session based' captchas
  245. """
  246. options = self.options
  247. urlp = urlparse(captcha)
  248. self.domain = urlp.hostname
  249. if not os.path.exists("inputs/%s"%(self.domain)):
  250. os.mkdir("inputs/%s"%(self.domain))
  251. if proxy:
  252. self.ignoreproxy = 0
  253. buf = ""
  254. i=0
  255. while i < int(num_tracks) and buf != "exit":
  256. self.optionCurl = CIntruderCurl(captcha, self.ignoreproxy, proxy)
  257. buf = self.optionCurl.request()
  258. if options.verbose:
  259. print "\n[-]Connection data:"
  260. out = self.optionCurl.print_options()
  261. print '-'*45
  262. if buf != "exit":
  263. m = hashlib.md5()
  264. m.update("%s%s"%(time.time(), captcha))
  265. h = "inputs/%s/%s.gif"%(self.domain, m.hexdigest())
  266. f = open(h, 'wb')
  267. f.write(buf.getvalue())
  268. f.close
  269. buf.close
  270. print "[Info] Saved:", h
  271. print "------------"
  272. i=i+1
  273. if buf != "exit":
  274. print "\n================="
  275. print "Tracking Results:"
  276. print "================="
  277. print "\nNumber of tracked captchas: [", num_tracks, "] \n"
  278. def run(self, opts=None):
  279. """
  280. Run cintruder
  281. """
  282. if opts:
  283. options = self.create_options(opts)
  284. self.set_options(options)
  285. options = self.options
  286. #step -1: run GUI/Web interface
  287. if options.web:
  288. self.create_web_interface()
  289. return
  290. #step -1: check/update for latest stable version
  291. if options.update:
  292. self.banner()
  293. try:
  294. print("\nTrying to update automatically to the latest stable version\n")
  295. Updater()
  296. except:
  297. print("\nSomething was wrong!. To have working this feature, you should clone CIntruder with:\n")
  298. print("$ git clone https://github.com/epsylon/cintruder\n")
  299. #step 0: list output results and get captcha targets
  300. if options.listmods:
  301. print "====================================="
  302. print "Listing specific OCR exploit modules:"
  303. print "=====================================\n"
  304. top = 'mods/'
  305. for root, dirs, files in os.walk(top, topdown=False):
  306. for name in files:
  307. if name == 'DESCRIPTION':
  308. if self.os_sys == "Windows": #check for win32 sys
  309. subprocess.call("type %s/%s"%(root, name), shell=True)
  310. else:
  311. subprocess.call("cat %s/%s"%(root, name), shell=True)
  312. print "\n[Info] List end...\n"
  313. return
  314. if options.track_list:
  315. print "=============================="
  316. print "Listing last tracked captchas:"
  317. print "==============================\n"
  318. top = 'inputs/'
  319. tracked_captchas = []
  320. for root, dirs, files in os.walk(top, topdown=False):
  321. for name in files:
  322. path = os.path.relpath(os.path.join(root, name))
  323. if self.os_sys == "Windows": #check for win32 sys
  324. atime = os.path.getatime(path)
  325. else:
  326. date = os.stat(path)
  327. atime = time.ctime(date.st_atime)
  328. tracked_captchas.append([atime,str(" + "+name),str(" |-> "+path)])
  329. tracked_captchas=sorted(tracked_captchas,key=lambda x:x[0]) # sorted by accessed time
  330. ca = 0 # to control max number of results
  331. for t in tracked_captchas:
  332. ca = ca + 1
  333. print "-------------------------"
  334. for c in t:
  335. if ca < 26:
  336. print c
  337. else:
  338. break
  339. print "-------------------------"
  340. print "\n[Info] List end...\n"
  341. return
  342. captchas = self.try_running(self.get_attack_captchas, "\nInternal error getting -captchas-. look at the end of this Traceback.")
  343. captchas = self.sanitize_captchas(captchas)
  344. captchas2track = captchas
  345. if self.isurl == 1 and (options.train or options.crack):
  346. if options.proxy:
  347. captchas = self.remote(captchas, options.proxy)
  348. else:
  349. captchas = self.remote(captchas, "")
  350. if options.verbose:
  351. print "[-] Connection data:"
  352. out = self.optionCurl.print_options()
  353. print '-'*45
  354. #step 0: track
  355. if options.track:
  356. if options.s_num:
  357. num_tracks = int(options.s_num) # tracking number defined by user
  358. else:
  359. num_tracks = int(5) # default track connections
  360. if options.proxy:
  361. self.try_running(self.track, "\nInternal problems tracking: ", (captchas2track, options.proxy, num_tracks))
  362. else:
  363. self.try_running(self.track, "\nInternal problems tracking: ", (captchas2track, "", num_tracks))
  364. #step 1: train
  365. if options.train:
  366. try:
  367. if len(captchas) == 1:
  368. for captcha in captchas:
  369. if captcha is None:
  370. print "\n[Error] Applying OCR algorithm... Is that captcha supported?\n"
  371. else:
  372. print "Target:", options.train
  373. print "=======\n"
  374. self.try_running(self.train, "\nInternal problems training: ", (captchas))
  375. else:
  376. for captcha in captchas:
  377. if len(captchas) > 1 and captcha is None:
  378. pass
  379. else:
  380. print "Target: ", options.train
  381. self.try_running(self.train, "\nInternal problems training: ", (captchas))
  382. except:
  383. print "\n[Error] Something wrong getting captcha. Aborting...\n"
  384. if options.xml:
  385. print "[Info] You don't need export to XML on this mode... File not generated!\n"
  386. #step 2: crack
  387. if options.crack:
  388. if len(captchas) == 1:
  389. for captcha in captchas:
  390. if captcha is None:
  391. print "\n[Error] Trying to bruteforce... Is that captcha supported?\n"
  392. else:
  393. print "Target: ", options.crack
  394. print "======="
  395. self.try_running(self.crack, "\nInternal problems cracking: ", (captchas))
  396. else:
  397. for captcha in captchas:
  398. if len(captchas) > 1 and captcha is None:
  399. pass
  400. else:
  401. print "Target: ", options.crack
  402. print "======="
  403. self.try_running(self.crack, "\nInternal problems cracking: ", (captchas))
  404. if options.command:
  405. print "[Info] Executing tool connector... \n"
  406. if self.word_sug is not None:
  407. print "[Info] This is the word suggested by CIntruder: [", self.word_sug, "] \n"
  408. else:
  409. print "[Error] CIntruder hasn't any word to suggest... Handlering tool process aborted! ;(\n"
  410. sys.exit(2)
  411. if "CINT" in options.command: # check parameter CINT on command (*)
  412. # change cintruder suggested word for the users captchas input form parameter
  413. # and execute handlered tool with it.
  414. if self.word_sug is not None:
  415. cmd = options.command.replace("CINT", self.word_sug)
  416. subprocess.call(cmd, shell=True)
  417. else:
  418. cmd = options.command
  419. subprocess.call(cmd, shell=True)
  420. else:
  421. print "[Error] Captcha's parameter flag: 'CINT' is not present on:", options.command, "\n"
  422. #step 3: export
  423. if options.xml:
  424. self.try_running(self.export, "\nInternal problems exporting: ", (captchas))
  425. def sanitize_captchas(self, captchas):
  426. """
  427. Sanitize correct input of source target(s)
  428. """
  429. options = self.options
  430. all_captchas = set()
  431. for captcha in captchas:
  432. # captcha from url
  433. if "http://" in captcha or "https://" in captcha:
  434. all_captchas.add(captcha)
  435. self.isurl = 1
  436. elif self.isurl == 0: # captcha from file
  437. (root, ext) = os.path.splitext(captcha)
  438. if ext != '.gif' and ext != '.jpg' and ext != '.jpeg' and ext != '.png': #by the moment
  439. captcha = None
  440. all_captchas.add(captcha)
  441. else:
  442. all_captchas.add(captcha)
  443. self.isurl = 0
  444. return all_captchas
  445. def create_web_interface(self):
  446. from webgui import ClientThread
  447. host = '0.0.0.0'
  448. port = 9999
  449. try:
  450. webbrowser.open('http://127.0.0.1:9999', new=1)
  451. tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  452. tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  453. tcpsock.bind((host,port))
  454. while True:
  455. tcpsock.listen(4)
  456. (clientsock, (ip, port)) = tcpsock.accept()
  457. newthread = ClientThread(ip, port, clientsock)
  458. newthread.start()
  459. except (KeyboardInterrupt, SystemExit):
  460. sys.exit()
  461. if __name__ == "__main__":
  462. app = cintruder()
  463. options = app.create_options()
  464. if options:
  465. app.set_options(options)
  466. app.run()