mirror of
https://github.com/calebstewart/pwncat.git
synced 2024-11-30 20:34:15 +01:00
Added computer and file server enumerations
This commit is contained in:
parent
895744a6bd
commit
bf5c1fd6cd
@ -162,7 +162,7 @@ class EnumerateModule(BaseModule):
|
|||||||
|
|
||||||
# Yield all the know facts which have already been enumerated
|
# Yield all the know facts which have already been enumerated
|
||||||
if cache and types:
|
if cache and types:
|
||||||
yield from (
|
cached = [
|
||||||
f
|
f
|
||||||
for f in target.facts
|
for f in target.facts
|
||||||
if f.source == self.name
|
if f.source == self.name
|
||||||
@ -170,9 +170,13 @@ class EnumerateModule(BaseModule):
|
|||||||
any(fnmatch.fnmatch(item_type, req_type) for req_type in types)
|
any(fnmatch.fnmatch(item_type, req_type) for req_type in types)
|
||||||
for item_type in f.types
|
for item_type in f.types
|
||||||
)
|
)
|
||||||
)
|
]
|
||||||
elif cache:
|
elif cache:
|
||||||
yield from (f for f in target.facts if f.source == self.name)
|
cached = [f for f in target.facts if f.source == self.name]
|
||||||
|
else:
|
||||||
|
cached = []
|
||||||
|
|
||||||
|
yield from cached
|
||||||
|
|
||||||
# Check if the module is scheduled to run now
|
# Check if the module is scheduled to run now
|
||||||
if (self.name in target.enumerate_state) and (
|
if (self.name in target.enumerate_state) and (
|
||||||
@ -194,19 +198,22 @@ class EnumerateModule(BaseModule):
|
|||||||
# Only add the item if it doesn't exist
|
# Only add the item if it doesn't exist
|
||||||
for f in target.facts:
|
for f in target.facts:
|
||||||
if f == item:
|
if f == item:
|
||||||
yield Status(item.title(session))
|
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
target.facts.append(item)
|
target.facts.append(item)
|
||||||
|
|
||||||
# Don't yield the actual fact if we didn't ask for this type
|
# Don't yield the actual fact if we didn't ask for this type
|
||||||
if not types or any(
|
if not types or any(
|
||||||
any(fnmatch.fnmatch(item_type, req_type) for req_type in types)
|
any(fnmatch.fnmatch(item_type, req_type) for req_type in types)
|
||||||
for item_type in item.types
|
for item_type in item.types
|
||||||
):
|
):
|
||||||
yield item
|
for c in cached:
|
||||||
|
if item == c:
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
yield Status(item.title(session))
|
yield item
|
||||||
|
else:
|
||||||
|
yield Status(item.title(session))
|
||||||
|
|
||||||
# Update state for restricted modules
|
# Update state for restricted modules
|
||||||
if self.SCHEDULE == Schedule.ONCE:
|
if self.SCHEDULE == Schedule.ONCE:
|
||||||
|
83
pwncat/modules/windows/enumerate/domain/computer.py
Normal file
83
pwncat/modules/windows/enumerate/domain/computer.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from typing import Any, Dict
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
from pwncat.db import Fact
|
||||||
|
from pwncat.modules import Status, ModuleFailed
|
||||||
|
from pwncat.platform.windows import Windows, PowershellError
|
||||||
|
from pwncat.modules.enumerate import Schedule, EnumerateModule
|
||||||
|
|
||||||
|
|
||||||
|
class ComputerObject(Fact):
|
||||||
|
def __init__(self, source: str, data: Dict):
|
||||||
|
super().__init__(source=source, types=["domain.computer"])
|
||||||
|
|
||||||
|
self.computer = data
|
||||||
|
|
||||||
|
def __getitem__(self, name: str):
|
||||||
|
""" Shortcut for getting properties from the `self.domain` property. """
|
||||||
|
|
||||||
|
return self.computer[name]
|
||||||
|
|
||||||
|
def title(self, session: "pwncat.manager.Session"):
|
||||||
|
return f"[blue]{self['dnshostname']}[/blue] ([cyan]{self['name']}[/cyan])"
|
||||||
|
|
||||||
|
def is_dc(self):
|
||||||
|
""" Query if this computer object is a domain controller """
|
||||||
|
|
||||||
|
uac = self.computer.get("useraccountcontrol") or 0
|
||||||
|
|
||||||
|
return (uac & 0x2000) > 0
|
||||||
|
|
||||||
|
def is_rodc(self):
|
||||||
|
""" Query if this computer object is a read only domain controller """
|
||||||
|
|
||||||
|
uac = self.computer.get("useraccountcontrol") or 0
|
||||||
|
|
||||||
|
return (uac & 0x04000000) > 0
|
||||||
|
|
||||||
|
def description(self, session: "pwncat.manager.Session"):
|
||||||
|
output = []
|
||||||
|
|
||||||
|
if self.is_rodc():
|
||||||
|
output.append("[red]Read-Only Domain Controller[/red]")
|
||||||
|
elif self.is_dc():
|
||||||
|
output.append("[bold red]Domain Controller[/bold red]")
|
||||||
|
|
||||||
|
output.append(f"Computer SID: [cyan]{self['objectsid']}[/cyan]")
|
||||||
|
output.append(f"Machine Account: [cyan]{self['samaccountname']}[/cyan]")
|
||||||
|
output.append(
|
||||||
|
f"Operating System: [blue]{self['operatingsystem']} {self['operatingsystemversion']}[/blue]"
|
||||||
|
)
|
||||||
|
output.append(
|
||||||
|
f"Distinguished Name: [magenta]{self['distinguishedname']}[/magenta]"
|
||||||
|
)
|
||||||
|
|
||||||
|
return "\n".join(output)
|
||||||
|
|
||||||
|
|
||||||
|
class Module(EnumerateModule):
|
||||||
|
""" Retrieve information on all domain computers """
|
||||||
|
|
||||||
|
PLATFORM = [Windows]
|
||||||
|
PROVIDES = ["domain.computer"]
|
||||||
|
SCHEDULE = Schedule.ONCE
|
||||||
|
|
||||||
|
def enumerate(self, session: "pwncat.manager.Session"):
|
||||||
|
""" Perform enumeration """
|
||||||
|
|
||||||
|
# Ensure we have PowerView loaded
|
||||||
|
yield Status("loading powersploit recon")
|
||||||
|
session.run("powersploit", group="recon")
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield Status("requesting domain computers")
|
||||||
|
computers = session.platform.powershell("Get-DomainComputer")[0]
|
||||||
|
except (IndexError, PowershellError) as exc:
|
||||||
|
# Doesn't appear to be a domain joined computer
|
||||||
|
return
|
||||||
|
|
||||||
|
if isinstance(computers, dict):
|
||||||
|
yield ComputerObject(self.name, computers)
|
||||||
|
else:
|
||||||
|
yield from (ComputerObject(self.name, computer) for computer in computers)
|
38
pwncat/modules/windows/enumerate/domain/fileserver.py
Normal file
38
pwncat/modules/windows/enumerate/domain/fileserver.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from typing import Any, Dict
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
from pwncat.db import Fact
|
||||||
|
from pwncat.modules import Status, ModuleFailed
|
||||||
|
from pwncat.platform.windows import Windows, PowershellError
|
||||||
|
from pwncat.modules.enumerate import Schedule, EnumerateModule
|
||||||
|
|
||||||
|
|
||||||
|
class Module(EnumerateModule):
|
||||||
|
""" Retrieve information on all domain computers """
|
||||||
|
|
||||||
|
PLATFORM = [Windows]
|
||||||
|
PROVIDES = ["domain.fileserver"]
|
||||||
|
SCHEDULE = Schedule.ONCE
|
||||||
|
|
||||||
|
def enumerate(self, session: "pwncat.manager.Session"):
|
||||||
|
""" Perform enumeration """
|
||||||
|
|
||||||
|
# Ensure we have PowerView loaded
|
||||||
|
yield Status("loading powersploit recon")
|
||||||
|
session.run("powersploit", group="recon")
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield Status("requesting domain file servers")
|
||||||
|
names = session.platform.powershell("Get-DomainFileServer")[0]
|
||||||
|
except (IndexError, PowershellError) as exc:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not isinstance(names, list):
|
||||||
|
names = [names]
|
||||||
|
|
||||||
|
names = [name.lower() for name in names]
|
||||||
|
|
||||||
|
for computer in session.run("enumerate.domain.computer"):
|
||||||
|
if computer["name"].lower() in names:
|
||||||
|
yield computer
|
Loading…
Reference in New Issue
Block a user