commit 2ad6c75ef83d2c046fca3785ebd373aadad11cca Author: Jordan ERNST Date: Sat Apr 16 18:48:42 2022 +0200 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..19ca352 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +files/* +!files/.gitkeep diff --git a/README.md b/README.md new file mode 100644 index 0000000..0753f0b --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# Pendora Box + +This too has several functions: +* Keep your pentesting scripts, binaries hosted on Github up-to-date. (master branch) +* Listen on HTTP or SMB to easily share your files to the victims + +## To-Do + +* Keeping up-to-date from Github releases +* Adding more services to listen to ? + +## Dependencies + +* requests python module +* impacket smbserver.py must be in PATH + +## Usage + +`python pendora-box.py` + +## Adding a file to track + +Simply add the informations to [config.json](./config.json), and run the script. +The file is gonna be automatically downloaded. diff --git a/config.json b/config.json new file mode 100644 index 0000000..ceb8103 --- /dev/null +++ b/config.json @@ -0,0 +1,31 @@ +{ + "githubfilesync": [ + { + "samratashok/nishang": [ + "Shells/Invoke-PowerShellTcp.ps1", + "Shells/Invoke-PowerShellTcpOneLine.ps1" + ] + }, + { + "samratashok/nishang": [ + "Shells/Invoke-PowerShellTcp.ps1", + "Shells/Invoke-PowerShellTcpOneLine.ps1" + ] + }, + { + "antonioCoco/ConPtyShell": [ + "Invoke-ConPtyShell.ps1" + ] + }, + { + "ly4k/PwnKit": [ + "PwnKit" + ] + }, + { + "Re4son/Churrasco": [ + "churrasco.exe" + ] + } + ] +} \ No newline at end of file diff --git a/files/.gitkeep b/files/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/pendora-box.py b/pendora-box.py new file mode 100644 index 0000000..67c2d29 --- /dev/null +++ b/pendora-box.py @@ -0,0 +1,175 @@ +import json +import pathlib +import hashlib +import requests +import base64 +import sys +from os import geteuid +import subprocess + + +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_info(repo, filepath): + url = f"https://api.github.com/repos/{repo}/contents/{filepath}" + r = requests.get(url) + sha = r.json()['sha'] + content = r.json()['content'] + return sha, content + + +def update(): + with open("config.json", "r") as jsonfile: + config = json.load(jsonfile) + + print("Updating...") + + for repo in config['githubfilesync']: + for reponame, value in repo.items(): + for filepath in value: + localfile = pathlib.Path('files').joinpath(pathlib.Path(filepath).name) + print(f" * {localfile} ", end='') + lastsha, content = get_info(reponame, filepath) + + 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 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.\nAvailable endpoints:') + for iname in ips: + if port == 80: + print(f' -> {iname}: http://{ips[iname]}/') + else: + print(f' -> {iname}: http://{ips[iname]}:{port}/') + + if port < 1024 and not is_sudo(): + print('Listening on any port under 1024 requires root permissions.') + cmd = ['sudo', 'python', '-m', 'http.server', '-d', files_dir, str(port)] + else: + cmd = ['python', '-m', 'http.server', '-d', files_dir, str(port)] + subprocess.call(cmd) + + +def listen_smb(files_dir): + port = ask_port(445) + ips = get_ips() + + print('The HTTP server is about to start.\nAvailable endpoints:') + for iname in ips: + if port == 445: + print(f' -> {iname}: \\\\{ips[iname]}\\share\\') + else: + print(f' -> {iname}: \\\\{ips[iname]}:{port}\\share\\ # This syntax (:port) is not supported on Windows ?') + + if port < 1024 and not is_sudo(): + print('Listening on any port under 1024 requires root permissions.') + cmd = ['sudo', 'smbserver.py', '-port', str(port), 'share', files_dir] + else: + cmd = ['smbserver.py', '-port', str(port), 'share', files_dir] + 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) + elif option == 0: + sys.exit('Quitting') + else: + print('Invalid option. Please enter a valid number.') + + +if __name__ == '__main__': + menu_options = { + 1: 'HTTP', + 2: 'SMB', + 0: 'Exit', + } + update() + menu_choice(menu_options)