1
0
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:
Caleb Stewart 2021-07-10 23:27:53 -04:00
parent 360c143004
commit 502a6b7906
4 changed files with 175 additions and 32 deletions

View File

@ -1,9 +1,11 @@
""" """
Windows-specific facts which are used in multiple places throughout the framework. 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 datetime import datetime
from pwncat.db import Fact
from pwncat.facts import User, Group from pwncat.facts import User, Group
@ -122,3 +124,36 @@ class WindowsGroup(Group):
self.group_description: str = description self.group_description: str = description
self.principal_source: str = principal_source self.principal_source: str = principal_source
self.domain: Optional[str] = domain 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)

View File

@ -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

View 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,
)

View File

@ -4,40 +4,55 @@ import rich.markup
from pwncat.db import Fact from pwncat.db import Fact
from pwncat.modules import ModuleFailed 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.enumerate import Schedule, EnumerateModule
from pwncat.modules.windows.enumerate import build_powershell_enumeration
class WindowsUpdateServer(Fact): def wsus_title(self, session: "pwncat.manager.Session"):
def __init__(self, source: str, server: str): return rich.markup.escape(self.server)
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): Module = build_powershell_enumeration(
"""Locate all WSUS update servers""" 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"] # class WindowsUpdateServer(Fact):
PLATFORM = [Windows] # def __init__(self, source: str, server: str):
SCHEDULE = Schedule.ONCE # super().__init__(source=source, types=["system.wsus.server"])
#
def enumerate(self, session: "pwncat.manager.Session"): # self.server = server
#
try: # def is_secure(self) -> bool:
result = session.platform.powershell( # """Check if the given server is secure"""
"Get-ItemPropertyValue -Path 'HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows\\WindowsUpdate' -Name WUServer" # return self.server.startswith("https://")
) #
if not result: # def title(self, session):
return # return rich.markup.escape(self.server)
#
yield WindowsUpdateServer(source=self.name, server=result[0]) #
except PowershellError as exc: # class Module(EnumerateModule):
pass # """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