mirror of
https://github.com/calebstewart/pwncat.git
synced 2024-11-27 19:04:15 +01:00
Added aslr, container, and selinux enumeration
This commit is contained in:
parent
bb1a48d7ab
commit
5089fc2cc9
@ -231,6 +231,22 @@ class Command(CommandDefinition):
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
# Grab SELinux State
|
||||
selinux = pwncat.victim.enumerate.first("system.selinux").data
|
||||
system_details.append(["SELinux", selinux.state])
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
# Grab ASLR State
|
||||
aslr = pwncat.victim.enumerate.first("system.aslr").data
|
||||
system_details.append(
|
||||
["ASLR", "DISABLED" if aslr.state == 0 else "ENABLED"]
|
||||
)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
# Grab init system
|
||||
init = pwncat.victim.enumerate.first("system.init").data
|
||||
@ -238,6 +254,13 @@ class Command(CommandDefinition):
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
# Check if we are in a container
|
||||
container = pwncat.victim.enumerate.first("system.container").data
|
||||
system_details.append(["Container", container.type])
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Build the table writer for the main section
|
||||
table_writer = MarkdownTableWriter()
|
||||
table_writer.headers = ["Property", "Value"]
|
||||
@ -256,12 +279,16 @@ class Command(CommandDefinition):
|
||||
"system.distro",
|
||||
"system.init",
|
||||
"system.arch",
|
||||
"system.aslr",
|
||||
"system.container",
|
||||
]
|
||||
|
||||
# This is the list of known enumeration types that we want to
|
||||
# happen first in this order. Other types will still be output
|
||||
# but will be output in an arbitrary order following this list
|
||||
ordered_types = [
|
||||
# Sudo privileges
|
||||
"sudo",
|
||||
# Possible kernel exploits - very important
|
||||
"system.kernel.exploit",
|
||||
# Enumerated user passwords - very important
|
||||
|
44
pwncat/enumerate/system/aslr.py
Normal file
44
pwncat/enumerate/system/aslr.py
Normal file
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python3
|
||||
import dataclasses
|
||||
from typing import Generator
|
||||
|
||||
from colorama import Fore
|
||||
|
||||
import pwncat
|
||||
from pwncat.enumerate import FactData
|
||||
|
||||
name = "pwncat.enumerate.system"
|
||||
provides = "system.aslr"
|
||||
per_user = False
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class ASLRState(FactData):
|
||||
|
||||
state: int
|
||||
""" the value of /proc/sys/kernel/randomize_va_space """
|
||||
|
||||
def __str__(self):
|
||||
if self.state == 0:
|
||||
return f"ASLR is {Fore.GREEN}disabled{Fore.RESET}"
|
||||
return f"ASLR is {Fore.RED}enabled{Fore.RESET}"
|
||||
|
||||
|
||||
def enumerate() -> Generator[FactData, None, None]:
|
||||
"""
|
||||
Check if this system is inside a container
|
||||
:return:
|
||||
"""
|
||||
|
||||
try:
|
||||
with pwncat.victim.open("/proc/sys/kernel/randomize_va_space", "r") as filp:
|
||||
value = filp.read()
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
value = None
|
||||
|
||||
if value is not None:
|
||||
yield ASLRState(value)
|
||||
except (FileNotFoundError, PermissionError):
|
||||
pass
|
52
pwncat/enumerate/system/container.py
Normal file
52
pwncat/enumerate/system/container.py
Normal file
@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python3
|
||||
import dataclasses
|
||||
from typing import Generator
|
||||
|
||||
from colorama import Fore
|
||||
|
||||
import pwncat
|
||||
from pwncat.enumerate import FactData
|
||||
|
||||
name = "pwncat.enumerate.system"
|
||||
provides = "system.container"
|
||||
per_user = False
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class ContainerData(FactData):
|
||||
|
||||
type: str
|
||||
""" what type of container? either docker or lxd """
|
||||
|
||||
def __str__(self):
|
||||
return f"Running in a {Fore.YELLOW}{self.type}{Fore.RESET} container"
|
||||
|
||||
|
||||
def enumerate() -> Generator[FactData, None, None]:
|
||||
"""
|
||||
Check if this system is inside a container
|
||||
:return:
|
||||
"""
|
||||
|
||||
try:
|
||||
with pwncat.victim.open("/proc/self/cgroup", "r") as filp:
|
||||
if "docker" in filp.read().lower():
|
||||
yield ContainerData("docker")
|
||||
return
|
||||
except (FileNotFoundError, PermissionError):
|
||||
pass
|
||||
|
||||
with pwncat.victim.subprocess(
|
||||
f'find / -maxdepth 3 -name "*dockerenv*" -exec ls -la {{}} \\; 2>/dev/null', "r"
|
||||
) as pipe:
|
||||
if pipe.read().strip() != b"":
|
||||
yield ContainerData("docker")
|
||||
return
|
||||
|
||||
try:
|
||||
with pwncat.victim.open("/proc/1/environ", "r") as filp:
|
||||
if "container=lxc" in filp.read().lower():
|
||||
yield ContainerData("lxc")
|
||||
return
|
||||
except (FileNotFoundError, PermissionError):
|
||||
pass
|
62
pwncat/enumerate/system/selinux.py
Normal file
62
pwncat/enumerate/system/selinux.py
Normal file
@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python3
|
||||
import dataclasses
|
||||
from typing import Generator, Dict
|
||||
|
||||
from colorama import Fore
|
||||
|
||||
from pwncat.enumerate import FactData
|
||||
import pwncat
|
||||
|
||||
name = "pwncat.enumerate.system"
|
||||
provides = "system.selinux"
|
||||
per_user = False
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class SELinuxState(FactData):
|
||||
|
||||
state: str
|
||||
status: Dict[str, str]
|
||||
|
||||
def __str__(self):
|
||||
result = f"SELinux is "
|
||||
if self.state == "enabled":
|
||||
result += f"{Fore.RED}enabled{Fore.RESET}"
|
||||
elif self.state == "disabled":
|
||||
result += f"{Fore.GREEN}disabled{Fore.RESET}"
|
||||
else:
|
||||
result += f"{Fore.YELLOW}{self.state}{Fore.RESET}"
|
||||
return result
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
width = max(len(x) for x in self.status) + 1
|
||||
return "\n".join(
|
||||
f"{key+':':{width}} {value}" for key, value in self.status.items()
|
||||
)
|
||||
|
||||
|
||||
def enumerate() -> Generator[FactData, None, None]:
|
||||
"""
|
||||
Check for SELinux status/availability
|
||||
"""
|
||||
|
||||
try:
|
||||
output = pwncat.victim.env(["sestatus"]).strip().decode("utf-8")
|
||||
except (FileNotFoundError, PermissionError):
|
||||
return
|
||||
|
||||
status = {}
|
||||
for line in output.split("\n"):
|
||||
line = line.strip().replace("\t", " ")
|
||||
values = " ".join([x for x in line.split(" ") if x != ""]).split(":")
|
||||
key = values[0].rstrip(":").strip()
|
||||
value = " ".join(values[1:])
|
||||
status[key] = value.strip()
|
||||
|
||||
if "SELinux status" in status:
|
||||
state = status["SELinux status"]
|
||||
else:
|
||||
state = "unknown"
|
||||
|
||||
yield SELinuxState(state, status)
|
@ -483,7 +483,7 @@ class Victim:
|
||||
f"pruning {Fore.RED}{name}{Fore.RESET} from busybox"
|
||||
)
|
||||
|
||||
util.success(f"pruned {len(provides)-len(new_provides)} setuid entries")
|
||||
util.success(f"pruned {len(provides) - len(new_provides)} setuid entries")
|
||||
provides = new_provides
|
||||
|
||||
# Let the class know we now have access to busybox
|
||||
@ -1556,11 +1556,11 @@ class Victim:
|
||||
try:
|
||||
new = self.client.recv(4096)
|
||||
if len(new) == 0:
|
||||
if len(output) > 0 or some == False:
|
||||
if len(output) > 0 or some is False:
|
||||
break
|
||||
output += new
|
||||
except (socket.timeout, BlockingIOError):
|
||||
if len(output) > 0 or some == False:
|
||||
if len(output) > 0 or some is False:
|
||||
break
|
||||
|
||||
self.client.settimeout(old_timeout)
|
||||
|
Loading…
Reference in New Issue
Block a user