Browse Source

Ported to Python3

epsylon 4 years ago
parent
commit
0f31f2900f

+ 0 - 60
.gitignore

@@ -1,60 +0,0 @@
-# ---> Python
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-env/
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-*.egg-info/
-.installed.cfg
-*.egg
-
-# PyInstaller
-#  Usually these files are written by a python script from a template
-#  before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*,cover
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-target/
-

File diff suppressed because it is too large
+ 0 - 231
LICENSE


+ 8 - 8
README.md

@@ -11,7 +11,7 @@ in the [LICENSE](./docs/LICENSE) file.
 
 ----------
 
- + Web:  http://cintruder.03c8.net
+ + Web:  https://cintruder.03c8.net
 
 ----------
 
@@ -19,22 +19,22 @@ in the [LICENSE](./docs/LICENSE) file.
 
 #### Installing:
 
-  CIntruder runs on many platforms.  It requires Python (2.x.y) and the following libraries:
+  CIntruder runs on many platforms.  It requires Python (3.x.x) and the following libraries:
 
-       python-pycurl - Python bindings to libcurl
-       python-libxml2 - Python bindings for the GNOME XML library
-       python-imaging - Python Imaging Library
+       python3-pycurl - Python bindings to libcurl (Python 3)
+       python3-libxml2 - Python3 bindings for the GNOME XML library
+       python3-pil - Python Imaging Library (Python3)
 
   On Debian-based systems (ex: Ubuntu), run: 
 
-       sudo apt-get install python-pycurl python-libxml2 python-imaging
+       sudo apt-get install python3-pycurl python3-libxml2 python3-pil
 
 ####  Source libs:
 
        * Python: https://www.python.org/downloads/
-       * PyCurl: http://pycurl.sourceforge.net/
+       * PyCurl: https://pycurl.sourceforge.net/
        * PyLibxml2: https://pypi.python.org/pypi/libxml2-python/
-       * Python Imaging Library (PIL): http://pythonware.com/products/pil/
+       * Python Imaging Library (PIL): https://pythonware.com/products/pil/
 
 ----------
 

+ 3 - 3
cintruder

@@ -1,9 +1,9 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 # -*- coding: iso-8859-15 -*-
 """
-This file is part of the cintruder project, http://cintruder.03c8.net
+This file is part of the cintruder project, https://cintruder.03c8.net
 
-Copyright (c) 2012/2016 psy <epsylon@riseup.net>
+Copyright (c) 2012/2020 psy <epsylon@riseup.net>
 
 cintruder is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free

+ 3 - 3
core/__init__.py

@@ -1,9 +1,9 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 # -*- coding: iso-8859-15 -*-
 """
-This file is part of the cintruder project, http://cintruder.03c8.net
+This file is part of the cintruder project, https://cintruder.03c8.net
 
-Copyright (c) 2012/2016 psy <epsylon@riseup.net>
+Copyright (c) 2012/2020 psy <epsylon@riseup.net>
 
 cintruder is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free

+ 23 - 23
core/crack.py

@@ -1,9 +1,9 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 # -*- coding: iso-8859-15 -*-
 """
-This file is part of the cintruder project, http://cintruder.03c8.net
+This file is part of the cintruder project, https://cintruder.03c8.net
 
-Copyright (c) 2012/2019 psy <epsylon@riseup.net>
+Copyright (c) 2012/2020 psy <epsylon@riseup.net>
 
 cintruder is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -25,15 +25,15 @@ import shutil
 class VectorCompare:
     def magnitude(self, concordance):
         total = 0
-        for word, count in concordance.iteritems():
+        for word, count in concordance.items():
             # print concordance 
             total += count ** 2
         return math.sqrt(total)
 
     def relation(self, concordance1, concordance2):
         topvalue = 0
-        for word, count in concordance1.iteritems():
-            if concordance2.has_key(word):
+        for word, count in concordance1.items():
+            if word in concordance2:
                 topvalue += count * concordance2[word]
         return topvalue / (self.magnitude(concordance1) * self.magnitude(concordance2))
 
@@ -70,11 +70,11 @@ class CIntruderCrack(object):
  
     def crack(self, options):
         v = VectorCompare()
-        path, dirs, files = os.walk("dictionary/").next()
+        path, dirs, files = next(os.walk("dictionary/"))
         dictionary = dirs
         imageset = []
         last_letter = None
-        print "\n[Info] Loading dictionary...\n"
+        print("[Info] Loading dictionary...\n")
         for letter in dictionary:
             for img in os.listdir('dictionary/'+letter):
                 temp = []
@@ -86,7 +86,7 @@ class CIntruderCrack(object):
             im2 = Image.new("P", im.size, 255)
             im = im.convert("P")
         except:
-            print "\nError during cracking!. Is that captcha supported?\n"
+            print("[Error] Fail during cracking!. Is that captcha supported?\n")
             if os.path.exists('core/images/previews'):
                 shutil.rmtree('core/images/previews') # remove last OCR
             return
@@ -130,35 +130,35 @@ class CIntruderCrack(object):
             im3 = im2.crop((letter[0], 0, letter[1], im2.size[1]))
             guess = []
             for image in imageset:
-                for x, y in image.iteritems():
+                for x, y in image.items():
                     if len(y) != 0:
                         guess.append(( v.relation(y[0], self.buildvector(im3)), x))
             guess.sort(reverse=True)
             word_per = guess[0][0] * 100
             if str(word_per) == "100.0":
-                print "Image position   :", countid
-                print "Broken Percent   :", int(round(float(word_per))), "%", "[+CRACKED!]"
+                print("Image position   : "+ str(countid))
+                print("Broken Percent   : "+ str(int(round(float(word_per))))+ "%"+ " [ FULL CRACKED!!! ]")
                 words[countid] = guess[0][1]
             else:
-                print "Image position   :", countid
-                print "Broken Percent   :", "%.4f" % word_per, "%"
+                print("Image position   : "+ str(countid))
+                print("Broken Percent   : %.4f" % word_per+ "%")
                 words[countid] = "_"
-            print "Word suggested   :", guess[0][1]
-            print "-------------------"
+            print("Word suggested   : "+str(guess[0][1]))
+            print("-------------------")
             if word_sug == None:
                 word_sug = str(guess[0][1])
             else:
                 word_sug = word_sug + str(guess[0][1])
             count += 1
             countid = countid + 1
-        print "\n========================================"
+        print("\n========================================")
         if options.verbose:
-            print "[Info] Elapsed OCR time :", elapsed
-            print "========================================"
+            print("[Info] Elapsed OCR time : "+ str(elapsed))
+            print("========================================")
         if word_sug is None:
-            print "Suggested Solution: ", "[ No idea!. Try to add more images to your dictionary/]"
+            print("Suggested Solution: [ No idea!. Try to add more images to your dictionary/ ]")
         else:
-            print "Cracked Words: ", words.values()
-            print "Suggested Solution: ", "[", word_sug, "]"
-        print "========================================\n"
+            print("Cracked Words: "+ str(list(words.values())))
+            print("Suggested Solution: [ "+ str(word_sug)+ " ]")
+        print("========================================\n")
         return word_sug

+ 20 - 21
core/curl.py

@@ -1,9 +1,9 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 # -*- coding: iso-8859-15 -*-
 """
-This file is part of the cintruder project, http://cintruder.03c8.net
+This file is part of the cintruder project, https://cintruder.03c8.net
 
-Copyright (c) 2012/2016 psy <epsylon@riseup.net>
+Copyright (c) 2012/2020 psy <epsylon@riseup.net>
 
 cintruder is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -19,11 +19,7 @@ with cintruder; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import pycurl
