mirror of
https://github.com/calebstewart/pwncat.git
synced 2024-11-27 19:04:15 +01:00
Added generic Powershell enumeration and startups
This commit is contained in:
parent
360c143004
commit
502a6b7906
@ -1,9 +1,11 @@
|
||||
"""
|
||||
Windows-specific facts which are used in multiple places throughout the framework.
|
||||
"""
|
||||
from typing import List, Optional
|
||||
import functools
|
||||
from typing import Any, List, Callable, Optional
|
||||
from datetime import datetime
|
||||
|
||||
from pwncat.db import Fact
|
||||
from pwncat.facts import User, Group
|
||||
|
||||
|
||||
@ -122,3 +124,36 @@ class WindowsGroup(Group):
|
||||
self.group_description: str = description
|
||||
self.principal_source: str = principal_source
|
||||
self.domain: Optional[str] = domain
|
||||
|
||||
|
||||
class PowershellFact(Fact):
|
||||
"""Powershell Object Wrapper Fact"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
source: str,
|
||||
types: List[str],
|
||||
obj: Any,
|
||||
title: Callable,
|
||||
description: Callable,
|
||||
):
|
||||
super().__init__(source=source, types=types)
|
||||
|
||||
self.obj = obj
|
||||
|
||||
if description is not None:
|
||||
self.description = functools.partial(description, self)
|
||||
if title is not None:
|
||||
self.title = functools.partial(title, self)
|
||||
|
||||
def description(self, session):
|
||||
return None
|
||||
|
||||
def title(self, session):
|
||||
return self.obj
|
||||
|
||||
def __getattr__(self, key: str):
|
||||
try:
|
||||
return self.obj[key]
|
||||
except KeyError:
|
||||
return super().__getattr__(key)
|
||||
|
@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import List, Callable
|
||||
|
||||
from pwncat.facts.windows import PowershellFact
|
||||
from pwncat.platform.windows import Windows, PowershellError
|
||||
from pwncat.modules.enumerate import Schedule, EnumerateModule
|
||||
|
||||
|
||||
def build_powershell_enumeration(
|
||||
types: List[str],
|
||||
schedule: Schedule,
|
||||
command: str,
|
||||
docstring: str,
|
||||
title: Callable = None,
|
||||
description: Callable = None,
|
||||
single: bool = False,
|
||||
):
|
||||
"""
|
||||
Build an enumeration module around a single powershell command.
|
||||
This will construct and return an enumeration class which executes
|
||||
the given powershell script and yields a fact with the given types
|
||||
that exposes all properties of the returned powershell objects. This
|
||||
is a helper to quickly develop basic powershell-based enumeration modules.
|
||||
"""
|
||||
|
||||
class Module(EnumerateModule):
|
||||
|
||||
PROVIDES = types
|
||||
PLATFORM = [Windows]
|
||||
SCHEDULE = schedule
|
||||
|
||||
def enumerate(self, session: "pwncat.manager.Session"):
|
||||
|
||||
try:
|
||||
result = session.platform.powershell(command)
|
||||
|
||||
if not result:
|
||||
return
|
||||
|
||||
if isinstance(result[0], list):
|
||||
results = result[0]
|
||||
else:
|
||||
results = [results[0]]
|
||||
|
||||
if single:
|
||||
yield PowershellFact(
|
||||
source=self.name,
|
||||
types=types,
|
||||
data=results[0],
|
||||
title=title,
|
||||
description=description,
|
||||
)
|
||||
else:
|
||||
yield from [
|
||||
PowershellFact(
|
||||
source=self.name,
|
||||
types=types,
|
||||
obj=obj,
|
||||
title=title,
|
||||
description=description,
|
||||
)
|
||||
for obj in results
|
||||
]
|
||||
|
||||
except PowershellError as exc:
|
||||
pass
|
||||
|
||||
# Set the docstring
|
||||
Module.__doc__ = docstring
|
||||
|
||||
return Module
|
22
pwncat/modules/windows/enumerate/system/startup.py
Normal file
22
pwncat/modules/windows/enumerate/system/startup.py
Normal file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Any, Dict
|
||||
|
||||
import rich.markup
|
||||
|
||||
from pwncat.modules.enumerate import Schedule
|
||||
from pwncat.modules.windows.enumerate import build_powershell_enumeration
|
||||
|
||||
|
||||
def startup_title(self, session: "pwncat.manager.Session"):
|
||||
return f"[cyan]{rich.markup.escape(self.Caption)}[/cyan]: {repr(rich.markup.escape(self.Command))}"
|
||||
|
||||
|
||||
Module = build_powershell_enumeration(
|
||||
types=["system.startup.command"],
|
||||
schedule=Schedule.ONCE,
|
||||
command="Get-CimInstance -ClassName Win32_StartupCommand",
|
||||
docstring="Locate all startup commands via WMI queries",
|
||||
title=startup_title,
|
||||
description=None,
|
||||
single=False,
|
||||
)
|
@ -4,40 +4,55 @@ import rich.markup
|
||||
|
||||
from pwncat.db import Fact
|
||||
from pwncat.modules import ModuleFailed
|
||||
from pwncat.modules.windows import Windows, PowershellError
|
||||
from pwncat.platform.windows import Windows, PowershellError
|
||||
from pwncat.modules.enumerate import Schedule, EnumerateModule
|
||||
from pwncat.modules.windows.enumerate import build_powershell_enumeration
|
||||
|
||||
|
||||
class WindowsUpdateServer(Fact):
|
||||
def __init__(self, source: str, server: str):
|
||||
super().__init__(source=source, types=["system.wsus.server"])
|
||||
|
||||
self.server = server
|
||||
|
||||
def is_secure(self) -> bool:
|
||||
"""Check if the given server is secure"""
|
||||
return self.server.startswith("https://")
|
||||
|
||||
def title(self, session):
|
||||
return rich.markup.escape(self.server)
|
||||
def wsus_title(self, session: "pwncat.manager.Session"):
|
||||
return rich.markup.escape(self.server)
|
||||
|
||||
|
||||
class Module(EnumerateModule):
|
||||
"""Locate all WSUS update servers"""
|
||||
Module = build_powershell_enumeration(
|
||||
types=["system.wsus.server"],
|
||||
schedule=Schedule.ONCE,
|
||||
command="Get-ItemPropertyValue -Path 'HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows\\WindowsUpdate' -Name WUServer",
|
||||
docstring="Locate all WSUS update server",
|
||||
title=wsus_title,
|
||||
description=None,
|
||||
single=True,
|
||||
)
|
||||
|
||||
PROVIDES = ["system.wsus.server"]
|
||||
PLATFORM = [Windows]
|
||||
SCHEDULE = Schedule.ONCE
|
||||
|
||||
def enumerate(self, session: "pwncat.manager.Session"):
|
||||
|
||||
try:
|
||||
result = session.platform.powershell(
|
||||
"Get-ItemPropertyValue -Path 'HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows\\WindowsUpdate' -Name WUServer"
|
||||
)
|
||||
if not result:
|
||||
return
|
||||
|
||||
yield WindowsUpdateServer(source=self.name, server=result[0])
|
||||
except PowershellError as exc:
|
||||
pass
|
||||
# class WindowsUpdateServer(Fact):
|
||||
# def __init__(self, source: str, server: str):
|
||||
# super().__init__(source=source, types=["system.wsus.server"])
|
||||
#
|
||||
# self.server = server
|
||||
#
|
||||
# def is_secure(self) -> bool:
|
||||
# """Check if the given server is secure"""
|
||||
# return self.server.startswith("https://")
|
||||
#
|
||||
# def title(self, session):
|
||||
# return rich.markup.escape(self.server)
|
||||
#
|
||||
#
|
||||
# class Module(EnumerateModule):
|
||||
# """Locate all WSUS update servers"""
|
||||
#
|
||||
# PROVIDES = ["system.wsus.server"]
|
||||
# PLATFORM = [Windows]
|
||||
# SCHEDULE = Schedule.ONCE
|
||||
#
|
||||
# def enumerate(self, session: "pwncat.manager.Session"):
|
||||
#
|
||||
# try:
|
||||
# result = session.platform.powershell(
|
||||
# "Get-ItemPropertyValue -Path 'HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows\\WindowsUpdate' -Name WUServer"
|
||||
# )
|
||||
# if not result:
|
||||
# return
|
||||
#
|
||||
# yield WindowsUpdateServer(source=self.name, server=result[0])
|
||||
# except PowershellError as exc:
|
||||
# pass
|
||||
|
Loading…
Reference in New Issue
Block a user