%global _empty_manifest_terminate_build 0 Name: python-pywerview Version: 0.5.0 Release: 1 Summary: A Python port of PowerSploit's PowerView License: GNU GPLv3 URL: https://github.com/the-useless-one/pywerview Source0: https://mirrors.aliyun.com/pypi/web/packages/2d/b8/62919b3e62083da26c5818866d5d39845b646d8f0a35628d8c20cc2364b9/pywerview-0.5.0.tar.gz BuildArch: noarch Requires: python3-impacket Requires: python3-beautifulsoup4 Requires: python3-lxml Requires: python3-pyasn1 Requires: python3-ldap3 Requires: python3-gssapi Requires: python3-pycryptodome %description # PywerView ____ __ ___ | _ \ _ ___ _____ _ _\ \ / (_) _____ __ | |_) | | | \ \ /\ / / _ \ '__\ \ / /| |/ _ \ \ /\ / / | __/| |_| |\ V V / __/ | \ V / | | __/\ V V / |_| \__, | \_/\_/ \___|_| \_/ |_|\___| \_/\_/ |___/ A (partial) Python rewriting of [PowerSploit](https://github.com/PowerShellMafia/PowerSploit)'s [PowerView](https://github.com/PowerShellMafia/PowerSploit/tree/master/Recon). Fork me on [GitHub](https://github.com/the-useless-one/pywerview). [![License](https://img.shields.io/github/license/the-useless-one/pywerview)](https://github.com/the-useless-one/pywerview/blob/master/LICENSE) ![Python versions](https://img.shields.io/pypi/pyversions/pywerview) [![GitHub release](https://img.shields.io/github/v/release/the-useless-one/pywerview)](https://github.com/the-useless-one/pywerview/releases/latest) [![PyPI version](https://img.shields.io/pypi/v/pywerview)](https://pypi.org/project/pywerview/) ## HISTORY As a pentester, I love using PowerView during my assignments. It makes it so easy to find vulnerable machines, or list what domain users were added to the local Administrators group of a machine, and much more. However, running PowerView on a computer which is not connected to the domain is a pain: I always find myself using [mimikatz](https://github.com/gentilkiwi/mimikatz/)'s `sekurlsa::pth` to run a Powershell prompt with stolen domain credentials, and that's not easy to script. Plus, I'm a Linux guy and I've always found it a shame that there were no complete Windows/Active Directory enumeration tool on Linux. That's why I decided to rewrite some of PowerView's functionalities in Python, using the wonderful [impacket](https://github.com/SecureAuthCorp/impacket) library. *Update:* I haven't tested the last version of PowerView yet, which can run from a machine not connected to a domain. I don't know if it works correctly under Linux using Powershell. If anyone has had any experience with this at all, you can contact me, I'm really interested. We'll see if pywerview has become obsoleted ;) but I think I'll continue working on it eitherway: I'd still rather use Python than Powershell on Linux, and I'm learning a lot! Plus, it may integrated in existing Linux tools written in Python. It's still great news that PowerView now supports machines not connected to the domain! ## DISCLAIMER This tool is far from complete (as you'll see in the [TODO](#todo) section)! I still have a lot more awesome PowerView functionalities to implement (the user hunting functions, the GPO functions, the local process enumeration, etc.), but I still think it can be useful as is. It's also (very) possible that there are (many) bugs in the code: I've only tested the simplest test cases. If you use this tool during an assignment and you get an error, please, open an issue with the error and the conditions that triggered this error. Also, blah blah blah, don't use it for evil purposes. ## REQUIREMENTS * Python 3.6 * impacket >= 0.9.22 * ldap3 >= 2.8.1 * gssapi (Which requires `libkrb5-dev`) * pycryptodomex (or pycryptodome) ## FUNCTIONALITIES If you like living on the bleeding edge, check out the [development branch](https://github.com/the-useless-one/pywerview/tree/develop). Here's the list of available commands: $ pywerview.py --help usage: pywerview.py [-h] {get-adobject,get-adserviceaccount,get-objectacl,get-netuser,get-netgroup,get-netcomputer,get-netdomaincontroller,get-netfileserver,get-dfsshare,get-netou,get-netsite,get-netsubnet,get-netdomaintrust,get-netgpo,get-netpso,get-domainpolicy,get-gpttmpl,get-netgpogroup,find-gpocomputeradmin,find-gpolocation,get-netgroupmember,get-netsession,get-localdisks,get-netdomain,get-netshare,get-netloggedon,get-netlocalgroup,invoke-checklocaladminaccess,get-netprocess,get-userevent,invoke-userhunter,invoke-processhunter,invoke-eventhunter} ... Rewriting of some PowerView's functionalities in Python optional arguments: -h, --help show this help message and exit Subcommands: Available subcommands {get-adobject,get-adserviceaccount,get-objectacl,get-netuser,get-netgroup,get-netcomputer,get-netdomaincontroller,get-netfileserver,get-dfsshare,get-netou,get-netsite,get-netsubnet,get-netdomaintrust,get-netgpo,get-netpso,get-domainpolicy,get-gpttmpl,get-netgpogroup,find-gpocomputeradmin,find-gpolocation,get-netgroupmember,get-netsession,get-localdisks,get-netdomain,get-netshare,get-netloggedon,get-netlocalgroup,invoke-checklocaladminaccess,get-netprocess,get-userevent,invoke-userhunter,invoke-processhunter,invoke-eventhunter} get-adobject Takes a domain SID, samAccountName or name, and return the associated object get-adserviceaccount Returns a list of all the gMSA of the specified domain. To retrieve passwords, you need a privileged account and a TLS connection to the LDAP server (use the --tls switch). get-objectacl Takes a domain SID, samAccountName or name, and return the ACL of the associated object get-netuser Queries information about a domain user get-netgroup Get a list of all current domain groups, or a list of groups a domain user is member of get-netcomputer Queries informations about domain computers get-netdomaincontroller Get a list of domain controllers for the given domain get-netfileserver Return a list of file servers, extracted from the domain users' homeDirectory, scriptPath, and profilePath fields get-dfsshare Return a list of all fault tolerant distributed file systems for a given domain get-netou Get a list of all current OUs in the domain get-netsite Get a list of all current sites in the domain get-netsubnet Get a list of all current subnets in the domain get-netdomaintrust Returns a list of all the trusts of the specified domain get-netgpo Get a list of all current GPOs in the domain get-netpso Get a list of all current PSOs in the domain get-domainpolicy Returns the default domain or DC policy for the queried domain or DC get-gpttmpl Helper to parse a GptTmpl.inf policy file path into a custom object get-netgpogroup Parses all GPOs in the domain that set "Restricted Group" or "Groups.xml" find-gpocomputeradmin Takes a computer (or OU) and determine who has administrative access to it via GPO find-gpolocation Takes a username or a group name and determine the computers it has administrative access to via GPO get-netgroupmember Return a list of members of a domain group get-netsession Queries a host to return a list of active sessions on the host (you can use local credentials instead of domain credentials) get-localdisks Queries a host to return a list of active disks on the host (you can use local credentials instead of domain credentials) get-netdomain Queries a host for available domains get-netshare Queries a host to return a list of available shares on the host (you can use local credentials instead of domain credentials) get-netloggedon This function will execute the NetWkstaUserEnum RPC call to query a given host for actively logged on users get-netlocalgroup Gets a list of members of a local group on a machine, or returns every local group. You can use local credentials instead of domain credentials, however, domain credentials are needed to resolve domain SIDs. invoke-checklocaladminaccess Checks if the given user has local admin access on the given host get-netprocess This function will execute the 'Select * from Win32_Process' WMI query to a given host for a list of executed process get-userevent This function will execute the 'SELECT * from Win32_NTLogEvent' WMI query to a given host for a list of executed process invoke-userhunter Finds which machines domain users are logged into invoke-processhunter Searches machines for processes with specific name, or ran by specific users invoke-eventhunter Searches machines for events with specific name, or ran by specific users Take a look at the [wiki](https://github.com/the-useless-one/pywerview/wiki) to see a more detailed usage of every command. *Attention:* in every command, the used domain name must be the post-Win2k UPN, and not the Win2k compatible name. For example, my domain name is `uselessdomain.local`. The Win2K compatible name is `USELESSDOMAIN`. In every command, I must use __`uselessdomain.local`__ as an argument, and __not__ `USELESSDOMAIN`. ## GLOBAL ARGUMENTS ### Logging You can provide a logging level to `pywerview` modules by using `-l` or `--logging-level` options. Supported levels are: * `CRITICAL`: Only critical errors are displayed **(default)** * `WARNING` Warnings are displayed, along with citical errors * `DEBUG`: Debug level (caution: **very** verbose) * `ULTRA`: Extreme debugging level (caution: **very very** verbose) (level names are case insensitive) ### Kerberos authentication Kerberos authentication is now (partially) supported, which means you can pass the ticket and other stuff. To authenticate via Kerberos: 1. Point the `KRB5CCNAME` environment variable to your cache credential file. 2. Use the `-k` option in your function call, or the `do_kerberos` in your library call. ```console $ klist stormtroopers.ccache Ticket cache: FILE:stormtroopers.ccache Default principal: stormtroopers@CONTOSO.COM Valid starting Expires Service principal 10/03/2022 16:46:45 11/03/2022 02:46:45 ldap/srv-ad.contoso.com@CONTOSO.COM renew until 11/03/2022 16:43:17 $ KRB5CCNAME=stormtroopers.ccache python3 pywerview.py get-netcomputer -t srv-ad.contoso.com -u stormtroopers -k dnshostname: centos.contoso.com dnshostname: debian.contoso.com dnshostname: Windows7.contoso.com dnshostname: Windows10.contoso.com dnshostname: SRV-MAIL.contoso.com dnshostname: SRV-AD.contoso.com ``` If your cache credential file contains a corresponding TGS, or a TGT for your calling user, Kerberos authentication will be used. __SPN patching is partial__. Right now, we're in a mixed configuration where we use `ldap3` for LDAP commands and `impacket` for the other protocols (SMB, RPC). That is because `impacket`'s LDAP implementation has several problems, such as mismanagement of non-ASCII characters (which is problematic for us baguette-eaters). `ldap3` uses `gssapi` to authenticate with Kerberos, and `gssapi` needs the full hostname in the SPN of a ticket, otherwise it throws an error. It would be possible to patch an SPN with an incomplete hostname, however it's not done for now. For any functions that only rely on `impacket` (SMB or RPC functions), you can use tickets with SPNs with an incomplete hostname. In the following example, we use an LDAP ticket with an incomplete hostname for an SMB function, without any trouble. You just have to make sure that the `--computername` argument matches this incomplete hostname in the SPN: ```console $ klist skywalker.ccache Ticket cache: FILE:skywalker.ccache Default principal: skywalker@CONTOSO.COM Valid starting Expires Service principal 13/04/2022 14:26:59 14/04/2022 00:26:58 ldap/srv-ad@CONTOSO.COM renew until 14/04/2022 14:23:29 $ KRB5CCNAME=skywalker.ccache python3 pywerview.py get-localdisks --computername srv-ad -u skywalker -k disk: A: disk: C: disk: D: ``` To recap: | SPN in the ticket | Can be used with LDAP functions | Can be used with SMB/RPC functions | | :-----------------------------------: | :-----------------------------: | :--------------------------------: | | `ldap/srv-ad.contoso.com@CONTOSO.COM` | ✔️ | ✔️ | | `cifs/srv-ad.contoso.com@CONTOSO.COM` | ✔️ | ✔️ | | `ldap/srv-ad@CONTOSO.COM` | ❌ | ✔️ | *NOTE:* The same limitation exists for TGT in your cache credential file: `krbtgt/srv-ad.contoso.com@CONTOSO.COM` will work but not `krbtgt/srv-ad@CONTOSO.COM`. ### LDAP SChannel authentication SChannel authentication is supported for a subset of the submodules. Functions that support SChannel authentication are: * get-adobject * get-adserviceaccount * get-objectacl * get-netuser * get-netgroup * get-netcomputer * get-netdomaincontroller * get-netfileserver * get-netou * get-netsite * get-netsubnet * get-netdomaintrust * get-netpso * get-netgpo * get-netgroupmember To authenticate via SChannel: 1. Retrieve the certificate and the key with your favorite tool ([ntlmrelayx.py](https://github.com/fortra/impacket), [certipy](https://github.com/ly4k/Certipy),...) 2. `pywerview` needs a certificate file and a key file, so you need to extract them from the `.pfx`. 3. Use `--cert` and `--key` as in the following example: ```console $ python3 pywerview.py get-netuser -w contoso.com --dc-ip 172.16.0.55 --cert stormtroopers.crt --key stormtroopers.key --username administrator --attributes distinguishedname useraccountcontrol --tls distinguishedname: CN=Administrator,CN=Users,DC=contoso,DC=com useraccountcontrol: NORMAL_ACCOUNT ``` If you don't specify the `--tls` flag when using certificate authentication, `pywerview` will try to use StartTLS and an `EXTERNAL SASL` bind as described in the [Microsoft documentation](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/8e73932f-70cf-46d6-88b1-8d9f86235e81) ### TLS connection You can force a connection to the LDAPS port by using the `--tls` switch. It can be necessary with some functions, for example when retrieving gMSA passwords with `get-adserviceaccount`: ```console $ python3 pywerview.py get-adserviceaccount -t srv-ad.contoso.com -u 'SRV-MAIL$' --hashes $NT_HASH --resolve-sids distinguishedname: CN=gMSA-01,CN=Managed Service Accounts,DC=contoso,DC=com objectsid: S-1-5-21-863927164-4106933278-53377030-3115 samaccountname: gMSA-01$ msds-groupmsamembership: CN=SRV-MAIL,CN=Computers,DC=contoso,DC=com description: enabled: True $ python3 pywerview.py get-adserviceaccount -t srv-ad.contoso.com -u 'SRV-MAIL$' --hashes $NT_HASH --resolve-sids --tls distinguishedname: CN=gMSA-01,CN=Managed Service Accounts,DC=contoso,DC=com objectsid: S-1-5-21-863927164-4106933278-53377030-3115 samaccountname: gMSA-01$ msds-managedpassword: 69730ce3914ac6[redacted] msds-groupmsamembership: CN=SRV-MAIL,CN=Computers,DC=contoso,DC=com description: enabled: True ``` ### JSON output Pywerview can print results in json format by using the `--json` switch. ## TODO * Many, many more PowerView functionalities to implement. I'll now focus on forest functions, then inter-forest trust functions * Lots of rewrite due to the last version of PowerView * Gracefully fail against Unix machines running Samba * Perform range cycling in `get-netgroupmember` * Manage request to the Global Catalog * Try to fall back to `tcp/139` for RPC communications if `tcp/445` is closed * Comment, document, and clean the code ## THANKS * Thanks to the [@PowerSploit](https://github.com/PowerShellMafia/PowerSploit/) team for an awesome tool. * Thanks to [@SecureAuthCorp](https://github.com/SecureAuthCorp/) for this complete and comprehensive library that is [impacket](https://github.com/SecureAuthCorp/impacket). * Special thanks to [@asolino](https://github.com/asolino) for his help on developing using impacket. * Thanks to [@byt3bl33d3r](https://github.com/byt3bl33d3r) for his contributions. * Thanks to [@ThePirateWhoSmellsOfSunflowers](https://github.com/ThePirateWhoSmellsOfSunflowers) for his debugging, love you baby :heart: * Thanks to [@mpgn](https://github.com/mpgn) for his python 3 contributions. ## COPYRIGHT PywerView - A Python rewriting of PowerSploit's PowerView Yannick Méheut [yannick (at) meheut (dot) org] - Copyright © 2023 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see [https://www.gnu.org/licenses/](https://www.gnu.org/licenses/). %package -n python3-pywerview Summary: A Python port of PowerSploit's PowerView Provides: python-pywerview BuildRequires: python3-devel BuildRequires: python3-setuptools BuildRequires: python3-pip %description -n python3-pywerview # PywerView ____ __ ___ | _ \ _ ___ _____ _ _\ \ / (_) _____ __ | |_) | | | \ \ /\ / / _ \ '__\ \ / /| |/ _ \ \ /\ / / | __/| |_| |\ V V / __/ | \ V / | | __/\ V V / |_| \__, | \_/\_/ \___|_| \_/ |_|\___| \_/\_/ |___/ A (partial) Python rewriting of [PowerSploit](https://github.com/PowerShellMafia/PowerSploit)'s [PowerView](https://github.com/PowerShellMafia/PowerSploit/tree/master/Recon). Fork me on [GitHub](https://github.com/the-useless-one/pywerview). [![License](https://img.shields.io/github/license/the-useless-one/pywerview)](https://github.com/the-useless-one/pywerview/blob/master/LICENSE) ![Python versions](https://img.shields.io/pypi/pyversions/pywerview) [![GitHub release](https://img.shields.io/github/v/release/the-useless-one/pywerview)](https://github.com/the-useless-one/pywerview/releases/latest) [![PyPI version](https://img.shields.io/pypi/v/pywerview)](https://pypi.org/project/pywerview/) ## HISTORY As a pentester, I love using PowerView during my assignments. It makes it so easy to find vulnerable machines, or list what domain users were added to the local Administrators group of a machine, and much more. However, running PowerView on a computer which is not connected to the domain is a pain: I always find myself using [mimikatz](https://github.com/gentilkiwi/mimikatz/)'s `sekurlsa::pth` to run a Powershell prompt with stolen domain credentials, and that's not easy to script. Plus, I'm a Linux guy and I've always found it a shame that there were no complete Windows/Active Directory enumeration tool on Linux. That's why I decided to rewrite some of PowerView's functionalities in Python, using the wonderful [impacket](https://github.com/SecureAuthCorp/impacket) library. *Update:* I haven't tested the last version of PowerView yet, which can run from a machine not connected to a domain. I don't know if it works correctly under Linux using Powershell. If anyone has had any experience with this at all, you can contact me, I'm really interested. We'll see if pywerview has become obsoleted ;) but I think I'll continue working on it eitherway: I'd still rather use Python than Powershell on Linux, and I'm learning a lot! Plus, it may integrated in existing Linux tools written in Python. It's still great news that PowerView now supports machines not connected to the domain! ## DISCLAIMER This tool is far from complete (as you'll see in the [TODO](#todo) section)! I still have a lot more awesome PowerView functionalities to implement (the user hunting functions, the GPO functions, the local process enumeration, etc.), but I still think it can be useful as is. It's also (very) possible that there are (many) bugs in the code: I've only tested the simplest test cases. If you use this tool during an assignment and you get an error, please, open an issue with the error and the conditions that triggered this error. Also, blah blah blah, don't use it for evil purposes. ## REQUIREMENTS * Python 3.6 * impacket >= 0.9.22 * ldap3 >= 2.8.1 * gssapi (Which requires `libkrb5-dev`) * pycryptodomex (or pycryptodome) ## FUNCTIONALITIES If you like living on the bleeding edge, check out the [development branch](https://github.com/the-useless-one/pywerview/tree/develop). Here's the list of available commands: $ pywerview.py --help usage: pywerview.py [-h] {get-adobject,get-adserviceaccount,get-objectacl,get-netuser,get-netgroup,get-netcomputer,get-netdomaincontroller,get-netfileserver,get-dfsshare,get-netou,get-netsite,get-netsubnet,get-netdomaintrust,get-netgpo,get-netpso,get-domainpolicy,get-gpttmpl,get-netgpogroup,find-gpocomputeradmin,find-gpolocation,get-netgroupmember,get-netsession,get-localdisks,get-netdomain,get-netshare,get-netloggedon,get-netlocalgroup,invoke-checklocaladminaccess,get-netprocess,get-userevent,invoke-userhunter,invoke-processhunter,invoke-eventhunter} ... Rewriting of some PowerView's functionalities in Python optional arguments: -h, --help show this help message and exit Subcommands: Available subcommands {get-adobject,get-adserviceaccount,get-objectacl,get-netuser,get-netgroup,get-netcomputer,get-netdomaincontroller,get-netfileserver,get-dfsshare,get-netou,get-netsite,get-netsubnet,get-netdomaintrust,get-netgpo,get-netpso,get-domainpolicy,get-gpttmpl,get-netgpogroup,find-gpocomputeradmin,find-gpolocation,get-netgroupmember,get-netsession,get-localdisks,get-netdomain,get-netshare,get-netloggedon,get-netlocalgroup,invoke-checklocaladminaccess,get-netprocess,get-userevent,invoke-userhunter,invoke-processhunter,invoke-eventhunter} get-adobject Takes a domain SID, samAccountName or name, and return the associated object get-adserviceaccount Returns a list of all the gMSA of the specified domain. To retrieve passwords, you need a privileged account and a TLS connection to the LDAP server (use the --tls switch). get-objectacl Takes a domain SID, samAccountName or name, and return the ACL of the associated object get-netuser Queries information about a domain user get-netgroup Get a list of all current domain groups, or a list of groups a domain user is member of get-netcomputer Queries informations about domain computers get-netdomaincontroller Get a list of domain controllers for the given domain get-netfileserver Return a list of file servers, extracted from the domain users' homeDirectory, scriptPath, and profilePath fields get-dfsshare Return a list of all fault tolerant distributed file systems for a given domain get-netou Get a list of all current OUs in the domain get-netsite Get a list of all current sites in the domain get-netsubnet Get a list of all current subnets in the domain get-netdomaintrust Returns a list of all the trusts of the specified domain get-netgpo Get a list of all current GPOs in the domain get-netpso Get a list of all current PSOs in the domain get-domainpolicy Returns the default domain or DC policy for the queried domain or DC get-gpttmpl Helper to parse a GptTmpl.inf policy file path into a custom object get-netgpogroup Parses all GPOs in the domain that set "Restricted Group" or "Groups.xml" find-gpocomputeradmin Takes a computer (or OU) and determine who has administrative access to it via GPO find-gpolocation Takes a username or a group name and determine the computers it has administrative access to via GPO get-netgroupmember Return a list of members of a domain group get-netsession Queries a host to return a list of active sessions on the host (you can use local credentials instead of domain credentials) get-localdisks Queries a host to return a list of active disks on the host (you can use local credentials instead of domain credentials) get-netdomain Queries a host for available domains get-netshare Queries a host to return a list of available shares on the host (you can use local credentials instead of domain credentials) get-netloggedon This function will execute the NetWkstaUserEnum RPC call to query a given host for actively logged on users get-netlocalgroup Gets a list of members of a local group on a machine, or returns every local group. You can use local credentials instead of domain credentials, however, domain credentials are needed to resolve domain SIDs. invoke-checklocaladminaccess Checks if the given user has local admin access on the given host get-netprocess This function will execute the 'Select * from Win32_Process' WMI query to a given host for a list of executed process get-userevent This function will execute the 'SELECT * from Win32_NTLogEvent' WMI query to a given host for a list of executed process invoke-userhunter Finds which machines domain users are logged into invoke-processhunter Searches machines for processes with specific name, or ran by specific users invoke-eventhunter Searches machines for events with specific name, or ran by specific users Take a look at the [wiki](https://github.com/the-useless-one/pywerview/wiki) to see a more detailed usage of every command. *Attention:* in every command, the used domain name must be the post-Win2k UPN, and not the Win2k compatible name. For example, my domain name is `uselessdomain.local`. The Win2K compatible name is `USELESSDOMAIN`. In every command, I must use __`uselessdomain.local`__ as an argument, and __not__ `USELESSDOMAIN`. ## GLOBAL ARGUMENTS ### Logging You can provide a logging level to `pywerview` modules by using `-l` or `--logging-level` options. Supported levels are: * `CRITICAL`: Only critical errors are displayed **(default)** * `WARNING` Warnings are displayed, along with citical errors * `DEBUG`: Debug level (caution: **very** verbose) * `ULTRA`: Extreme debugging level (caution: **very very** verbose) (level names are case insensitive) ### Kerberos authentication Kerberos authentication is now (partially) supported, which means you can pass the ticket and other stuff. To authenticate via Kerberos: 1. Point the `KRB5CCNAME` environment variable to your cache credential file. 2. Use the `-k` option in your function call, or the `do_kerberos` in your library call. ```console $ klist stormtroopers.ccache Ticket cache: FILE:stormtroopers.ccache Default principal: stormtroopers@CONTOSO.COM Valid starting Expires Service principal 10/03/2022 16:46:45 11/03/2022 02:46:45 ldap/srv-ad.contoso.com@CONTOSO.COM renew until 11/03/2022 16:43:17 $ KRB5CCNAME=stormtroopers.ccache python3 pywerview.py get-netcomputer -t srv-ad.contoso.com -u stormtroopers -k dnshostname: centos.contoso.com dnshostname: debian.contoso.com dnshostname: Windows7.contoso.com dnshostname: Windows10.contoso.com dnshostname: SRV-MAIL.contoso.com dnshostname: SRV-AD.contoso.com ``` If your cache credential file contains a corresponding TGS, or a TGT for your calling user, Kerberos authentication will be used. __SPN patching is partial__. Right now, we're in a mixed configuration where we use `ldap3` for LDAP commands and `impacket` for the other protocols (SMB, RPC). That is because `impacket`'s LDAP implementation has several problems, such as mismanagement of non-ASCII characters (which is problematic for us baguette-eaters). `ldap3` uses `gssapi` to authenticate with Kerberos, and `gssapi` needs the full hostname in the SPN of a ticket, otherwise it throws an error. It would be possible to patch an SPN with an incomplete hostname, however it's not done for now. For any functions that only rely on `impacket` (SMB or RPC functions), you can use tickets with SPNs with an incomplete hostname. In the following example, we use an LDAP ticket with an incomplete hostname for an SMB function, without any trouble. You just have to make sure that the `--computername` argument matches this incomplete hostname in the SPN: ```console $ klist skywalker.ccache Ticket cache: FILE:skywalker.ccache Default principal: skywalker@CONTOSO.COM Valid starting Expires Service principal 13/04/2022 14:26:59 14/04/2022 00:26:58 ldap/srv-ad@CONTOSO.COM renew until 14/04/2022 14:23:29 $ KRB5CCNAME=skywalker.ccache python3 pywerview.py get-localdisks --computername srv-ad -u skywalker -k disk: A: disk: C: disk: D: ``` To recap: | SPN in the ticket | Can be used with LDAP functions | Can be used with SMB/RPC functions | | :-----------------------------------: | :-----------------------------: | :--------------------------------: | | `ldap/srv-ad.contoso.com@CONTOSO.COM` | ✔️ | ✔️ | | `cifs/srv-ad.contoso.com@CONTOSO.COM` | ✔️ | ✔️ | | `ldap/srv-ad@CONTOSO.COM` | ❌ | ✔️ | *NOTE:* The same limitation exists for TGT in your cache credential file: `krbtgt/srv-ad.contoso.com@CONTOSO.COM` will work but not `krbtgt/srv-ad@CONTOSO.COM`. ### LDAP SChannel authentication SChannel authentication is supported for a subset of the submodules. Functions that support SChannel authentication are: * get-adobject * get-adserviceaccount * get-objectacl * get-netuser * get-netgroup * get-netcomputer * get-netdomaincontroller * get-netfileserver * get-netou * get-netsite * get-netsubnet * get-netdomaintrust * get-netpso * get-netgpo * get-netgroupmember To authenticate via SChannel: 1. Retrieve the certificate and the key with your favorite tool ([ntlmrelayx.py](https://github.com/fortra/impacket), [certipy](https://github.com/ly4k/Certipy),...) 2. `pywerview` needs a certificate file and a key file, so you need to extract them from the `.pfx`. 3. Use `--cert` and `--key` as in the following example: ```console $ python3 pywerview.py get-netuser -w contoso.com --dc-ip 172.16.0.55 --cert stormtroopers.crt --key stormtroopers.key --username administrator --attributes distinguishedname useraccountcontrol --tls distinguishedname: CN=Administrator,CN=Users,DC=contoso,DC=com useraccountcontrol: NORMAL_ACCOUNT ``` If you don't specify the `--tls` flag when using certificate authentication, `pywerview` will try to use StartTLS and an `EXTERNAL SASL` bind as described in the [Microsoft documentation](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/8e73932f-70cf-46d6-88b1-8d9f86235e81) ### TLS connection You can force a connection to the LDAPS port by using the `--tls` switch. It can be necessary with some functions, for example when retrieving gMSA passwords with `get-adserviceaccount`: ```console $ python3 pywerview.py get-adserviceaccount -t srv-ad.contoso.com -u 'SRV-MAIL$' --hashes $NT_HASH --resolve-sids distinguishedname: CN=gMSA-01,CN=Managed Service Accounts,DC=contoso,DC=com objectsid: S-1-5-21-863927164-4106933278-53377030-3115 samaccountname: gMSA-01$ msds-groupmsamembership: CN=SRV-MAIL,CN=Computers,DC=contoso,DC=com description: enabled: True $ python3 pywerview.py get-adserviceaccount -t srv-ad.contoso.com -u 'SRV-MAIL$' --hashes $NT_HASH --resolve-sids --tls distinguishedname: CN=gMSA-01,CN=Managed Service Accounts,DC=contoso,DC=com objectsid: S-1-5-21-863927164-4106933278-53377030-3115 samaccountname: gMSA-01$ msds-managedpassword: 69730ce3914ac6[redacted] msds-groupmsamembership: CN=SRV-MAIL,CN=Computers,DC=contoso,DC=com description: enabled: True ``` ### JSON output Pywerview can print results in json format by using the `--json` switch. ## TODO * Many, many more PowerView functionalities to implement. I'll now focus on forest functions, then inter-forest trust functions * Lots of rewrite due to the last version of PowerView * Gracefully fail against Unix machines running Samba * Perform range cycling in `get-netgroupmember` * Manage request to the Global Catalog * Try to fall back to `tcp/139` for RPC communications if `tcp/445` is closed * Comment, document, and clean the code ## THANKS * Thanks to the [@PowerSploit](https://github.com/PowerShellMafia/PowerSploit/) team for an awesome tool. * Thanks to [@SecureAuthCorp](https://github.com/SecureAuthCorp/) for this complete and comprehensive library that is [impacket](https://github.com/SecureAuthCorp/impacket). * Special thanks to [@asolino](https://github.com/asolino) for his help on developing using impacket. * Thanks to [@byt3bl33d3r](https://github.com/byt3bl33d3r) for his contributions. * Thanks to [@ThePirateWhoSmellsOfSunflowers](https://github.com/ThePirateWhoSmellsOfSunflowers) for his debugging, love you baby :heart: * Thanks to [@mpgn](https://github.com/mpgn) for his python 3 contributions. ## COPYRIGHT PywerView - A Python rewriting of PowerSploit's PowerView Yannick Méheut [yannick (at) meheut (dot) org] - Copyright © 2023 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see [https://www.gnu.org/licenses/](https://www.gnu.org/licenses/). %package help Summary: Development documents and examples for pywerview Provides: python3-pywerview-doc %description help # PywerView ____ __ ___ | _ \ _ ___ _____ _ _\ \ / (_) _____ __ | |_) | | | \ \ /\ / / _ \ '__\ \ / /| |/ _ \ \ /\ / / | __/| |_| |\ V V / __/ | \ V / | | __/\ V V / |_| \__, | \_/\_/ \___|_| \_/ |_|\___| \_/\_/ |___/ A (partial) Python rewriting of [PowerSploit](https://github.com/PowerShellMafia/PowerSploit)'s [PowerView](https://github.com/PowerShellMafia/PowerSploit/tree/master/Recon). Fork me on [GitHub](https://github.com/the-useless-one/pywerview). [![License](https://img.shields.io/github/license/the-useless-one/pywerview)](https://github.com/the-useless-one/pywerview/blob/master/LICENSE) ![Python versions](https://img.shields.io/pypi/pyversions/pywerview) [![GitHub release](https://img.shields.io/github/v/release/the-useless-one/pywerview)](https://github.com/the-useless-one/pywerview/releases/latest) [![PyPI version](https://img.shields.io/pypi/v/pywerview)](https://pypi.org/project/pywerview/) ## HISTORY As a pentester, I love using PowerView during my assignments. It makes it so easy to find vulnerable machines, or list what domain users were added to the local Administrators group of a machine, and much more. However, running PowerView on a computer which is not connected to the domain is a pain: I always find myself using [mimikatz](https://github.com/gentilkiwi/mimikatz/)'s `sekurlsa::pth` to run a Powershell prompt with stolen domain credentials, and that's not easy to script. Plus, I'm a Linux guy and I've always found it a shame that there were no complete Windows/Active Directory enumeration tool on Linux. That's why I decided to rewrite some of PowerView's functionalities in Python, using the wonderful [impacket](https://github.com/SecureAuthCorp/impacket) library. *Update:* I haven't tested the last version of PowerView yet, which can run from a machine not connected to a domain. I don't know if it works correctly under Linux using Powershell. If anyone has had any experience with this at all, you can contact me, I'm really interested. We'll see if pywerview has become obsoleted ;) but I think I'll continue working on it eitherway: I'd still rather use Python than Powershell on Linux, and I'm learning a lot! Plus, it may integrated in existing Linux tools written in Python. It's still great news that PowerView now supports machines not connected to the domain! ## DISCLAIMER This tool is far from complete (as you'll see in the [TODO](#todo) section)! I still have a lot more awesome PowerView functionalities to implement (the user hunting functions, the GPO functions, the local process enumeration, etc.), but I still think it can be useful as is. It's also (very) possible that there are (many) bugs in the code: I've only tested the simplest test cases. If you use this tool during an assignment and you get an error, please, open an issue with the error and the conditions that triggered this error. Also, blah blah blah, don't use it for evil purposes. ## REQUIREMENTS * Python 3.6 * impacket >= 0.9.22 * ldap3 >= 2.8.1 * gssapi (Which requires `libkrb5-dev`) * pycryptodomex (or pycryptodome) ## FUNCTIONALITIES If you like living on the bleeding edge, check out the [development branch](https://github.com/the-useless-one/pywerview/tree/develop). Here's the list of available commands: $ pywerview.py --help usage: pywerview.py [-h] {get-adobject,get-adserviceaccount,get-objectacl,get-netuser,get-netgroup,get-netcomputer,get-netdomaincontroller,get-netfileserver,get-dfsshare,get-netou,get-netsite,get-netsubnet,get-netdomaintrust,get-netgpo,get-netpso,get-domainpolicy,get-gpttmpl,get-netgpogroup,find-gpocomputeradmin,find-gpolocation,get-netgroupmember,get-netsession,get-localdisks,get-netdomain,get-netshare,get-netloggedon,get-netlocalgroup,invoke-checklocaladminaccess,get-netprocess,get-userevent,invoke-userhunter,invoke-processhunter,invoke-eventhunter} ... Rewriting of some PowerView's functionalities in Python optional arguments: -h, --help show this help message and exit Subcommands: Available subcommands {get-adobject,get-adserviceaccount,get-objectacl,get-netuser,get-netgroup,get-netcomputer,get-netdomaincontroller,get-netfileserver,get-dfsshare,get-netou,get-netsite,get-netsubnet,get-netdomaintrust,get-netgpo,get-netpso,get-domainpolicy,get-gpttmpl,get-netgpogroup,find-gpocomputeradmin,find-gpolocation,get-netgroupmember,get-netsession,get-localdisks,get-netdomain,get-netshare,get-netloggedon,get-netlocalgroup,invoke-checklocaladminaccess,get-netprocess,get-userevent,invoke-userhunter,invoke-processhunter,invoke-eventhunter} get-adobject Takes a domain SID, samAccountName or name, and return the associated object get-adserviceaccount Returns a list of all the gMSA of the specified domain. To retrieve passwords, you need a privileged account and a TLS connection to the LDAP server (use the --tls switch). get-objectacl Takes a domain SID, samAccountName or name, and return the ACL of the associated object get-netuser Queries information about a domain user get-netgroup Get a list of all current domain groups, or a list of groups a domain user is member of get-netcomputer Queries informations about domain computers get-netdomaincontroller Get a list of domain controllers for the given domain get-netfileserver Return a list of file servers, extracted from the domain users' homeDirectory, scriptPath, and profilePath fields get-dfsshare Return a list of all fault tolerant distributed file systems for a given domain get-netou Get a list of all current OUs in the domain get-netsite Get a list of all current sites in the domain get-netsubnet Get a list of all current subnets in the domain get-netdomaintrust Returns a list of all the trusts of the specified domain get-netgpo Get a list of all current GPOs in the domain get-netpso Get a list of all current PSOs in the domain get-domainpolicy Returns the default domain or DC policy for the queried domain or DC get-gpttmpl Helper to parse a GptTmpl.inf policy file path into a custom object get-netgpogroup Parses all GPOs in the domain that set "Restricted Group" or "Groups.xml" find-gpocomputeradmin Takes a computer (or OU) and determine who has administrative access to it via GPO find-gpolocation Takes a username or a group name and determine the computers it has administrative access to via GPO get-netgroupmember Return a list of members of a domain group get-netsession Queries a host to return a list of active sessions on the host (you can use local credentials instead of domain credentials) get-localdisks Queries a host to return a list of active disks on the host (you can use local credentials instead of domain credentials) get-netdomain Queries a host for available domains get-netshare Queries a host to return a list of available shares on the host (you can use local credentials instead of domain credentials) get-netloggedon This function will execute the NetWkstaUserEnum RPC call to query a given host for actively logged on users get-netlocalgroup Gets a list of members of a local group on a machine, or returns every local group. You can use local credentials instead of domain credentials, however, domain credentials are needed to resolve domain SIDs. invoke-checklocaladminaccess Checks if the given user has local admin access on the given host get-netprocess This function will execute the 'Select * from Win32_Process' WMI query to a given host for a list of executed process get-userevent This function will execute the 'SELECT * from Win32_NTLogEvent' WMI query to a given host for a list of executed process invoke-userhunter Finds which machines domain users are logged into invoke-processhunter Searches machines for processes with specific name, or ran by specific users invoke-eventhunter Searches machines for events with specific name, or ran by specific users Take a look at the [wiki](https://github.com/the-useless-one/pywerview/wiki) to see a more detailed usage of every command. *Attention:* in every command, the used domain name must be the post-Win2k UPN, and not the Win2k compatible name. For example, my domain name is `uselessdomain.local`. The Win2K compatible name is `USELESSDOMAIN`. In every command, I must use __`uselessdomain.local`__ as an argument, and __not__ `USELESSDOMAIN`. ## GLOBAL ARGUMENTS ### Logging You can provide a logging level to `pywerview` modules by using `-l` or `--logging-level` options. Supported levels are: * `CRITICAL`: Only critical errors are displayed **(default)** * `WARNING` Warnings are displayed, along with citical errors * `DEBUG`: Debug level (caution: **very** verbose) * `ULTRA`: Extreme debugging level (caution: **very very** verbose) (level names are case insensitive) ### Kerberos authentication Kerberos authentication is now (partially) supported, which means you can pass the ticket and other stuff. To authenticate via Kerberos: 1. Point the `KRB5CCNAME` environment variable to your cache credential file. 2. Use the `-k` option in your function call, or the `do_kerberos` in your library call. ```console $ klist stormtroopers.ccache Ticket cache: FILE:stormtroopers.ccache Default principal: stormtroopers@CONTOSO.COM Valid starting Expires Service principal 10/03/2022 16:46:45 11/03/2022 02:46:45 ldap/srv-ad.contoso.com@CONTOSO.COM renew until 11/03/2022 16:43:17 $ KRB5CCNAME=stormtroopers.ccache python3 pywerview.py get-netcomputer -t srv-ad.contoso.com -u stormtroopers -k dnshostname: centos.contoso.com dnshostname: debian.contoso.com dnshostname: Windows7.contoso.com dnshostname: Windows10.contoso.com dnshostname: SRV-MAIL.contoso.com dnshostname: SRV-AD.contoso.com ``` If your cache credential file contains a corresponding TGS, or a TGT for your calling user, Kerberos authentication will be used. __SPN patching is partial__. Right now, we're in a mixed configuration where we use `ldap3` for LDAP commands and `impacket` for the other protocols (SMB, RPC). That is because `impacket`'s LDAP implementation has several problems, such as mismanagement of non-ASCII characters (which is problematic for us baguette-eaters). `ldap3` uses `gssapi` to authenticate with Kerberos, and `gssapi` needs the full hostname in the SPN of a ticket, otherwise it throws an error. It would be possible to patch an SPN with an incomplete hostname, however it's not done for now. For any functions that only rely on `impacket` (SMB or RPC functions), you can use tickets with SPNs with an incomplete hostname. In the following example, we use an LDAP ticket with an incomplete hostname for an SMB function, without any trouble. You just have to make sure that the `--computername` argument matches this incomplete hostname in the SPN: ```console $ klist skywalker.ccache Ticket cache: FILE:skywalker.ccache Default principal: skywalker@CONTOSO.COM Valid starting Expires Service principal 13/04/2022 14:26:59 14/04/2022 00:26:58 ldap/srv-ad@CONTOSO.COM renew until 14/04/2022 14:23:29 $ KRB5CCNAME=skywalker.ccache python3 pywerview.py get-localdisks --computername srv-ad -u skywalker -k disk: A: disk: C: disk: D: ``` To recap: | SPN in the ticket | Can be used with LDAP functions | Can be used with SMB/RPC functions | | :-----------------------------------: | :-----------------------------: | :--------------------------------: | | `ldap/srv-ad.contoso.com@CONTOSO.COM` | ✔️ | ✔️ | | `cifs/srv-ad.contoso.com@CONTOSO.COM` | ✔️ | ✔️ | | `ldap/srv-ad@CONTOSO.COM` | ❌ | ✔️ | *NOTE:* The same limitation exists for TGT in your cache credential file: `krbtgt/srv-ad.contoso.com@CONTOSO.COM` will work but not `krbtgt/srv-ad@CONTOSO.COM`. ### LDAP SChannel authentication SChannel authentication is supported for a subset of the submodules. Functions that support SChannel authentication are: * get-adobject * get-adserviceaccount * get-objectacl * get-netuser * get-netgroup * get-netcomputer * get-netdomaincontroller * get-netfileserver * get-netou * get-netsite * get-netsubnet * get-netdomaintrust * get-netpso * get-netgpo * get-netgroupmember To authenticate via SChannel: 1. Retrieve the certificate and the key with your favorite tool ([ntlmrelayx.py](https://github.com/fortra/impacket), [certipy](https://github.com/ly4k/Certipy),...) 2. `pywerview` needs a certificate file and a key file, so you need to extract them from the `.pfx`. 3. Use `--cert` and `--key` as in the following example: ```console $ python3 pywerview.py get-netuser -w contoso.com --dc-ip 172.16.0.55 --cert stormtroopers.crt --key stormtroopers.key --username administrator --attributes distinguishedname useraccountcontrol --tls distinguishedname: CN=Administrator,CN=Users,DC=contoso,DC=com useraccountcontrol: NORMAL_ACCOUNT ``` If you don't specify the `--tls` flag when using certificate authentication, `pywerview` will try to use StartTLS and an `EXTERNAL SASL` bind as described in the [Microsoft documentation](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/8e73932f-70cf-46d6-88b1-8d9f86235e81) ### TLS connection You can force a connection to the LDAPS port by using the `--tls` switch. It can be necessary with some functions, for example when retrieving gMSA passwords with `get-adserviceaccount`: ```console $ python3 pywerview.py get-adserviceaccount -t srv-ad.contoso.com -u 'SRV-MAIL$' --hashes $NT_HASH --resolve-sids distinguishedname: CN=gMSA-01,CN=Managed Service Accounts,DC=contoso,DC=com objectsid: S-1-5-21-863927164-4106933278-53377030-3115 samaccountname: gMSA-01$ msds-groupmsamembership: CN=SRV-MAIL,CN=Computers,DC=contoso,DC=com description: enabled: True $ python3 pywerview.py get-adserviceaccount -t srv-ad.contoso.com -u 'SRV-MAIL$' --hashes $NT_HASH --resolve-sids --tls distinguishedname: CN=gMSA-01,CN=Managed Service Accounts,DC=contoso,DC=com objectsid: S-1-5-21-863927164-4106933278-53377030-3115 samaccountname: gMSA-01$ msds-managedpassword: 69730ce3914ac6[redacted] msds-groupmsamembership: CN=SRV-MAIL,CN=Computers,DC=contoso,DC=com description: enabled: True ``` ### JSON output Pywerview can print results in json format by using the `--json` switch. ## TODO * Many, many more PowerView functionalities to implement. I'll now focus on forest functions, then inter-forest trust functions * Lots of rewrite due to the last version of PowerView * Gracefully fail against Unix machines running Samba * Perform range cycling in `get-netgroupmember` * Manage request to the Global Catalog * Try to fall back to `tcp/139` for RPC communications if `tcp/445` is closed * Comment, document, and clean the code ## THANKS * Thanks to the [@PowerSploit](https://github.com/PowerShellMafia/PowerSploit/) team for an awesome tool. * Thanks to [@SecureAuthCorp](https://github.com/SecureAuthCorp/) for this complete and comprehensive library that is [impacket](https://github.com/SecureAuthCorp/impacket). * Special thanks to [@asolino](https://github.com/asolino) for his help on developing using impacket. * Thanks to [@byt3bl33d3r](https://github.com/byt3bl33d3r) for his contributions. * Thanks to [@ThePirateWhoSmellsOfSunflowers](https://github.com/ThePirateWhoSmellsOfSunflowers) for his debugging, love you baby :heart: * Thanks to [@mpgn](https://github.com/mpgn) for his python 3 contributions. ## COPYRIGHT PywerView - A Python rewriting of PowerSploit's PowerView Yannick Méheut [yannick (at) meheut (dot) org] - Copyright © 2023 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see [https://www.gnu.org/licenses/](https://www.gnu.org/licenses/). %prep %autosetup -n pywerview-0.5.0 %build %py3_build %install %py3_install install -d -m755 %{buildroot}/%{_pkgdocdir} if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi pushd %{buildroot} if [ -d usr/lib ]; then find usr/lib -type f -printf "\"/%h/%f\"\n" >> filelist.lst fi if [ -d usr/lib64 ]; then find usr/lib64 -type f -printf "\"/%h/%f\"\n" >> filelist.lst fi if [ -d usr/bin ]; then find usr/bin -type f -printf "\"/%h/%f\"\n" >> filelist.lst fi if [ -d usr/sbin ]; then find usr/sbin -type f -printf "\"/%h/%f\"\n" >> filelist.lst fi touch doclist.lst if [ -d usr/share/man ]; then find usr/share/man -type f -printf "\"/%h/%f.gz\"\n" >> doclist.lst fi popd mv %{buildroot}/filelist.lst . mv %{buildroot}/doclist.lst . %files -n python3-pywerview -f filelist.lst %dir %{python3_sitelib}/* %files help -f doclist.lst %{_docdir}/* %changelog * Thu Jun 08 2023 Python_Bot - 0.5.0-1 - Package Spec generated