| skipped 2 lines |
3 | 3 | | |
4 | 4 | | try: |
5 | 5 | | import socketserver |
6 | | - | from shutil import which |
| 6 | + | from os.path import isfile |
7 | 7 | | import argparse |
8 | | - | import re |
9 | | - | import subprocess |
10 | | - | import json |
11 | 8 | | import multiprocessing |
| 9 | + | from csv import DictReader |
12 | 10 | | except Exception as e: |
13 | 11 | | print("Caught exception: {}\nAre you running with python3?".format(e)) |
14 | 12 | | exit(1) |
| skipped 1 lines |
16 | 14 | | |
17 | 15 | | _PORT_ = 4521 |
18 | 16 | | _IP_ = '0.0.0.0' |
19 | | - | _searchsploit = "" |
| 17 | + | _SEARCHSPLOIT_ = "/usr/share/exploitdb/files_exploits.csv" |
20 | 18 | | |
21 | 19 | | class SearchHandler(socketserver.StreamRequestHandler): |
22 | 20 | | def handle(self): |
23 | 21 | | try: |
24 | 22 | | print('[+] Connection from '+ self.client_address[0]) |
25 | 23 | | self.pool = multiprocessing.Pool(10) |
26 | | - | for output in self.pool.imap(SearchHandler.search, iter(self.rfile.readline, b'\n'), 5): |
27 | | - | if not output[0]: |
28 | | - | #error'd out. print the results, but don't send them on? |
29 | | - | print(output[1]) |
30 | | - | continue |
31 | | - | jsonOutput = json.loads(output[1]) |
32 | | - | if jsonOutput.get("results", False): |
33 | | - | print('[+] Found results for: {}'.format(jsonOutput.get("SEARCH", output))) |
| 24 | + | for output in self.pool.imap(SearchHandler.search, iter(self.rfile.readline, b'\n')): |
| 25 | + | if output: |
| 26 | + | print(output) |
34 | 27 | | self.wfile.write(output.encode()) |
35 | | - | else: |
36 | | - | print('[-] No results for: {}'.format(jsonOutput.get("SEARCH", output))) |
| 28 | + | |
37 | 29 | | |
38 | 30 | | self.pool.close() |
39 | 31 | | self.pool.join() |
| skipped 6 lines |
46 | 38 | | |
47 | 39 | | @classmethod |
48 | 40 | | def search(cls, data): |
49 | | - | try: |
50 | | - | term = data.decode().strip().split(" ") |
51 | | - | term[-1] = term[-1][:3] #cut down on the last item which should be the version number |
52 | | - | for splitTerms in term: |
53 | | - | if not re.search("^[\w:\-\+\.~_]+$", splitTerms): |
54 | | - | return [False, "[-] recieved search term with invalid characters: {}".format(data.decode().strip())] #bad term return so we don't search it |
55 | | - | else: |
56 | | - | proc = subprocess.Popen([_searchsploit, '-j', *term], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
57 | | - | output = proc.stdout.read() |
58 | | - | return [True, output] |
59 | | - | |
60 | | - | except Exception as e: |
61 | | - | return [False, "[-] ".format(e)] |
| 41 | + | query = data.decode().strip().split(" ") |
| 42 | + | query[-1] = query[-1][:3] #cut down on the last item which should be the version number |
| 43 | + | output = ["[ ]" + data] |
| 44 | + | for rows in ExploitServer.exploitDatabase: |
| 45 | + | if all([term in rows["description"] for term in query]): |
| 46 | + | output.append('\t | '.join(rows["description"], rows["file"])) |
| 47 | + | if output: |
| 48 | + | return "\n".join(output) |
62 | 49 | | |
63 | 50 | | |
64 | 51 | | |
65 | 52 | | class ExploitServer(socketserver.ThreadingMixIn, socketserver.TCPServer): |
66 | | - | pass |
| 53 | + | exploitDatabase = [] |
67 | 54 | | |
68 | 55 | | |
69 | 56 | | def main(): |
| skipped 9 lines |
79 | 66 | | if __name__ == "__main__": |
80 | 67 | | #parse the args |
81 | 68 | | parser = argparse.ArgumentParser() |
82 | | - | parser.add_argument("-i", "--ip", help="Ip to listen on") |
83 | | - | parser.add_argument("-p", "--port", help="Port to listen on") |
| 69 | + | parser.add_argument("-i", "--ip", help="Ip to listen on", required=True) |
| 70 | + | parser.add_argument("-p", "--port", help="Port to listen on", required=True) |
| 71 | + | parser.add_argument("-f", "--file", help="The exploit csv to use") |
84 | 72 | | args = parser.parse_args() |
85 | 73 | | if args.ip: |
86 | 74 | | _IP_ = args.ip |
87 | 75 | | if args.port: |
88 | 76 | | _PORT_ = args.port |
| 77 | + | if args.file: |
| 78 | + | _SEARCHSPLOIT_ = args.file |
89 | 79 | | |
90 | | - | #make sure we have searchsploit accessable |
91 | | - | _searchsploit = which("searchsploit") |
92 | | - | if not _searchsploit: |
93 | | - | print("Please install searchsploit.\nFor more details visit: https://github.com/offensive-security/exploit-database") |
| 80 | + | if not isfile(_SEARCHSPLOIT_): |
| 81 | + | print("[-] Cannot find csv databse: {}\nFor more details visit: https://github.com/offensive-security/exploit-database".format(_SEARCHSPLOIT_)) |
94 | 82 | | exit(2) |
| 83 | + | |
| 84 | + | #parse the exploit database and collect all the results |
| 85 | + | try: |
| 86 | + | with open(_SEARCHSPLOIT_) as Fin: |
| 87 | + | reader = DictReader(Fin) |
| 88 | + | for lines in reader: |
| 89 | + | #add the database to the exploit server for non global persistance... or maybe it is technically still global? |
| 90 | + | ExploitServer.exploitDatabase.append(lines) |
| 91 | + | except Exception as e: |
| 92 | + | print("[-] Exception caught while attempting to parse database file. {}".format(e)) |
| 93 | + | exit(3) |
95 | 94 | | |
96 | 95 | | print("[ ] Starting up") |
97 | 96 | | main() |