import json import pathlib import hashlib import requests import base64 import sys from os import geteuid import subprocess from io import BytesIO import zipfile import rpmfile import gzip def compute_file_hash(filepath): with open(filepath, 'rb') as file_for_hash: data = file_for_hash.read() filesize = len(data) # Github sha value is computed as such: return hashlib.sha1(b"blob " + bytes(str(filesize), 'utf-8') + b"\0" + data).hexdigest() def get_master_info(repo, filepath, credz): url = f"https://api.github.com/repos/{repo}/contents/{filepath}" r = requests.get(url, auth=credz) sha = r.json()['sha'] content = r.json()['content'] return sha, content def get_last_release_info(repo, credz): url = f"https://api.github.com/repos/{repo}/releases" r = requests.get(url, auth=credz) for release in r.json(): if not release['draft'] and not release['prerelease']: return release['tag_name'] def extract_bin(archtype, binpath, destpath, content): ioobj = BytesIO(content) # Get a File object from bytes ;) if archtype == 'zip': with zipfile.ZipFile(ioobj, "r") as zf: filenames = zf.namelist() for fn in filenames: if binpath in fn: with open(destpath, 'wb') as f: f.write(zf.read(fn)) break elif archtype == 'rpm': with rpmfile.RPMFile(fileobj=ioobj) as rpm: # Extract a fileobject from the archive fd = rpm.extractfile(binpath) with open(destpath, 'wb') as f: f.write(fd.read()) elif archtype == 'gz': with open(destpath, 'wb') as f: f.write(gzip.decompress(content)) ioobj.close() def githubmastersync(reponame, filepaths, credz): for filepath in filepaths: localfile = pathlib.Path('files').joinpath(pathlib.Path(filepath).name) print(f" * {localfile} ", end='') lastsha, content = get_master_info(reponame, filepath, credz) if not localfile.exists(): content = base64.b64decode(content) with open(localfile, 'wb') as f: f.write(content) print('-> Installed! ;)') else: sha = compute_file_hash(localfile) if sha == lastsha: print('-> Up-to-date.') else: content = base64.b64decode(content) with open(localfile, 'wb') as f: f.write(content) print('-> Updated!') def githubreleasesync(reponame, repoinfo, credz): local_version = repoinfo['local_version'] last_version = get_last_release_info(reponame, credz) short_version = last_version.replace('v', '') filenames = repoinfo['files'] for filename in filenames: if isinstance(filename, dict): binpath = filename['binpath'] filename = filename['filename'] filename = filename.replace('{last_version}', last_version).replace('{short_version}', short_version) localfile = pathlib.Path('files').joinpath(pathlib.Path(binpath).name) if filename.endswith('.gz'): is_gz = True print(f" * {localfile} ", end='') else: filename = filename.replace('{last_version}', last_version).replace('{short_version}', short_version) localfile = pathlib.Path('files').joinpath(pathlib.Path(filename).name) print(f" * {localfile} ", end='') urldl = f'https://github.com/{reponame}/releases/download/{last_version}/{filename}' if not localfile.exists(): content = requests.get(urldl, auth=credz).content if is_gz: extract_bin('gz', binpath, localfile, content) else: with open(localfile, 'wb') as f: f.write(content) print('-> Installed! ;)') else: if local_version == last_version: print('-> Up-to-date.') else: content = requests.get(urldl, auth=credz).content if is_gz: extract_bin('gz', binpath, localfile, content) else: with open(localfile, 'wb') as f: f.write(content) print('-> Updated!') with open("config.json", "r") as jsonfile: data = json.load(jsonfile) data['githubreleasesync'][reponame]['local_version'] = last_version with open("config.json", "w") as jsonfile: json.dump(data, jsonfile, indent=4) def ncatsync(conf): r = requests.get('https://nmap.org/dist/') last_version = r.text.split('The latest Nmap release is version ')[1].split('.\n')[0] local_version = conf['local_version'] for filename in conf['files']: localfile = pathlib.Path('files').joinpath(pathlib.Path(filename).name) print(f" * {localfile} ", end='') if filename == "ncat.exe": archtype = 'zip' binpath = 'ncat.exe' destpath = 'files/ncat.exe' urldl = f'https://nmap.org/dist/nmap-{last_version}-win32.zip' elif filename == "ncat": archtype = 'rpm' binpath = './usr/bin/ncat' destpath = 'files/ncat' urldl = f'https://nmap.org/dist/ncat-{last_version}-1.x86_64.rpm' if not localfile.exists(): content = requests.get(urldl).content extract_bin(archtype, binpath, destpath, content) print('-> Installed! ;)') else: if local_version == last_version: print('-> Up-to-date.') else: content = requests.get(urldl).content extract_bin(archtype, binpath, destpath, content) with open("config.json", "r") as jsonfile: data = json.load(jsonfile) data['ncat']['local_version'] = last_version with open("config.json", "w") as jsonfile: json.dump(data, jsonfile, indent=4) print('-> Updated!') with open("config.json", "r") as jsonfile: data = json.load(jsonfile) data['ncat']['local_version'] = last_version with open("config.json", "w") as jsonfile: json.dump(data, jsonfile, indent=4) def update(config): print("Updating...") with open("credz.json", "r") as jsonfile: credz = json.load(jsonfile) credz = (credz['username'], credz['token']) for reponame, filepaths in config['githubmastersync'].items(): githubmastersync(reponame, filepaths, credz) for reponame, repoinfo in config['githubreleasesync'].items(): githubreleasesync(reponame, repoinfo, credz) ncatsync(config['ncat']) make_executable() def make_executable(): path = pathlib.Path('files') for fpath in path.glob("*"): if fpath.name != '.gitkeep': fpath.chmod(0o777) def print_menu(menu_options): for key in menu_options.keys(): print(key, '->', menu_options[key]) def is_sudo(): return True if geteuid() == 0 else False def ask_port(default_port): while True: try: choice = input(f'What port would you like to listen on ? [{default_port}]: ') if choice == '': port = default_port else: port = int(choice) break except ValueError: print('Wrong input. Please enter a number ...') return port def listen_http(files_dir): port = ask_port(80) ips = get_ips() print('The HTTP server is about to start.\nA good start ;) :') for iname in ips: if port == 80: print(f' -> {iname}: http://{ips[iname]}/linpeas.sh') else: print(f' -> {iname}: http://{ips[iname]}:{port}/linpeas.sh') cmd = ['python', '-m', 'http.server', '-d', files_dir, str(port)] if port < 1024 and not is_sudo(): print('Listening on any port under 1024 requires root permissions.') cmd.insert(0, 'sudo') subprocess.call(cmd) def listen_smb(files_dir, version): port = ask_port(445) ips = get_ips() print('The HTTP server is about to start.\nA good start ;) :') for iname in ips: if port == 445: print(f' -> {iname}: \\\\{ips[iname]}\\share\\winPEASany.exe') else: print(f' -> {iname}: \\\\{ips[iname]}:{port}\\share\\winPEASany.exe # This syntax (:port) is not supported on Windows ?') if version == 1: cmd = ['smbserver.py', '-port', str(port), 'share', files_dir] elif version == 2: cmd = ['smbserver.py', '-smb2support', '-port', str(port), 'share', files_dir] else: sys.exit('Wrong SMB version') if port < 1024 and not is_sudo(): print('Listening on any port under 1024 requires root permissions.') cmd.insert(0, 'sudo') subprocess.call(cmd) def get_public_ip(): return requests.get('https://api.ipify.org').text def get_ips(): ips = dict() try: ips['public'] = get_public_ip() except requests.exceptions.ConnectionError: pass cmd = ['ip', 'a'] out = subprocess.run(cmd, capture_output=True).stdout.decode('utf-8') lines = out.split('\n') while("" in lines): lines.remove("") for line in lines: if line[0].isdigit(): iname = line.split(' ')[1].split(':')[0] if 'inet ' in line: ip = line.split(' ')[5].split('/')[0] if ip != '127.0.0.1': ips[iname] = ip return ips def menu_choice(menu_options): while(True): print_menu(menu_options) option = '' try: option = int(input('Enter your choice: ')) except ValueError: print('Wrong input. Please enter a number ...') files_dir = pathlib.Path.cwd().joinpath('files') if option == 1: listen_http(files_dir) elif option == 2: listen_smb(files_dir, 1) elif option == 3: listen_smb(files_dir, 2) elif option == 0: sys.exit('Quitting') else: print('Invalid option. Please enter a valid number.') if __name__ == '__main__': with open("config.json", "r") as jsonfile: config = json.load(jsonfile) update(config) print('Choose a service to start a listener:') menu_options = { 1: 'HTTP', 2: 'SMB1', 3: 'SMB2', 0: 'Exit', } menu_choice(menu_options)