348 lines
10 KiB
Python
348 lines
10 KiB
Python
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)
|