diff --git a/pwncat/facts/windows.py b/pwncat/facts/windows.py index 0b85207..5183129 100644 --- a/pwncat/facts/windows.py +++ b/pwncat/facts/windows.py @@ -60,6 +60,7 @@ class WindowsUser(User): password_last_set: Optional[datetime], last_logon: Optional[datetime], principal_source: str, + domain: Optional[str] = None, password: Optional[str] = None, hash: Optional[str] = None, ): @@ -78,6 +79,15 @@ class WindowsUser(User): self.password_last_set: Optional[datetime] = password_last_set self.last_logon: Optional[datetime] = last_logon self.principal_source: str = principal_source + self.domain: Optional[str] = domain + + def __repr__(self): + if self.password is None and self.hash is None: + return f"""User(uid={self.id}, name={repr(self.name)}, domain={repr(self.domain)})""" + elif self.password is not None: + return f"""User(uid={repr(self.id)}, name={repr(self.name)}, domain={repr(self.domain)}, password={repr(self.password)})""" + else: + return f"""User(uid={repr(self.id)}, name={repr(self.name)}, domain={repr(self.domain)}, hash={repr(self.hash)})""" class WindowsGroup(Group): diff --git a/pwncat/modules/windows/enumerate/user/__init__.py b/pwncat/modules/windows/enumerate/user/__init__.py index c1c33f7..38d1fb9 100644 --- a/pwncat/modules/windows/enumerate/user/__init__.py +++ b/pwncat/modules/windows/enumerate/user/__init__.py @@ -40,4 +40,63 @@ class Module(EnumerateModule): password_last_set=None, last_logon=None, principal_source=user["PrincipalSource"], + domain=None, + ) + + try: + result = session.platform.powershell( + "(Get-WmiObject Win32_ComputerSystem).PartOfDomain" + )[0] + except (KeyError, PowershellError): + # Unable to grab domain status + return + + # Not in a domain + if not result: + return + + # We are in a domain, load powerview + session.run("powersploit", group="recon") + + try: + results = session.platform.powershell("Get-DomainUser")[0] + except (KeyError, PowershellError): + # We coudln't retrieve domain users :( + return + + if isinstance(results, dict): + results = [results] + + for user in results: + + dn = user.get("distinguishedname") + if dn is None: + domain = "unknown" + else: + dn = dn.split(",") + domain = [] + for element in dn[::-1]: + if element.startswith("DC="): + domain.insert(0, element.split("=")[1]) + else: + break + + domain = ".".join(domain) + + yield WindowsUser( + source=self.name, + name=user["samaccountname"], + uid=user["objectsid"], + account_expires=None, + description=user.get("description") or "", + enabled=True, + full_name=user.get("name") or "", + password_changeable_date=None, + password_expires=None, + user_may_change_password=True, + password_required=True, + password_last_set=None, + last_logon=None, + principal_source="", + domain=domain, ) diff --git a/pwncat/platform/windows.py b/pwncat/platform/windows.py index 237da3a..700a1ad 100644 --- a/pwncat/platform/windows.py +++ b/pwncat/platform/windows.py @@ -1283,8 +1283,6 @@ function prompt { if result.startswith(b"E:S2:EXCEPTION:"): raise PlatformError(result.split(b"E:S2:EXCEPTION:")[1].decode("utf-8")) - elif result.startswith(b"E:PWSH:"): - raise PowershellError(result.split(b"E:PWSH:")[1].decode("utf-8")) # Wait for the command to complete while result != b"DONE": @@ -1293,6 +1291,8 @@ function prompt { try: # Receive results result = self.channel.recvline().strip() + if result.startswith(b"E:PWSH:"): + raise PowershellError(result.split(b"E:PWSH:")[1].decode("utf-8")) while result != b"END": results.append(json.loads(result)) result = self.channel.recvline().strip()