Projects STRLCPY linuxprivchecker Commits af71ed26
🤬
  • updated to use an async tcp server for *maybe* some performance improvement

  • Loading...
  • linted committed 3 years ago
    af71ed26
    1 parent ebf99619
  • ■ ■ ■ ■ ■ ■
    privcheckerserver.py
    skipped 29 lines
    30 30   import socketserver
    31 31   from os.path import isfile
    32 32   import argparse
    33  - import multiprocessing
     33 + from concurrent.futures import ProcessPoolExecutor
    34 34   from csv import DictReader
     35 + import asyncio
     36 + from typing import List, OrderedDict, ByteString
    35 37  except Exception as e:
    36 38   print("Caught exception: {}\nAre you running with python3?".format(e))
    37 39   exit(1)
    38 40   
    39 41   
    40 42  _PORT_ = 4521
    41  -_IP_ = '0.0.0.0'
     43 +_IP_ = "0.0.0.0"
    42 44  _SEARCHSPLOIT_ = "/usr/share/exploitdb/files_exploits.csv"
    43 45   
    44  -class SearchHandler(socketserver.StreamRequestHandler):
    45  - def handle(self):
    46  - try:
    47  - print('[+] Connection from '+ self.client_address[0])
    48  - self.pool = multiprocessing.Pool(10)
    49  - for output in self.pool.imap(SearchHandler.search, iter(self.rfile.readline, b'\n')):
    50  - if output:
    51  - print(output)
    52  - self.wfile.write(output.encode() + b'\n')
    53 46   
    54  - self.pool.close()
    55  - print('[$] Closing connection from {}\n'.format(self.client_address[0]))
    56  - self.pool.join()
    57  - except Exception as e:
    58  - self.pool.terminate()
    59  - self.wfile.write('[-] Exception Caught: {}'.format(e).encode())
    60  - print("[-] Exception Caught: {}".format(e))
    61  - self.pool.join()
     47 +class SearchHandler():
     48 + def __init__(self, database) -> None:
     49 + self.db = database
    62 50   
    63  - @classmethod
    64  - def search(cls, data):
     51 + async def handle(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
     52 + remote_addr = "{}:{}".format(*writer.get_extra_info('peername'))
     53 + print("[$] Connection from {}".format(remote_addr) )
     54 + loop = asyncio.get_running_loop()
     55 + with ProcessPoolExecutor() as pool:
     56 + futures = []
     57 + while True: # this is how they do it in the docs... smh
     58 + line = await reader.readline()
     59 + if not line:
     60 + break
     61 + print("[ ] checking line: '{!r}'".format(line))
     62 + futures.append(loop.run_in_executor(pool, self.search, line))
     63 +
     64 + if not futures:
     65 + print("[-] No data received from {}".format(remote_addr))
     66 + 
     67 + done,_ = await asyncio.wait(futures)
     68 + 
     69 + for task in done:
     70 + exception = task.exception()
     71 + if exception:
     72 + print("[-] Error: {}".format(exception))
     73 + writer.write("[-] Error: {}".format(exception).encode())
     74 + else:
     75 + res = task.result()
     76 + if res:
     77 + print(res.decode())
     78 + writer.write(res)
     79 + 
     80 + print("[$] Closing connection from {}".format(remote_addr))
     81 + await writer.drain()
     82 + writer.close()
     83 + 
     84 + 
     85 + def search(self, data: ByteString) -> ByteString:
    65 86   query = data.decode().strip().split(" ")
    66  - query[-1] = query[-1][:3] #cut down on the last item which should be the version number
     87 + query[-1] = query[-1][:3] # cut down on the last item which should be the version number
    67 88   output = []
    68  - for rows in ExploitServer.exploitDatabase:
     89 + for rows in self.db:
    69 90   if all([term in rows["description"] for term in query]):
    70  - output.append('\t'.join((rows["description"], rows["file"])))
     91 + output.append("\t".join((rows["description"], rows["file"])))
    71 92   if output:
    72  - return "[ ] " + "\n".join([' '.join(query), *output])
     93 + return ("[+] {}\n".format(data.decode().strip()) + "\n".join(output)).encode()
     94 + return b''
    73 95   
    74 96   
     97 +async def start_server(ip, port, database):
     98 + handler = SearchHandler(database)
     99 + server = await asyncio.start_server(handler.handle, ip, port)
     100 + print("[+] Listening on {}:{}".format(ip, port))
    75 101   
    76  -class ExploitServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    77  - exploitDatabase = []
     102 + async with server:
     103 + await server.serve_forever()
    78 104   
    79 105   
    80 106  def main():
    81  - exploit = ExploitServer((_IP_, _PORT_), SearchHandler)
    82  - print('[ ] Starting server on port ' + str(_PORT_))
    83  - try:
    84  - exploit.serve_forever()
    85  - except:
    86  - print('[-] Caught exception. Shutting down.')
    87  - exploit.shutdown()
    88  - exploit.server_close()
    89  -
    90  -if __name__ == "__main__":
    91  - #parse the args
    92 107   parser = argparse.ArgumentParser()
    93  - parser.add_argument("-i", "--ip", help="Ip to listen on")
    94  - parser.add_argument("-p", "--port", help="Port to listen on")
    95  - parser.add_argument("-f", "--file", help="The exploit csv to use")
     108 + parser.add_argument("-i", "--ip", help="Ip to listen on", default=_IP_)
     109 + parser.add_argument("-p", "--port", help="Port to listen on", default=_PORT_)
     110 + parser.add_argument("-f", "--file", help="The exploit csv to use", default=_SEARCHSPLOIT_)
    96 111   args = parser.parse_args()
    97  - if args.ip:
    98  - _IP_ = args.ip
    99  - if args.port:
    100  - _PORT_ = args.port
    101  - if args.file:
    102  - _SEARCHSPLOIT_ = args.file
     112 + 
     113 + print("[ ] Starting up")
     114 + database = parse_exploitdb(args.file)
     115 + asyncio.run(start_server(args.ip, args.port, database))
    103 116   
    104  - if not isfile(_SEARCHSPLOIT_):
    105  - print("[-] Cannot find csv databse: {}\nFor more details visit: https://github.com/offensive-security/exploit-database".format(_SEARCHSPLOIT_))
    106  - exit(2)
     117 +def parse_exploitdb(path: str) -> List[OrderedDict[str,str]]:
     118 + database = []
     119 + if not isfile(path):
     120 + raise FileNotFoundError(
     121 + "[-] Cannot find csv database at {}\nFor more details visit: https://github.com/offensive-security/exploit-database".format(
     122 + path
     123 + )
     124 + )
    107 125   
    108  - #parse the exploit database and collect all the results
     126 + # parse the exploit database and collect all the results
    109 127   try:
    110  - with open(_SEARCHSPLOIT_) as Fin:
     128 + with open(path, 'r') as Fin:
    111 129   reader = DictReader(Fin)
    112 130   for lines in reader:
    113  - #add the database to the exploit server for non global persistance... or maybe it is technically still global?
    114  - ExploitServer.exploitDatabase.append(lines)
     131 + # add the database to the exploit server for non global persistance
     132 + database.append(lines)
    115 133   except Exception as e:
    116  - print("[-] Exception caught while attempting to parse database file. {}".format(e))
    117  - exit(3)
     134 + raise AttributeError(
     135 + "[-] Exception caught while attempting to parse database file. {}".format(e)
     136 + )
     137 + return database
    118 138   
    119  - print("[ ] Starting up")
     139 +if __name__ == "__main__":
     140 + # parse the args
    120 141   main()
Please wait...
Page is in error, reload to recover