1
0
mirror of https://github.com/calebstewart/pwncat.git synced 2024-11-27 19:04:15 +01:00

Migrated some enumeration code into the new module framework

This commit is contained in:
John Hammond 2020-08-31 22:05:49 -04:00
parent 9a855c409f
commit 1706213920
8 changed files with 445 additions and 0 deletions

View File

@ -0,0 +1,46 @@
#!/usr/bin/env python3
from typing import List
import dataclasses
import pwncat
from pwncat import util
from pwncat.modules.enumerate import EnumerateModule, Schedule
@dataclasses.dataclass
class ArchData:
"""
Represents a W.X.Y-Z kernel version where W is the major version,
X is the minor version, Y is the patch, and Z is the ABI.
This explanation came from here:
https://askubuntu.com/questions/843197/what-are-kernel-version-number-components-w-x-yy-zzz-called
"""
arch: str
""" The determined architecture. """
def __str__(self):
return f"Running on a [cyan]{self.arch}[/cyan] processor"
class Module(EnumerateModule):
"""
Enumerate kernel/OS version information
:return:
"""
PROVIDES = ["arch"]
def enumerate(self):
"""
Enumerate kernel/OS version information
:return:
"""
try:
result = pwncat.victim.env(["uname", "-m"]).decode("utf-8").strip()
except FileNotFoundError:
return
yield "arch", ArchData(result)

View File

@ -0,0 +1,43 @@
#!/usr/bin/env python3
from typing import List
import dataclasses
import pwncat
from pwncat import util
from pwncat.modules.enumerate import EnumerateModule, Schedule
@dataclasses.dataclass
class ASLRStateData:
state: int
""" the value of /proc/sys/kernel/randomize_va_space """
def __str__(self):
if self.state == 0:
return f"ASLR is [green]disabled[/green]"
return f"ASLR is [red]enabled[/red]"
class Module(EnumerateModule):
"""
Determine whether or not ASLR is enabled or disabled.
:return:
"""
PROVIDES = ["aslr"]
def enumerate(self):
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 "aslr", ASLRStateData(value)
except (FileNotFoundError, PermissionError):
pass

View File

@ -0,0 +1,51 @@
#!/usr/bin/env python3
from typing import List
import dataclasses
import pwncat
from pwncat import util
from pwncat.modules.enumerate import EnumerateModule, Schedule
@dataclasses.dataclass
class ContainerData:
type: str
""" what type of container? either docker or lxd """
def __str__(self):
return f"Running in a [yellow]{self.type}[/yellow] container"
class Module(EnumerateModule):
"""
Check if this system is inside a container
:return:
"""
PROVIDES = ["container"]
def enumerate(self):
try:
with pwncat.victim.open("/proc/self/cgroup", "r") as filp:
if "docker" in filp.read().lower():
yield "container", 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 "container", ContainerData("docker")
return
try:
with pwncat.victim.open("/proc/1/environ", "r") as filp:
if "container=lxc" in filp.read().lower():
yield "container", ContainerData("lxc")
return
except (FileNotFoundError, PermissionError):
pass

View File

@ -0,0 +1,75 @@
#!/usr/bin/env python3
from typing import List
import dataclasses
import pwncat
from pwncat import util
from pwncat.modules.enumerate import EnumerateModule, Schedule
@dataclasses.dataclass
class DistroVersionData:
"""
Represents a W.X.Y-Z kernel version where W is the major version,
X is the minor version, Y is the patch, and Z is the ABI.
This explanation came from here:
https://askubuntu.com/questions/843197/what-are-kernel-version-number-components-w-x-yy-zzz-called
"""
name: str
ident: str
build_id: str
version: str
def __str__(self):
return (
f"Running [blue]{self.name}[/blue] ([cyan]{self.ident}[/cyan]), "
f"Version [red]{self.version}[/red], "
f"Build ID [green]{self.build_id}[/green]."
)
class Module(EnumerateModule):
"""
Enumerate kernel/OS version information
:return:
"""
PROVIDES = ["distro"]
def enumerate(self):
build_id = None
pretty_name = None
ident = None
version = None
try:
with pwncat.victim.open("/etc/os-release", "r") as filp:
for line in filp:
line = line.strip()
if line.startswith("PRETTY_NAME="):
pretty_name = line.split("=")[1].strip('"')
elif line.startswith("BUILD_ID="):
build_id = line.split("=")[1].strip('"')
elif line.startswith("ID="):
ident = line.split("=")[1].strip('"')
elif line.startswith("VERSION_ID="):
version = line.split("=")[1].strip('"')
except (PermissionError, FileNotFoundError):
pass
if version is None:
try:
with pwncat.victim.open("/etc/lsb-release", "r") as filp:
for line in filp:
if line.startswith("LSB_VERSION="):
version = line.split("=")[1].strip('"')
break
except (PermissionError, FileNotFoundError):
pass
if pretty_name is None and build_id is None and ident is None and version is None:
return
yield "distro", DistroVersionData(pretty_name, ident, build_id, version)

View File

@ -0,0 +1,38 @@
#!/usr/bin/env python3
from typing import List
import dataclasses
import pwncat
from pwncat import util
from pwncat.modules.enumerate import EnumerateModule, Schedule
class Module(EnumerateModule):
"""
Enumerate system hostname facts
:return: A generator of hostname facts
"""
PROVIDES = ["hostname"]
def enumerate(self):
try:
hostname = pwncat.victim.env(["hostname", "-f"]).decode("utf-8").strip()
yield "hostname", hostname
return
except FileNotFoundError:
pass
try:
hostname = pwncat.victim.env(["hostnamectl"]).decode("utf-8").strip()
hostname = hostname.replace("\r\n", "\n").split("\n")
for name in hostname:
if "static hostname" in name.lower():
hostname = name.split(": ")[1]
yield "hostname", hostname
return
except (FileNotFoundError, IndexError):
pass
return