-
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
+from io import BytesIO
 
 class CIntruderCurl(object):
     """
@@ -41,7 +37,7 @@ class CIntruderCurl(object):
         self.handle = pycurl.Curl()
         self.verbosity = 0
         self.url = self.set_url(captcha)
-        self.captcha = StringIO()
+        self.captcha = BytesIO()
         self.proxy = self.set_proxy(ignoreproxy, proxy)
         self.set_option(pycurl.SSL_VERIFYHOST, 0)
         self.set_option(pycurl.SSL_VERIFYPEER, 0)
@@ -96,7 +92,7 @@ class CIntruderCurl(object):
         """
         Set the given option.
         """
-        apply(self.handle.setopt, args)
+        self.handle.setopt(*args)
 
     def request(self):
         """
@@ -105,7 +101,7 @@ class CIntruderCurl(object):
         if self.agent:
             self.set_option(pycurl.USERAGENT, self.agent)
         if self.referer:
-            self.set_option(pycurl.REFERER, self.referer) 
+            self.set_option(pycurl.REFERER, self.referer)
         if self.proxy:
             self.set_option(pycurl.PROXY, self.proxy)
         if self.ignoreproxy:
@@ -117,11 +113,14 @@ class CIntruderCurl(object):
         self.handle.setopt(self.handle.WRITEFUNCTION, self.captcha.write)
         try:
             self.handle.perform()
-            print "[Info] Getting captcha...\n"                
+            print("\n[Info] Getting captcha...")           
             return self.captcha
-        except pycurl.error, error:
-            errno, errstr = error
-            print '\n[Error] Connection error!:', errstr, "\n"
+        except pycurl.error as error:
+            try:
+                errno, errstr = error
+            except:
+                errno, errstr = "unknown!", "unknown!"
+            print('\n[Error] Connection error... '+ str(errstr))
             return "exit"
  
     def close(self):
@@ -135,11 +134,11 @@ class CIntruderCurl(object):
         """
         Print selected options.
         """
-        print "\n[-]Verbose: active"
-        print "[-]HTTP User Agent:", self.agent
-        print "[-]HTTP Referer:", self.referer
+        print("\n[-] Verbose: active")
+        print("[-] HTTP User Agent: "+str(self.agent))
+        print("[-] HTTP Referer: "+ str(self.referer))
         if self.ignoreproxy:
-            print "[-]Proxy:", "No proxy!"
+            print("[-] Proxy: No proxy!")
         else:
-            print "[-]Proxy:", self.proxy
-        print "[-]URL:", self.url, "\n"
+            print("[-] Proxy: "+ str(self.proxy))
+        print("[-] URL: "+ str(self.url)+ "\n")

BIN
core/images/cintruder.png


File diff suppressed because it is too large
+ 1 - 0
core/images/cintruder.txt


+ 43 - 6
core/js/web.js

