From fbe93c0f4deca446be6ddfe8e99aebd38ce8ae8e Mon Sep 17 00:00:00 2001 From: Caleb Stewart Date: Thu, 11 Jun 2020 01:56:20 -0400 Subject: [PATCH] Fixed screen-version enumeration Also, added a `victim.chdir` method which returns the old cwd as well as changes working directories in one command. --- pwncat/enumerate/screen_versions.py | 7 ++++++- pwncat/privesc/__init__.py | 1 + pwncat/privesc/screen.py | 7 +++---- pwncat/remote/victim.py | 21 ++++++++++++++++++++- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/pwncat/enumerate/screen_versions.py b/pwncat/enumerate/screen_versions.py index a6ed459..868a9cf 100644 --- a/pwncat/enumerate/screen_versions.py +++ b/pwncat/enumerate/screen_versions.py @@ -2,6 +2,7 @@ import dataclasses import shlex from typing import Generator +import os from colorama import Fore @@ -46,7 +47,7 @@ def enumerate() -> Generator[FactData, None, None]: # Look for matching binaries with pwncat.victim.subprocess( - f"find {shlex.join(paths)} \( -type f -or -type l \) -executable -name 'screen*' -printf '%#m %p\\n' 2>/dev/null" + f"find {shlex.join(paths)} \\( -type f -or -type l \\) -executable \\( -name 'screen' -or -name 'screen-*' \\) -printf '%#m %p\\n' 2>/dev/null" ) as pipe: for line in pipe: line = line.decode("utf-8").strip() @@ -54,4 +55,8 @@ def enumerate() -> Generator[FactData, None, None]: path = " ".join(path) perms = int(perms, 8) + # When the screen source code is on disk and marked as executable, this happens... + if os.path.splitext(path)[1] in [".c", ".o", ".h"]: + continue + yield ScreenVersion(path, perms) diff --git a/pwncat/privesc/__init__.py b/pwncat/privesc/__init__.py index d0a7a07..502b1ee 100644 --- a/pwncat/privesc/__init__.py +++ b/pwncat/privesc/__init__.py @@ -9,6 +9,7 @@ from typing import List, Tuple, Optional, Any from colorama import Fore from prompt_toolkit.shortcuts import confirm +from rich.progress import Progress, BarColumn import pwncat from pwncat import util diff --git a/pwncat/privesc/screen.py b/pwncat/privesc/screen.py index 6702cc8..d6d886f 100644 --- a/pwncat/privesc/screen.py +++ b/pwncat/privesc/screen.py @@ -121,8 +121,7 @@ class Method(BaseMethod): raise PrivescError("compilation failed: {exc}") # Switch to /etc but save our previous directory so we can return to it - old_cwd = pwncat.victim.env(["pwd"]).strip().decode("utf-8") - pwncat.victim.run("cd /etc") + old_cwd = pwncat.victim.chdir("/etc") # Run screen with our library, saving the umask before changing it start_umask = pwncat.victim.run("umask").decode("utf-8").strip() @@ -145,7 +144,7 @@ class Method(BaseMethod): if file_owner != b"0": # Hop back to the original directory - pwncat.victim.env(["cd", old_cwd]) + pwncat.victim.chdir(old_cwd) # Ensure the files are removed pwncat.victim.env(["rm", "-f", rootshell]) @@ -153,7 +152,7 @@ class Method(BaseMethod): raise PrivescError("failed to create root shell") # Hop back to the original directory - pwncat.victim.env(["cd", old_cwd]) + pwncat.victim.chdir(old_cwd) # Start the root shell! pwncat.victim.run(rootshell, wait=False) diff --git a/pwncat/remote/victim.py b/pwncat/remote/victim.py index c355ae4..7fd79d6 100644 --- a/pwncat/remote/victim.py +++ b/pwncat/remote/victim.py @@ -269,6 +269,7 @@ class Victim: "initializing: {task.fields[status]}", BarColumn(bar_width=None), "[progress.percentage]{task.percentage:>3.1f}%", + console=console, ) as progress: task_id = progress.add_task("initializing", total=7, status="hostname") @@ -420,7 +421,7 @@ class Victim: # Synchronize the terminals self.command_parser.dispatch_line("sync --quiet") - progress.update(task_id, status="complete", advance=1, visible=True) + progress.update(task_id, status="complete", advance=1) # Force the local TTY to enter raw mode self.state = State.RAW @@ -1316,6 +1317,24 @@ class Victim: return access + def chdir(self, path: str) -> str: + """ + Change directories in the remote process. Returns the old CWD. + + :param path: the directory to change to + :return: the old current working directory + """ + + cd_cmd = util.join(["cd", path]) + command = f"echo $PWD; {cd_cmd} || echo _PWNCAT_BAD_CD_" + output = self.run(command).decode("utf-8") + + if "_PWNCAT_BAD_CD_" in output: + raise FileNotFoundError(f"{path}: No such file or directory") + + output = output.replace("\r\n", "\n").split("\n") + return output[0] + def listdir(self, path: str) -> Generator[str, None, None]: """ List the contents of the specified directory.