View File

@ -0,0 +1,50 @@
#!/usr/bin/env python3
from typing import List
import dataclasses
import re
import pwncat
from pwncat import util
from pwncat.modules.enumerate import EnumerateModule, Schedule
@dataclasses.dataclass
class HostData:
address: str
hostnames: List[str]
def __str__(self):
joined_hostnames = ", ".join(self.hostnames)
return f"[cyan]{self.address}[/cyan] -> [blue]{joined_hostnames}[/blue]"
class Module(EnumerateModule):
"""
Enumerate hosts identified in /etc/hosts which are not localhost
:return:
"""
PROVIDES = ["hosts"]
def enumerate(self):
try:
with pwncat.victim.open("/etc/hosts", "r") as filp:
for line in filp:
# Remove comments
line = re.sub(r"#.*$", "", line).strip()
line = line.replace("\t", " ")
# We don't care about localhost or localdomain entries
if (
line.endswith("localhost")
or line.endswith(".localdomain")
or line.endswith("localhost6")
or line.endswith(".localdomain")
or line.endswith("localhost4")
or line.endswith("localdomain4")
or line == ""
):
continue
address, *hostnames = [e for e in line.split(" ") if e != ""]
yield "hosts", HostData(address, hostnames)
except (PermissionError, FileNotFoundError):
pass

View File

@ -0,0 +1,77 @@
#!/usr/bin/env python3
from typing import List
import dataclasses
import pwncat
from pwncat import util
from pwncat.modules.enumerate import EnumerateModule, Schedule
@dataclasses.dataclass
class InitSystemData:
init: util.Init
version: str
def __str__(self):
return f"Running [blue]{self.init}[/blue]"
@property
def description(self):
return self.version
class Module(EnumerateModule):
"""
Enumerate system init service
:return:
"""
PROVIDES = ["init"]
def enumerate(self):
init = util.Init.UNKNOWN
version = None
# Try to get the command name of the running init process
try:
with pwncat.victim.open("/proc/1/comm", "r") as filp:
comm = filp.read().strip()
if comm is not None:
if "systemd" in comm.lower():
init = util.Init.SYSTEMD
elif "sysv" in comm.lower():
init = util.Init.SYSV
elif "upstart" in comm.lower():
init = util.Init.UPSTART
except (PermissionError, FileNotFoundError):
comm = None
# Try to get the command name of the running init process
try:
with pwncat.victim.open("/proc/1/cmdline", "r") as filp:
comm = filp.read().strip().split("\x00")[0]
except (PermissionError, FileNotFoundError):
comm = None
if comm is not None:
if "systemd" in comm.lower():
init = util.Init.SYSTEMD
elif "sysv" in comm.lower():
init = util.Init.SYSV
elif "upstart" in comm.lower():
init = util.Init.UPSTART
with pwncat.victim.subprocess(f"{comm} --version", "r") as filp:
version = filp.read().decode("utf-8").strip()
if "systemd" in version.lower():
init = util.Init.SYSTEMD
elif "sysv" in version.lower():
init = util.Init.SYSV
elif "upstart" in version.lower():
init = util.Init.UPSTART
# No need to provide an empty version string. They apparently don't support "--version"
if version == "":
version = None
yield "init", InitSystemData(init, version)

View File

@ -0,0 +1,65 @@
#!/usr/bin/env python3
from typing import List
import dataclasses
import pwncat
from pwncat import util
from pwncat.modules.enumerate import EnumerateModule, Schedule
@dataclasses.dataclass
class KernelVersionData:
"""
Represents a W.X.Y-Z kernel version where W is the major version,
X is the minor version, Y is the patch, and Z is the ABI.
This explanation came from here:
https://askubuntu.com/questions/843197/what-are-kernel-version-number-components-w-x-yy-zzz-called
"""
major: int
minor: int
patch: int
abi: str
def __str__(self):
return (
f"Running Linux Kernel [red]{self.major}[/red]."
f"[green]{self.minor}[/green]."
f"[blue]{self.patch}[/blue]-[cyan]{self.abi}[/cyan]"
)
class Module(EnumerateModule):
"""
Enumerate kernel/OS version information
:return:
"""
PROVIDES = ["kernel"]
def enumerate(self):
# Try to find kernel version number
try:
kernel = pwncat.victim.env(["uname", "-r"]).strip().decode("utf-8")
if kernel == "":
raise FileNotFoundError
except FileNotFoundError:
try:
with pwncat.victim.open("/proc/version", "r") as filp:
kernel = filp.read()
except (PermissionError, FileNotFoundError):
kernel = None
# Parse the kernel version number
if kernel is not None:
kernel = kernel.strip()
# We got the full "uname -a" style output
if kernel.lower().startswith("linux"):
kernel = kernel.split(" ")[2]
# Split out the sections
w, x, *y_and_z = kernel.split(".")
y_and_z = ".".join(y_and_z).split("-")
y = y_and_z[0]
z = "-".join(y_and_z[1:])
yield "kernel", KernelVersionData(int(w), int(x), int(y), z)