@@ -1,7 +1,7 @@
 /*
-This file is part of the cintruder project, http://cintruder.03c8.net
+This file is part of the cintruder project, https://cintruder.03c8.net
 
-Copyright (c) 2012/2019 psy <epsylon@riseup.net>
+Copyright (c) 2012/2020 psy <epsylon@riseup.net>
 
 cintruder is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -159,24 +159,48 @@ function SetXML() {
    }
 }
 function loadRemoteOCR(train_url){
-       document.getElementById("target_captcha_img_path").src="images/previews/last-preview.gif#"+ new Date().getTime();
+       fromDataURL('images/previews/last-preview.gif', function(enc_img) {
+       r = "data:image/gif;base64,";
+       enc_img = enc_img.replace(r, "");
+       var dec_img = atob(enc_img)
+       var img_preview = "data:image/gif;base64,"+dec_img
+       document.getElementById("target_captcha_img_path").src=img_preview;
        document.getElementById('Captcha-IN').style.display = 'block';
        document.getElementById("directory-words").src = "directory-words";
        document.getElementById("OCR-out").style.display = "block";
+ })
 }
 function loadRemoteOCRCrack(crack_url){
-       document.getElementById("target_captcha_img_path").src="images/previews/last-preview.gif#"+ new Date().getTime();
+       fromDataURL('images/previews/last-preview.gif', function(enc_img) {
+       r = "data:image/gif;base64,";
+       enc_img = enc_img.replace(r, "");
+       var dec_img = atob(enc_img)
+       var img_preview = "data:image/gif;base64,"+dec_img
+       document.getElementById("target_captcha_img_path").src=img_preview;
        document.getElementById('Captcha-IN').style.display = 'block';
+ })
 }
 function loadOCRCrack(){
-       document.getElementById("target_captcha_img_path").src="images/previews/last-preview.gif#"+ new Date().getTime();
+       fromDataURL('images/previews/last-preview.gif', function(enc_img) {
+       r = "data:image/gif;base64,";
+       enc_img = enc_img.replace(r, "");
+       var dec_img = atob(enc_img)
+       var img_preview = "data:image/gif;base64,"+dec_img
+       document.getElementById("target_captcha_img_path").src=img_preview;
        document.getElementById('Captcha-IN').style.display = 'block';
+ })
 }
 function loadOCR(){
-       document.getElementById("target_captcha_img_path").src="images/previews/last-preview.gif#"+ new Date().getTime();
+       fromDataURL('images/previews/last-preview.gif', function(enc_img) {
+       r = "data:image/gif;base64,";
+       enc_img = enc_img.replace(r, "");
+       var dec_img = atob(enc_img)
+       var img_preview = "data:image/gif;base64,"+dec_img
+       document.getElementById("target_captcha_img_path").src=img_preview;
        document.getElementById('Captcha-IN').style.display = 'block';
        document.getElementById("directory-words").src = "directory-words";
        document.getElementById("OCR-out").style.display = "block";
+ })
 }
 function TrackCaptchas(){
         if(document.getElementById("tor").checked) {
@@ -305,3 +329,16 @@ function showResults() {
          document.getElementById('Captcha-IN').style.display = 'none';
          document.getElementById('OCR-out').style.display = 'none';
 }
+function fromDataURL(url, callback) {
+         var httpRequest = new XMLHttpRequest();
+         httpRequest.onload = function() {
+         var fileReader = new FileReader();
+         fileReader.onloadend = function() {
+             callback(fileReader.result);
+         }
+             fileReader.readAsDataURL(httpRequest.response);
+         };
+         httpRequest.open('GET', url);
+         httpRequest.responseType = 'blob';
+         httpRequest.send();
+}

+ 120 - 130
core/main.py

@@ -1,9 +1,9 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 # -*- coding: iso-8859-15 -*-
 """
-This file is part of the cintruder project, http://cintruder.03c8.net
+This file is part of the cintruder project, https://cintruder.03c8.net
 
-Copyright (c) 2012/2019 psy <epsylon@riseup.net>
+Copyright (c) 2012/2020 psy <epsylon@riseup.net>
 
 cintruder is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along
 with cintruder; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
-import os, traceback, hashlib, sys, time, socket, urlparse
+import os, traceback, hashlib, sys, time, socket
 import platform, subprocess, re, webbrowser, shutil
 from core.options import CIntruderOptions
 from core.crack import CIntruderCrack
@@ -26,7 +26,11 @@ from core.ocr import CIntruderOCR
 from core.curl import CIntruderCurl
 from core.xml_export import CIntruderXML
 from core.update import Updater
-from urlparse import urlparse
+try:
+    from urlparse import urlparse
+except:
+    import urllib.request, urllib.parse, urllib.error
+    from urllib.parse import urlparse
 
 # set to emit debug messages about errors (0 = off).
 DEBUG = 0
@@ -72,40 +76,26 @@ class cintruder():
         self._webbrowser = browser
 
     def banner(self):
-        print '='*75
-        print ""
-        print "        o8%8888,    "
-        print "       o88%8888888. "
-        print "      8'-    -:8888b   "
-        print "     8'         8888  "
-        print "    d8.-=. ,==-.:888b  "
-        print "    >8 `~` :`~' d8888   "
-        print "    88         ,88888   "
-        print "    88b. `-~  ':88888  "
-        print "    888b \033[1;31m~==~\033[1;m .:88888 "
-        print "    88888o--:':::8888      "
-        print "    `88888| :::' 8888b  "
-        print "    8888^^'       8888b  "
-        print "   d888           ,%888b.   "
-        print "  d88%            %%%8--'-.  "
-        print " /88:.__ ,       _%-' ---  -  "
-        print "     '''::===..-'   =  --.  `\n"
-        print self.optionParser.description, "\n"
-        print '='*75
-
-    @classmethod
-    def try_running(cls, func, error, args=None):
-        """
-        Try running a function and print some error if it fails and exists with
-        a fatal error.
-        """
-        args = args or []
-        try:
-            return func(*args)
-        except Exception:
-            print(error, "error")
-            if DEBUG:
-                traceback.print_exc()
+        print('='*75)
+        print("")
+        print("        o8%8888,    ")
+        print("       o88%8888888. ")
+        print("      8'-    -:8888b   ")
+        print("     8'         8888  ")
+        print("    d8.-=. ,==-.:888b  ")
+        print("    >8 `~` :`~' d8888   ")
+        print("    88         ,88888   ")
+        print("    88b. `-~  ':88888  ")
+        print("    888b \033[1;31m~==~\033[1;m .:88888 ")
+        print("    88888o--:':::8888      ")
+        print("    `88888| :::' 8888b  ")
+        print("    8888^^'       8888b  ")
+        print("   d888           ,%888b.   ")
+        print("  d88%            %%%8--'-.  ")
+        print(" /88:.__ ,       _%-' ---  -  ")
+        print("     '''::===..-'   =  --.  `\n")
+        print(self.optionParser.description, "\n")
+        print('='*75)
 
     def get_attack_captchas(self):
         """
@@ -114,36 +104,35 @@ class cintruder():
         captchas = []
         options = self.options
         p = self.optionParser
-
         if options.train:
-            print('='*75)
-            print(str(p.version))
-            print('='*75)
+            print(('='*75))
+            print((str(p.version)))
+            print(('='*75))
             print("Starting to 'train'...")
-            print('='*75)
+            print(('='*75))
             captchas = [options.train]
         if options.crack:
-            print('='*75)
-            print(str(p.version))
-            print('='*75)
+            print(('='*75))
+            print((str(p.version)))
+            print(('='*75))
             print("Starting to 'crack'")
-            print('='*75)
+            print(('='*75))
             captchas = [options.crack]
         if options.track:
-            print('='*75)
-            print(str(p.version))
-            print('='*75)
+            print(('='*75))
+            print((str(p.version)))
+            print(('='*75))
             print("Tracking captchas from url...")
-            print('='*75+"\n")
-            captchas = [options.track]       
+            print(('='*75))
+            captchas = [options.track]
         return captchas
 
-    def train(self, captchas):
+    def train(self, captcha):
         """
         Learn mode:
             + Add words to the brute forcing dictionary
         """
-        self.train_captcha(captchas)
+        self.train_captcha(captcha)
 
     def train_captcha(self, captcha):
         """
@@ -155,19 +144,19 @@ class cintruder():
         options = self.options
         # step 1: applying OCR techniques
         if options.name: # with a specific OCR module
-            print "[Info] Using module: [", options.name, "]"
+            print("[Info] Loading module: [ "+ options.name + " ]\n")
             try:
                 sys.path.append('mods/%s/'%(options.name))
                 exec("from " + options.name + "_ocr" + " import CIntruderOCR") # import module
             except Exception:
-                print "\n[Error] '"+ options.name+ "' module not found!\n"
+                print("\n[Error] '"+ options.name+ "' module not found!\n")
                 return #sys.exit(2)
             if options.setids: # with a specific colour ID
                 setids = int(options.setids)
                 if setids >= 0 and setids <= 255:
                     self.optionOCR = CIntruderOCR(captcha, options)
                 else:
-                    print "\n[Error] You must enter a valid RGB colour ID number (between 0 and 255)\n"
+                    print("\n[Error] You must enter a valid RGB colour ID number (between 0 and 255)\n")
                     return #sys.exit(2)
             else:
                 self.optionOCR = CIntruderOCR(captcha, options)
@@ -177,17 +166,17 @@ class cintruder():
                 if setids >= 0 and setids <= 255:
                     self.optionOCR = CIntruderOCR(captcha, options)
                 else:
-                    print "\n[Error] You must enter a valid RGB colour ID number (between 0 and 255)\n"
+                    print("\n[Error] You must enter a valid RGB colour ID number (between 0 and 255)\n")
                     return #sys.exit(2)
             else:
                 self.optionOCR = CIntruderOCR(captcha, options)
 
-    def crack(self, captchas):
+    def crack(self, captcha):
         """
         Crack mode:
             + Brute force target's captcha against a dictionary
         """
-        self.crack_captcha(captchas)
+        self.crack_captcha(captcha)
 
     def crack_captcha(self, captcha):
         """
@@ -195,13 +184,12 @@ class cintruder():
         """
         options = self.options
         if options.name:
-            print "Loading module:", options.name
-            print "==============="
+            print("[Info] Loading module: ["+ str(options.name) + "] \n")
             try:
                 sys.path.append('mods/%s/'%(options.name))
                 exec("from " + options.name + "_crack" + " import CIntruderCrack")
             except Exception:
-                print "\n[Error] '"+ options.name+ "' module not found!\n"
+                print("\n[Error] '"+ options.name+ "' module not found!\n")
                 return #sys.exit(2)
             self.optionCrack = CIntruderCrack(captcha)
             w = self.optionCrack.crack(options)
@@ -220,8 +208,11 @@ class cintruder():
             os.mkdir("inputs/")
         for captcha in captchas:
             c = self.remote_captcha(captcha, proxy)
-            l.append(c)
-        return l
+            if c:
+                l.append(c)
+                return l
+            else:
+                return
 
     def remote_captcha(self, captcha, proxy):
         """
@@ -233,9 +224,9 @@ class cintruder():
         buf = self.optionCurl.request()
         if buf != "exit":
             m = hashlib.md5()
-            m.update(captcha)
+            m.update(captcha.encode('utf-8'))
             c = "%s.gif"%(m.hexdigest())
-            h = "inputs/" + c
+            h = "inputs/" + str(c)
             f = open(h, 'wb')
             f.write(buf.getvalue())
             f.close
@@ -251,10 +242,10 @@ class cintruder():
         if self.options.xml and not (self.options.train):
             self.optionXML = CIntruderXML(captchas)
             if self.word_sug == None:
-                print "[Info] XML NOT created!. There are not words to suggest..."
+                print("[Info] XML NOT created!. There are not words to suggest...")
             else:
                 self.optionXML.print_xml_results(captchas, self.options.xml, self.word_sug)
-                print "[Info] XML created:", self.options.xml, "\n"
+                print("[Info] XML created: "+str(self.options.xml)+ "\n")
 
     def track(self, captchas, proxy, num_tracks):
         """
@@ -280,25 +271,25 @@ class cintruder():
             self.optionCurl = CIntruderCurl(captcha, self.ignoreproxy, proxy)
             buf = self.optionCurl.request()
             if options.verbose:
-                print "\n[-]Connection data:"
+                print("\n[-]Connection data:")
                 out = self.optionCurl.print_options()
-                print '-'*45
+                print('-'*45)
             if buf != "exit":
                 m = hashlib.md5()
-                m.update("%s%s"%(time.time(), captcha))
+                m.update(captcha.encode('utf-8'))
                 h = "inputs/%s/%s.gif"%(self.domain, m.hexdigest())
                 f = open(h, 'wb')
                 f.write(buf.getvalue())
                 f.close
                 buf.close
-                print "[Info] Saved:", h
-                print "------------"
+                print("[Info] Saved: "+ str(h))
+                print("------------")
             i=i+1
         if buf != "exit":
-            print "\n================="
-            print "Tracking Results:"
-            print "================="
-            print "\nNumber of tracked captchas: [", num_tracks, "] \n"
+            print("\n=================")
+            print("Tracking Results:")
+            print("=================")
+            print("\nNumber of tracked captchas: [ "+ str(num_tracks)+" ] \n")
 
     def run(self, opts=None):
         """ 
@@ -319,17 +310,17 @@ class cintruder():
                 print("\nTrying to update automatically to the latest stable version\n")
                 Updater() 
             except:
-                print "Not any .git repository found!\n"
-                print "="*30
-                print "\nTo have working this feature, you should clone CIntruder with:\n"
-                print "$ git clone %s" % self.GIT_REPOSITORY
-                print "\nAlso you can try this other mirror:\n"
-                print "$ git clone %s" % self.GIT_REPOSITORY2 + "\n"
+                print("Not any .git repository found!\n")
+                print("="*30)
+                print("\nTo have working this feature, you should clone CIntruder with:\n")
+                print("$ git clone %s" % self.GIT_REPOSITORY)
+                print("\nAlso you can try this other mirror:\n")
+                print("$ git clone %s" % self.GIT_REPOSITORY2 + "\n")
         #step 0: list output results and get captcha targets
         if options.listmods:
-            print "====================================="
-            print "Listing specific OCR exploit modules:"
-            print "=====================================\n"
+            print("=====================================")
+            print("Listing specific OCR exploit modules:")
+            print("=====================================\n")
             top = 'mods/'
             for root, dirs, files in os.walk(top, topdown=False):
                 for name in files:
@@ -339,12 +330,12 @@ class cintruder():
                         else:
                             subprocess.call("cat %s/%s"%(root, name), shell=True)
 
-            print "\n[Info] List end...\n"
+            print("\n[Info] List end...\n")
             return
         if options.track_list:
-            print "=============================="
-            print "Listing last tracked captchas:"
-            print "==============================\n"
+            print("==============================")
+            print("Listing last tracked captchas:")
+            print("==============================\n")
             top = 'inputs/'
             tracked_captchas = []
             for root, dirs, files in os.walk(top, topdown=False):
@@ -360,16 +351,16 @@ class cintruder():
             ca = 0 # to control max number of results
             for t in tracked_captchas:
                 ca = ca + 1
-                print "-------------------------"
+                print("-------------------------")
                 for c in t:
                     if ca < 26:
-                        print c
+                        print(c)
                     else:
                         break
-                print "-------------------------"
-            print "\n[Info] List end...\n"
+                print("-------------------------")
+            print("\n[Info] List end...\n")
             return 
-        captchas = self.try_running(self.get_attack_captchas, "\nInternal error getting -captchas-. look at the end of this Traceback.")
+        captchas = self.get_attack_captchas()
         captchas = self.sanitize_captchas(captchas)
         captchas2track = captchas
         if self.isurl == 1 and (options.train or options.crack):
@@ -378,9 +369,9 @@ class cintruder():
             else:
                 captchas = self.remote(captchas, "")
             if options.verbose:
-                print "[-] Connection data:"
+                print("\n[-] Connection data:")
                 out = self.optionCurl.print_options()
-                print '-'*45
+                print('-'*45)
         #step 0: track
         if options.track:
             if options.s_num:
@@ -388,59 +379,56 @@ class cintruder():
             else:
                 num_tracks = int(5) # default track connections
             if options.proxy:
-                self.try_running(self.track, "\nInternal problems tracking: ", (captchas2track, options.proxy, num_tracks))
+                self.track(captchas2track, options.proxy, num_tracks)
             else:
-                self.try_running(self.track, "\nInternal problems tracking: ", (captchas2track, "", num_tracks))
+                self.track(captchas2track, "", num_tracks)
         #step 1: train
         if options.train:
             try:
                 if len(captchas) == 1:
                     for captcha in captchas:
                         if captcha is None:
-                            print "\n[Error] Applying OCR algorithm... Is that captcha supported?\n"
+                            print("\n[Error] Applying OCR algorithm... Is that captcha supported?\n")
                             if os.path.exists('core/images/previews'):
                                 shutil.rmtree('core/images/previews') # remove last OCR
                         else:
-                            print "Target:", options.train
-                            print "=======\n"
-                            self.try_running(self.train, "\nInternal problems training: ", (captchas))   
+                            print("\n[Info] Target: "+ options.train+"\n")
+                            self.train(captcha)
                 else:
                     for captcha in captchas:
                         if len(captchas) > 1 and captcha is None:
                             pass
                         else:
-                            print "Target: ", options.train
-                            self.try_running(self.train, "\nInternal problems training: ", (captchas))
+                            print("\n[Info] Target: "+ options.train+"\n")
+                            self.train(captcha)
             except:
-                print "\n[Error] Something wrong getting captcha. Aborting...\n"
+                print("[Error] Something wrong getting captcha. Aborting...\n")
             if options.xml:
-                print "[Info] You don't need export to XML on this mode... File not generated!\n"
+                print("[Info] You don't need export to XML on this mode... File not generated!\n")
         #step 2: crack
         if options.crack:
             if len(captchas) == 1:
                 for captcha in captchas:
                     if captcha is None:
-                        print "\n[Error] Trying to bruteforce... Is that captcha supported?\n"
+                        print("\n[Error] Trying to bruteforce... Is that captcha supported?\n")
                         if os.path.exists('core/images/previews'):
                             shutil.rmtree('core/images/previews') # remove last OCR
                     else:
-                        print "Target: ", options.crack
-                        print "======="
-                        self.try_running(self.crack, "\nInternal problems cracking: ", (captchas))
+                        print("\n[Info] Target: "+ options.crack+"\n")
+                        self.crack(captcha)
             else:
                 for captcha in captchas:
                     if len(captchas) > 1 and captcha is None:
                         pass
                     else:
-                        print "Target: ", options.crack
-                        print "======="
-                        self.try_running(self.crack, "\nInternal problems cracking: ", (captchas))
+                        print("\n[Info] Target: "+ options.crack+"\n")
+                        self.crack(captcha)
             if options.command:
-                print "[Info] Executing tool connector... \n"
+                print("[Info] Executing tool connector... \n")
                 if self.word_sug is not None:
-                    print "[Info] This is the word suggested by CIntruder: [", self.word_sug, "] \n"
+                    print("[Info] This is the word suggested by CIntruder: [ "+ str(self.word_sug)+ " ] \n")
                 else:
-                    print "[Error] CIntruder hasn't any word to suggest... Handlering tool process aborted! ;(\n"
+                    print("[Error] CIntruder hasn't any word to suggest... Handlering tool process aborted! ;(\n")
                     sys.exit(2)
                 if "CINT" in options.command: # check parameter CINT on command (*)
                     # change cintruder suggested word for the users captchas input form parameter
@@ -452,10 +440,10 @@ class cintruder():
                         cmd = options.command
                         subprocess.call(cmd, shell=True)
                 else:
-                    print "[Error] Captcha's parameter flag: 'CINT' is not present on:", options.command, "\n"
+                    print("[Error] Captcha's parameter flag: 'CINT' is not present on: "+ str(options.command)+ "\n")
         #step 3: export
         if options.xml:
-            self.try_running(self.export, "\nInternal problems exporting: ", (captchas))
+            self.export(captchas)
 
     def sanitize_captchas(self, captchas):
         """
@@ -470,7 +458,7 @@ class cintruder():
                 self.isurl = 1
             elif self.isurl == 0: # captcha from file
                 (root, ext) = os.path.splitext(captcha)       
-                if ext != '.gif' and ext != '.jpg' and ext != '.jpeg' and ext != '.png': #by the moment                    
+                if ext != '.gif' and ext != '.jpg' and ext != '.jpeg' and ext != '.png': # by the moment                    
                     captcha = None
                     all_captchas.add(captcha)
                 else:
@@ -479,18 +467,20 @@ class cintruder():
         return all_captchas
 
     def create_web_interface(self):
-        from webgui import ClientThread
+        # launch webserver+gui
+        from .webgui import ClientThread
+        import webbrowser
         host = '0.0.0.0'
         port = 9999
-        try: 
+        try:
             webbrowser.open('http://127.0.0.1:9999', new=1)
             tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-	    tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-	    tcpsock.bind((host,port))
-	    while True:
-	        tcpsock.listen(4)
-	        (clientsock, (ip, port)) = tcpsock.accept()
-	        newthread = ClientThread(ip, port, clientsock)
+            tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            tcpsock.bind((host,port))
+            while True:
+                tcpsock.listen(4)
+                (clientsock, (ip, port)) = tcpsock.accept()
+                newthread = ClientThread(ip, port, clientsock)
                 newthread.start()
         except (KeyboardInterrupt, SystemExit):
             sys.exit()

+ 29 - 30
core/ocr.py

@@ -1,9 +1,9 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 # -*- coding: iso-8859-15 -*-
 """
-This file is part of the cintruder project, http://cintruder.03c8.net
+This file is part of the cintruder project, https://cintruder.03c8.net
 
-Copyright (c) 2012/2016 psy <epsylon@riseup.net>
+Copyright (c) 2012/2020 psy <epsylon@riseup.net>
 
 cintruder is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -51,33 +51,33 @@ class CIntruderOCR(object):
             im2 = Image.new("P", im.size, 255)
             im = im.convert("P")
         except:
-            print "Error during OCR process... Is that captcha supported?\n"
+            print("[Error] Fail during OCR process... Is that captcha supported?\n")
             return
         colourid = []
         try: # extract colour histogram
             hist = im.histogram()
         except:
-            print "\n[Error] Something wrong extracting histogram. Aborting...\n"
+            print("[Error] Something wrong extracting histogram. Aborting...\n")
             return
         values = {}
         for i in range(256):
             values[i] = hist[i]
         if options.verbose:
-            print "\n[Info] Extracting advanced OCR info..."
-            print "\n=============================" 
-            print "Image Histogram (order by >):"
-            print "============================="
+            print("[Info] Extracting advanced OCR info...")
+            print("\n=============================") 
+            print("Image Histogram (order by >):")
+            print("=============================")
         count = 0
-        for j, k in sorted(values.items(), key=itemgetter(1), reverse=True)[:10]:
+        for j, k in sorted(list(values.items()), key=itemgetter(1), reverse=True)[:10]:
             colourid.append(j)  
             if options.verbose:
                 count = count + 1
                 if count == 1: # first is background
-                    print "Colour ID: [", j, "] -> Total pixels:", k, "[Background]"
+                    print("Colour ID: [ "+ str(j)+ " ] -> Total pixels: "+ str(k)+ " [Background]")
                 else:
-                    print "Colour ID: [", j, "] -> Total pixels:", k
+                    print("Colour ID: [ "+ str(j)+ " ] -> Total pixels: "+ str(k))
         if options.verbose:
-            print ""
+            print("")
         temp = {}
         for x in range(im.size[1]):
             for y in range(im.size[0]):
@@ -113,27 +113,26 @@ class CIntruderOCR(object):
         for letter in letters:
             m = hashlib.md5()
             im3 = im2.crop(( letter[0], 0, letter[1], im2.size[1] ))
-            m.update("%s%s"%(time.time(), count))
             im3.save("outputs/words/%s.gif"%(m.hexdigest()))
             im3.save("core/images/previews/ocr/%s.gif"%(m.hexdigest()))
             count += 1
-        print "[Info] Processing captcha/image with OCR algorithms. Please wait...\n"
-        print "================="
-        print "Training Results:"
-        print "================="
-        print "[Info] Number of 'symbols' found: [", count, "]"
+        print("[Info] Processing captcha/image with OCR algorithms. Please wait...\n")
+        print("=================")
+        print("Training Results:")
+        print("=================")
+        print("\n[Info] Number of 'symbols' found: "+ str(count)+"\n")
         if count == 0:
-            print "\nOuch!. Looks like this captcha is resisting to our OCR methods... by the moment ;-)\n"
-            print "Try this...\n" 
-            print "    1) Check colour's ID values and quantity of pixels of each by using verbose" 
-            print "    2) Set different ID values to your OCR configuration and try it again"
-            print "    3) Try to apply some image filters (ex: B/W) manually with an editor (ex: GIMP) to your target"
-            print "    4) Maybe there is a module that works correctly for this captcha...\n"
-            print "------------\n"
+            print("\nOuch!. Looks like this captcha is resisting to our OCR methods... by the moment ;-)\n")
+            print("Try this...\n") 
+            print("    1) Check colour's ID values and quantity of pixels of each by using verbose") 
+            print("    2) Set different ID values to your OCR configuration and try it again")
+            print("    3) Try to apply some image filters (ex: B/W) manually with an editor (ex: GIMP) to your target")
+            print("    4) Maybe there is a module that works correctly for this captcha...\n")
+            print("------------\n")
         else:
-            path, dirs, files = os.walk("outputs/words/").next()
+            path, dirs, files = next(os.walk("outputs/words/"))
             file_count = str(len(files))
-            print "[Info] Generated [ "+ file_count+ " ] OCR images here:", "outputs/words/\n"
+            print ("[Info] Generated [ "+ file_count+ " ] OCR images here: outputs/words/\n")
             if options.verbose:
                 # checking for platform to list new words added to dictionary
                 os_sys = platform.system()
@@ -141,8 +140,8 @@ class CIntruderOCR(object):
                     subprocess.call("dir outputs/words/", shell=True)
                 else:
                     subprocess.call("ls outputs/words/", shell=True)
-                print ""
-            print "Now move each (human-recognized) OCR image to the correct folder on: dictionary/\n"
+                print("")
+            print("Now move each (human-recognized) OCR image to the correct folder on: dictionary/\n")
 
 if __name__ == "__main__":
     if sys.argv[1:]:

+ 31 - 31
core/options.py

@@ -1,9 +1,9 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 # -*- coding: iso-8859-15 -*-
 """
-This file is part of the cintruder project, http://cintruder.03c8.net
+This file is part of the cintruder project, https://cintruder.03c8.net
 
-Copyright (c) 2012/2019 psy <epsylon@riseup.net>
+Copyright (c) 2012/2020 psy <epsylon@riseup.net>
 
 cintruder is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -25,7 +25,7 @@ class CIntruderOptions(optparse.OptionParser):
         optparse.OptionParser.__init__(self, 
                            description='Captcha Intruder - OCR Bruteforcing Toolkit - by psy',
                            prog='cintruder.py',
-			   version='\nCIntruder v0.3.1 - 2019 - (GPLv3.0) -> by psy\n',
+			   version='\nCIntrud3r v0.4 - 2012/2020 - (GPLv3.0) -> by psy\n',
                            usage= '\n\ncintruder [OPTIONS]')
         self.add_option("-v", "--verbose", action="store_true", dest="verbose", help="active verbose mode output results")
         self.add_option("--proxy", action="store", dest="proxy", help="use proxy server (tor: http://localhost:8118)")
@@ -58,32 +58,32 @@ class CIntruderOptions(optparse.OptionParser):
         (options, args) = self.parse_args(user_args)
         options.args = args
         if (not options.train and not options.crack and not options.track and not options.track_list and not options.listmods and not options.web and not options.update):
-            print '='*75
-            print ""
-            print "        o8%8888,    "
-            print "       o88%8888888. " 
-            print "      8'-    -:8888b   "
-            print "     8'         8888  "
-            print "    d8.-=. ,==-.:888b  "
-            print "    >8 `~` :`~' d8888   "
-            print "    88         ,88888   "
-            print "    88b. `-~  ':88888  "
-            print "    888b \033[1;31m~==~\033[1;m .:88888 "
-            print "    88888o--:':::8888      "
-            print "    `88888| :::' 8888b  "
-            print "    8888^^'       8888b  "
-            print "   d888           ,%888b.   "
-            print "  d88%            %%%8--'-.  "
-            print " /88:.__ ,       _%-' ---  -  "
-            print "     '''::===..-'   =  --.  `\n"
-            print  self.description, "\n"
-            print '='*75, "\n"
-            print " * Project site: http://cintruder.03c8.net", "\n"
-            print " * IRC: irc.freenode.net -> #cintruder", "\n"
-            print " * Mailing list: cintruder-users@lists.sf.net", "\n"
-            print '='*75
-            print "\n -> For HELP use: -h or --help"
-            print "\n -> For WEB interface use: --gui\n"
-            print '='*55, "\n"
+            print('='*75)
+            print("")
+            print("        o8%8888,    ")
+            print("       o88%8888888. ") 
+            print("      8'-    -:8888b   ")
+            print("     8'         8888  ")
+            print("    d8.-=. ,==-.:888b  ")
+            print("    >8 `~` :`~' d8888   ")
+            print("    88         ,88888   ")
+            print("    88b. `-~  ':88888  ")
+            print("    888b \033[1;31m~==~\033[1;m .:88888 ")
+            print("    88888o--:':::8888      ")
+            print("    `88888| :::' 8888b  ")
+            print("    8888^^'       8888b  ")
+            print("   d888           ,%888b.   ")
+            print("  d88%            %%%8--'-.  ")
+            print(" /88:.__ ,       _%-' ---  -  ")
+            print("     '''::===..-'   =  --.  `\n")
+            print(self.description, "\n")
+            print('='*75, "\n")
+            print(" * Project site: https://cintruder.03c8.net", "\n")
+            print(" * IRC: irc.freenode.net -> #cintruder", "\n")
+            print(" * Mailing list: cintruder-users@lists.sf.net", "\n")
+            print('='*75)
+            print("\n -> For HELP use: -h or --help")
+            print("\n -> For WEB interface use: --gui\n")
+            print('='*55, "\n")
             return False
         return options

+ 12 - 12
core/update.py

@@ -1,9 +1,9 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 # -*- coding: iso-8859-15 -*-
 """
-This file is part of the cintruder project, http://cintruder.03c8.net
+This file is part of the cintruder project, https://cintruder.03c8.net
 
-Copyright (c) 2012/2016/2018 psy <epsylon@riseup.net>
+Copyright (c) 2012/2020 psy <epsylon@riseup.net>
 
 cintruder is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -31,16 +31,16 @@ class Updater(object):
         GIT_REPOSITORY2 = "https://github.com/epsylon/cintruder"
         rootDir = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', ''))
         if not os.path.exists(os.path.join(rootDir, ".git")):
-            print "Not any .git repository found!\n"
-            print "="*30
-            print "\nTo have working this feature, you should clone CIntruder with:\n"
-            print "$ git clone %s" % GIT_REPOSITORY
-            print "\nAlso you can try this other mirror:\n"
-            print "$ git clone %s" % GIT_REPOSITORY2 + "\n"
+            print("Not any .git repository found!\n")
+            print("="*30)
+            print("\nTo have working this feature, you should clone CIntruder with:\n")
+            print("$ git clone %s" % GIT_REPOSITORY)
+            print("\nAlso you can try this other mirror:\n")
+            print("$ git clone %s" % GIT_REPOSITORY2 + "\n")
         else:
             checkout = execute("git checkout . && git pull", shell=True, stdout=PIPE, stderr=PIPE).communicate()[0]
-            print checkout
+            print(checkout)
             if not "Already up-to-date" in checkout:
-                print "Congratulations!! CIntruder has been updated... ;-)\n"
+                print("Congratulations!! CIntruder has been updated... ;-)\n")
             else:
-                print "Your CIntruder doesn't need to be updated... ;-)\n"
+                print("Your CIntruder doesn't need to be updated... ;-)\n")

File diff suppressed because it is too large
+ 50 - 17
core/webgui.py


+ 4 - 4
core/xml_export.py

@@ -1,9 +1,9 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 # -*- coding: iso-8859-15 -*-
 """
-This file is part of the cintruder project, http://cintruder.03c8.net
+This file is part of the cintruder project, https://cintruder.03c8.net
 
-Copyright (c) 2012/2016 psy <epsylon@riseup.net>
+Copyright (c) 2012/2020 psy <epsylon@riseup.net>
 
 cintruder is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -36,7 +36,7 @@ class CIntruderXML(object):
         root = xml.Element("report")
         hdr = xml.SubElement(root, "header")
         title = xml.SubElement(hdr, "title")
-        title.text = "Captcha Intruder [http://cintruder.03c8.net] Report: " + str(datetime.datetime.now())
+        title.text = "Captcha Intruder [https://cintruder.03c8.net] Report: " + str(datetime.datetime.now())
         target = xml.SubElement(root, "target")
         captcha = xml.SubElement(target, "captcha")
         words = xml.SubElement(captcha, "word")

+ 47 - 0
docs/.github/CODE_OF_CONDUCT.md

@@ -0,0 +1,47 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project leader at epsylon@riseup.net. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
+

File diff suppressed because it is too large
+ 36 - 0
docs/.github/CONTRIBUTING.md


+ 36 - 0
docs/.github/ISSUE_TEMPLATE/bug_report.md

@@ -0,0 +1,36 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: bug report
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+1. Run '...'
+2. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Running environment:**
+ - cintruder version [e.g. 0.1]
+ - Installation method [e.g. git]
+ - Operating system: [e.g. Debian 4.19.16-1~bpo9+1 (2019-02-07) ]
+ - Python version [e.g. 3.7]
+
+**Error details:**
+ - Relevant console output [if any]
+ - Exception traceback [if any]
+
+**Additional context**
+Add any other context about the problem here.
+
+---

+ 22 - 0
docs/.github/ISSUE_TEMPLATE/feature_request.md

@@ -0,0 +1,22 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: feature request
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
+
+---

+ 43 - 0
docs/AUTHOR

@@ -0,0 +1,43 @@
+========================
+
+ nick: psy (epsylon)
+  
+  <epsylon@riseup.net> 
+
+ web: https://03c8.net
+
+=======================
+
+ code:
+
+ - https://code.03c8.net/epsylon
+ - https://github.com/epsylon
+
+=======================
+
+ software/projects:
+
+ - AnonTwi: Tool for OAuth2 applications (such as: GNUSocial, Twitter) that provides different layers of privacy/encryption.
+ - Bordercheck: Tool to visualize 'real-time' on a world map the geolocation of data when surfing the web.
+ - CIntruder: Tool to bypass captchas using OCR (Optical Character Recognition) bruteforcing methods.
+ - Collatz: Tool to simulate the Collatz's conjeture.
+ - DieKunstDerFuge: Video on different topics related to hacktivism recorded during 2013 from an intimate narrative perspective.
+ - ECOin: Decentralized key/value registration and transfer system based on Bitcoin technology (a cryptocurrency).
+ - Euler-Bricks: Tool to search for Euler's "bricks".
+ - Goldbach: Tool to simulate the Goldbach's conjeture.
+ - Lorea: Social networking autonomous project to build a distributed, encrypted and federated network.
+ - Orb: Tool for massive footprinting.
+ - pArAnoIA-Browser: Tool designed to surf the Internet using some "paranoic" methods.
+ - Propagare: Tool for extraction, organization and semantic analysis of newspapers.
+ - PyAISnake: Tool to train AI models on solve spatial problems through the classic video game "snake".
+ - PyDog4Apache: Tool to sneak logs from Apache web server.
+ - UFONet: Denial of Service [DDoS & DoS attacks] Toolkit (a botnet of botnets).
+ - XSSer: Automatic -framework- to detect, exploit and report XSS vulnerabilities.
+
+=======================
+
+ BTC: 
+
+  19aXfJtoYJUoXEZtjNwsah2JKN9CK5Pcjw
+
+========================

+ 7 - 1
docs/CHANGELOG

@@ -1,7 +1,13 @@
 ================================================================
-Changelog: CIntruder v0.3 (cintruder.03c8.net)
+Changelog: CIntruder v0.4 (https://cintruder.03c8.net)
 ==============================
 
+===================
+January 6, 2020:
+===================
+
+- Ported to Python3
+
 ===================
 January 17, 2019:
 ===================

+ 46 - 0
docs/COMMITMENT

@@ -0,0 +1,46 @@
+GPL Cooperation Commitment
+Version 1.0
+
+Before filing or continuing to prosecute any legal proceeding or claim
+(other than a Defensive Action) arising from termination of a Covered
+License, we commit to extend to the person or entity ('you') accused
+of violating the Covered License the following provisions regarding
+cure and reinstatement, taken from GPL version 3. As used here, the
+term 'this License' refers to the specific Covered License being
+enforced.
+
+    However, if you cease all violation of this License, then your
+    license from a particular copyright holder is reinstated (a)
+    provisionally, unless and until the copyright holder explicitly
+    and finally terminates your license, and (b) permanently, if the
+    copyright holder fails to notify you of the violation by some
+    reasonable means prior to 60 days after the cessation.
+
+    Moreover, your license from a particular copyright holder is
+    reinstated permanently if the copyright holder notifies you of the
+    violation by some reasonable means, this is the first time you
+    have received notice of violation of this License (for any work)
+    from that copyright holder, and you cure the violation prior to 30
+    days after your receipt of the notice.
+
+We intend this Commitment to be irrevocable, and binding and
+enforceable against us and assignees of or successors to our
+copyrights.
+
+Definitions
+
+'Covered License' means the GNU General Public License, version 2
+(GPLv2), the GNU Lesser General Public License, version 2.1
+(LGPLv2.1), or the GNU Library General Public License, version 2
+(LGPLv2), all as published by the Free Software Foundation.
+
+'Defensive Action' means a legal proceeding or claim that We bring
+against you in response to a prior proceeding or claim initiated by
+you or your affiliate.
+
+'We' means each contributor to this repository as of the date of
+inclusion of this file, including subsidiaries of a corporate
+contributor.
+
+This work is available under a Creative Commons Attribution-ShareAlike
+4.0 International license (https://creativecommons.org/licenses/by-sa/4.0/).

+ 9 - 9
docs/INSTALL

@@ -1,6 +1,6 @@
-============================================
-CIntruder - [cintruder.03c8.net] - 2012/2016
-============================================
+====================================================
+CIntruder - [cintruder.03c8.net] - 2012/2020
+====================================================
 
 Captcha Intruder is an automatic pentesting tool to bypass captchas.
 
@@ -8,17 +8,17 @@ Captcha Intruder is an automatic pentesting tool to bypass captchas.
 How-to INSTALL:
 ===================
 
-CIntruder runs on many platforms.  It requires Python and the following libraries:
+CIntruder runs on many platforms.  It requires Python (3.x.x) and the following libraries:
 
-    - python-pycurl  - Python bindings to libcurl
-    - python-libxml2 - Python bindings for the GNOME XML library
-    - python-imaging - Python Imaging Library
+    - python3-pycurl - Python bindings to libcurl (Python 3)
+    - python3-libxml2 - Python3 bindings for the GNOME XML library
+    - python3-pil - Python Imaging Library (Python3)
 
 =========
 
 On Debian-based systems (ex: Ubuntu), run: 
 
-    sudo apt-get install python-pycurl python-libxml2 python-imaging
+    sudo apt-get install python3-pycurl python3-libxml2 python3-pil
 
 =========
 
@@ -32,7 +32,7 @@ Or write directly to:
 
 Website: 
 
-    - http://cintruder.03c8.net/
+    - https://cintruder.03c8.net/
 
 =========
 

+ 3 - 3
mods/easy/__init__.py

@@ -1,9 +1,9 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 # -*- coding: iso-8859-15 -*-
 """
-This file is part of the cintruder project, http://cintruder.03c8.net
+This file is part of the cintruder project, https://cintruder.03c8.net
 
-Copyright (c) 2012/2016 psy <epsylon@riseup.net>
+Copyright (c) 2012/2020 psy <epsylon@riseup.net>
 
 cintruder is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free

+ 23 - 23
mods/easy/easy_crack.py

@@ -1,9 +1,9 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 # -*- coding: iso-8859-15 -*-
 """
-This file is part of the cintruder project, http://cintruder.03c8.net
+This file is part of the cintruder project, https://cintruder.03c8.net
 
-Copyright (c) 2012/2016 psy <epsylon@riseup.net>
+Copyright (c) 2012/2020 psy <epsylon@riseup.net>
 
 cintruder is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -25,15 +25,15 @@ import shutil
 class VectorCompare:
     def magnitude(self, concordance):
         total = 0
-        for word, count in concordance.iteritems():
+        for word, count in concordance.items():
             # print concordance 
             total += count ** 2
         return math.sqrt(total)
 
     def relation(self, concordance1, concordance2):
         topvalue = 0
-        for word, count in concordance1.iteritems():
-            if concordance2.has_key(word):
+        for word, count in concordance1.items():
+            if word in concordance2:
                 topvalue += count * concordance2[word]
         return topvalue / (self.magnitude(concordance1) * self.magnitude(concordance2))
 
@@ -71,11 +71,11 @@ class CIntruderCrack(object):
  
     def crack(self, options):
         v = VectorCompare()
-        path, dirs, files = os.walk(self.dictionary_path).next()
+        path, dirs, files = next(os.walk(self.dictionary_path))
         dictionary = dirs
         imageset = []
         last_letter = None
-        print "\n[Info] Loading dictionary...\n"
+        print("\n[Info] Loading dictionary...\n")
         for letter in dictionary:
             for img in os.listdir(self.dictionary_path+letter):
                 temp = []
@@ -87,7 +87,7 @@ class CIntruderCrack(object):
             im2 = Image.new("P", im.size, 255)
             im = im.convert("P")
         except:
-            print "\nError during cracking!. Is that captcha supported?\n"
+            print("\nError during cracking!. Is that captcha supported?\n")
             return
         temp = {}
         for x in range(im.size[1]):
@@ -125,35 +125,35 @@ class CIntruderCrack(object):
             im3 = im2.crop((letter[0], 0, letter[1], im2.size[1]))
             guess = []
             for image in imageset:
-                for x, y in image.iteritems():
+                for x, y in image.items():
                     if len(y) != 0:
                         guess.append(( v.relation(y[0], self.buildvector(im3)), x))
             guess.sort(reverse=True)
             word_per = guess[0][0] * 100
             if str(word_per) == "100.0":
-                print "Image position   :", countid
-                print "Broken Percent   :", int(round(float(word_per))), "%", "[+CRACKED!]"
+                print("Image position   : "+ str(countid))
+                print("Broken Percent   : "+ str(int(round(float(word_per))))+ "%"+ " [ FULL CRACKED!!! ]")
                 words[countid] = guess[0][1]
             else:
-                print "Image position   :", countid
-                print "Broken Percent   :", "%.4f" % word_per, "%"
+                print("Image position   : "+ str(countid))
+                print("Broken Percent   : %.4f" % word_per + "%")
                 words[countid] = "_"
-            print "Word suggested   :", guess[0][1]
-            print "-------------------"
+            print("Word suggested   : "+ str(guess[0][1]))
+            print("-------------------")
             if word_sug == None:
                 word_sug = str(guess[0][1])
             else:
                 word_sug = word_sug + str(guess[0][1])
             count += 1
             countid = countid + 1
-        print "\n========================================"
+        print("\n========================================")
         if options.verbose:
-            print "[Info] Elapsed OCR time :", elapsed
-            print "========================================"
+            print("[Info] Elapsed OCR time : "+ str(elapsed))
+            print("========================================")
         if word_sug is None:
-            print "Suggested Solution: ", "[ No idea!. Try to add more images to your dictionary/]"
+            print("Suggested Solution: [ No idea!. Try to add more images to your dictionary/ ]")
         else:
-            print "Cracked Words: ", words.values()
-            print "Suggested Solution: ", "[", word_sug, "]"
-        print "========================================\n"
+            print("Cracked Words: " +str(list(words.values())))
+            print("Suggested Solution: [ "+ str(word_sug)+ " ]")
+        print("========================================\n")
         return word_sug

+ 28 - 30
mods/easy/easy_ocr.py

@@ -1,9 +1,9 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 # -*- coding: iso-8859-15 -*-
 """
-This file is part of the cintruder project, http://cintruder.03c8.net
+This file is part of the cintruder project, https://cintruder.03c8.net
 
-Copyright (c) 2012/2016 psy <epsylon@riseup.net>
+Copyright (c) 2012/2020 psy <epsylon@riseup.net>
 
 cintruder is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -44,7 +44,6 @@ class CIntruderOCR(object):
         else:
             shutil.rmtree("core/images/previews/ocr/")
             os.mkdir("core/images/previews/ocr/")
-
         # initialize main CIntruder
         try:
             im = Image.open(captcha)
@@ -52,28 +51,28 @@ class CIntruderOCR(object):
             im2 = Image.new("P", im.size, 255)
             im = im.convert("P")
         except:
-            print "Error during OCR process!. Is that captcha supported?\n"
+            print("[Error] Fail during OCR process!. Is that captcha supported?\n")
             return
         colourid = []
         try: # extract colour histogram
             hist = im.histogram()
         except:
-            print "\n[Error] Something wrong extracting histogram. Aborting...\n"
+            print("[Error] Something wrong extracting histogram. Aborting...\n")
             return
         values = {}
         for i in range(256):
             values[i] = hist[i]
         if options.verbose:
-            print "[Info] Extracting advanced OCR info..."
-            print "\n============================="
-            print "Image Histogram (order by >):"
-            print "============================="
-        for j, k in sorted(values.items(), key=itemgetter(1), reverse=True)[:10]:
+            print("[Info] Extracting advanced OCR info...")
+            print("\n=============================")
+            print("Image Histogram (order by >):")
+            print("=============================")
+        for j, k in sorted(list(values.items()), key=itemgetter(1), reverse=True)[:10]:
             colourid.append(j)  
             if options.verbose:
-                print "Colour ID: [", j, "] -> Total pixels:", k
+                print("Colour ID: [ "+ str(j) + " ] -> Total pixels: " +str(k))
         if options.verbose:
-            print ""
+            print("")
         temp = {}
         for x in range(im.size[1]):
             for y in range(im.size[0]):
@@ -109,27 +108,26 @@ class CIntruderOCR(object):
         for letter in letters:
             m = hashlib.md5()
             im3 = im2.crop(( letter[0], 0, letter[1], im2.size[1] ))
-            m.update("%s%s"%(time.time(), count))
             im3.save("outputs/words/%s.gif"%(m.hexdigest()))
             im3.save("core/images/previews/ocr/%s.gif"%(m.hexdigest()))
             count += 1
-        print "[Info] Processing captcha/image with OCR algorithms. Please wait...\n"
-        print "================="
-        print "Training Results:"
-        print "================="
-        print "\nNumber of 'symbols' found: [", count, "]"
+        print("[Info] Processing captcha/image with OCR algorithms. Please wait...\n")
+        print("=================")
+        print("Training Results:")
+        print("=================")
+        print("\n[Info] Number of 'symbols' found: "+ str(count)+"\n")
         if count == 0:
-            print "\nOuch!. Looks like this captcha is resisting to our OCR methods... by the moment ;-)\n"
-            print "Try this...\n" 
-            print "    1) Check colour's ID values and quantity of pixels of each by using verbose" 
-            print "    2) Set different ID values to your OCR configration and try it again"
-            print "    3) Try to apply some image filters (ex: B/W) manually with an editor (ex: GIMP) to your target"
-            print "    4) Maybe this module that you are using is not working for this captcha...\n"
-            print "------------\n"
+            print("\nOuch!. Looks like this captcha is resisting to our OCR methods... by the moment ;-)\n")
+            print("Try this...\n") 
+            print("    1) Check colour's ID values and quantity of pixels of each by using verbose") 
+            print("    2) Set different ID values to your OCR configration and try it again")
+            print("    3) Try to apply some image filters (ex: B/W) manually with an editor (ex: GIMP) to your target")
+            print("    4) Maybe this module that you are using is not working for this captcha...\n")
+            print("------------\n")
         else:
-            path, dirs, files = os.walk("outputs/words/").next()
+            path, dirs, files = next(os.walk("outputs/words/"))
             file_count = str(len(files))
-            print "\n[Info] Generated [ "+ file_count+ " ] OCR images here:", "outputs/words/\n"
+            print("[Info] Generated [ "+ file_count+ " ] OCR images here: outputs/words/\n")
             if options.verbose:
                 # checking for platform to list new words added to dictionary
                 os_sys = platform.system()
@@ -137,8 +135,8 @@ class CIntruderOCR(object):
                     subprocess.call("dir outputs/words/", shell=True)
                 else:
                     subprocess.call("ls outputs/words/", shell=True)
-                print ""
-            print "Now move each (human-recognized) OCR image to the correct folder on: dictionary/\n"
+                print("")
+            print("Now move each (human-recognized) OCR image to the correct folder on: dictionary/\n")
 
 if __name__ == "__main__":
     if sys.argv[1:]: