WebSec 101: JuiceShop ⭐⭐⭐ challenges 1/2

Hello!

Welcome to the third part of my web sec journey through Juice Shop!

Today we will take care of half of  the ⭐⭐⭐ challenges. There are 22 tasks, so I’ll split them into 2 parts, to make it easier to acquire.

Without further ado, let’s get the hacking party started!

Goals

We can find 9 different categories of ⭐⭐⭐ challenges:

  • Improper Input Validation – 5
  • Broken Authentication – 3
  • Broken Anti Automation – 1
  • Broken Access Control – 5
  • Injection – 3
  • Sensitive Data Exposure – 1
  • Security through Obscurity – 1
  • XSS – 2
  • XXE – 1

I really enjoy learning things by categories, so I decided to close all of the task from three of them: Improter Input Validation (5), Broken Authentication (3) and Injections (3).

That makes 11 tasks together, and alot to digest:

Short term goals for today 😉

I also wanted to split XSS and Injections between days – they are the most “impressive” while being in the beginning of the learning path, but you can’t have your cake and eat it too.

🍰XSS and 🎂Injection cakes

⭐⭐⭐Login Jim (Injection)

Injection is always a promising start – hacks are attractive, didactic and not overcomplicated. What is not meaningless – this one goes with tutorial. So, let’s treat it like an entry step. In this one we are asked to log in with Jim’s user account, and the hint is to ‘try cracking Jim’s password has if you harvested it already‘ – I did not, but after finishing database scheme I’ll get back to it. ‘Alternatively, if you know Jim’s email, try SQL injection‘.

One of the ⭐⭐ challenges was to log in as administrator. I can basically check for Jim’s email with my notes:

Screenshot from notes

So, login is (hard to guess):

jim@juice-sh.op

Let’s check the tutorial then:

Of course, tutorial was right:

Reviews are leaking e-mails

But we already knew it. Then the tutor guides us:

Tutor as always is very informative 😉
We will need it in further tasks…

And we did it!

We are logged as Jim!

⭐⭐⭐Bjoern’s Favorite Pet (Broken Authentication)

To solve this challenge, we have to reset the password of Bjoern’s OWASP account via the Forgot Password mechanism with the original answer to his security question. We also know that ‘He might have spoiled it on at least one occasion when a camera was running. Maybe somewhere else‘.

Again, we know Bjoern’s email e.g. from reviews:

Reviews leaking again

So the email is:

bjoern@owasp.org

What is the Security Question?

Bjoern’s Security Question

We also know that one of ⭐ challenge was about repair encoding for Bjoern’s cat photos 😼 #zatschi Unfortunately it is:

Wrong answer to security question

But Bjoern ‘might have spoiled it on at least one occasion when a camera was running’. So again, we have to do simple googling. After that, we will find video: BeNeLux Day 2018: Juice Shop: OWASP’s Most Broken Flagship – Björn Kimminich.

Around 4:00 Bjoern is answering the question with the name: Zaya

Zaya 😉

So after sending request similar to:

{"email":"bjoern@owasp.org","answer":"Zaya","new":"12345","repeat":"12345"}

We managed to change Bjoern’s password 😉

⭐⭐⭐GDPR Data Erasure (Broken Authentication)

The General Data Protection Regulation (EU) 2016/679 (GDPR) is a regulation in EU law on data protection and privacy in the European Union and the European Economic Area.

GDPR Art. 17 Right to erasure, or, as it’s called – ‘right to be forgotten’ stands:

The data subject shall have the right to obtain from the controller the erasure of personal data concerning him or her without undue delay and the controller shall have the obligation to erase personal data without undue delay(…)

GDPR Art. 17

In this challenge we have to log in with Chris’ erased user account. The hint is that it turned out that there is something wrong with “right to be forgotten” implementation.

I checked it: there is special form for requesting data erasure, which requires email and security question answer:

Data Erasure Form

Actually it wasn’t very informative, so I need to try another way around. I checked the hints and I got the confirmation about the form:

  1. Trying out the Request Data Erasure functionality might be interesting, but cannot help you solve this challenge in real time.

The second one is interesting:

  1. If you have solved the challenge Retrieve a list of all user credentials via SQL Injection you might have already retrieved some information about how the Juice Shop ‘deletes’ users upon their request.

I’ve already did, but it can be found in the different (future) article. The email we are looking for is:

chris.pike@juice-sh.op


So, we can try simple SQL injection:

Similar to Jim’s…

And with the simple request:

{"email":"chris.pike@juice-sh.op'--","password":"x"}

We have solved the challenge!

I’m Chris now 😉

⭐⭐⭐Database Schema (Injection)

This one is called to the blackboard by the previous ones. We need to exfiltrate the entire DB schema definition via SQL Injection. We are advised to craft union select attack, find out which database system is in use and where it would store data.

As we may know, the SQLite is in place. So I went for SQLite Faq and checked ‘How do I list all tables/indices contained in an SQLite database‘ – so the schema is stored in sqlite_master.

As I mentioned, while writing this article I’m a little ahead with solving, so I alredy know that /product/search?q= parameter is vulnerable to SQL injection, so that’s the place to start crafting SQL injections.

Let’s start step by step.

I’ve sended GET /rest/products/search?q= to intruder and started to experiment:

  • search?q=’)— parameter returned me error:
search?q=’)—

As you can see I’ve got even full SELECT statement:

“SELECT * FROM Products WHERE ((name LIKE ‘%’)–%’ OR description LIKE ‘%’)–%’) AND deletedAt IS NULL) ORDER BY name”

After changing the request to:

  • search?q=’))–

To reveal database schema we will use UNION SELECT statement with sqlite_master master.

The UNION operator is used in SQL injections to join a query, purposely forged by the tester, to the original query. The result of the forged query will be joined to the result of the original query, allowing the tester to obtain the values of columns of other tables.

Union Exploitation Technique – WSTG OWASP

That works perfectly. So we can go further! I would be much easier to use params view:

  • UNION SELECT * FROM x—
First UNION SELECT

And I got error message:

"message": "SQLITE_ERROR: no such table: x",

So let’s check:

  • ‘)) UNION SELECT * FROM sqlite_master—

And we have different error:

"SQLITE_ERROR: SELECTs to the left and right of UNION do not have the same number of result columns"

Now it’s almost sitting ducks!

We have to guess how many columns there is with trying:

')) UNION SELECT '1' FROM sqlite_master—  - same error
')) UNION SELECT '1', '2' FROM sqlite_master-- - same eror
..
89')) UNION SELECT '1', '2', '3', '4', '5', '6', '7', '8' FROM sqlite_master— - still the same eror
')) UNION SELECT '1', '2', '3', '4', '5', '6', '7', '8', '9' FROM sqlite_master-- - HERE WE ARE!
Working UNION SELECT

So we just need to get rid of the rest of the products and fixed values with:

qwert')) UNION SELECT sql, '2', '3', '4', '5', '6', '7', '8', '9' FROM sqlite_master--
Database Schema – leaked!

⭐⭐⭐Reset Jim’s Password (Broken Authentication)

This one should be less painful. We need to reset Jim’s password via the Forgot Password mechanism with the original answer to his security question.

it should be similar to reseting Bjoenrn’s Password. Hints tell us that the hardest part of this challenge is actually to find out who Jim actually is, and he picked one of the worst security questions and chose to answer it truthfully, but also is a celebrity, and even brute forcing the answer should be possible with the right kind of word list.

Let’s check the question:

Your eldest siblings middle name?

What do we know about Jim from his comments and saved addresses (we know them, because we can hack into his account 😊) ?

It has to be James Tiberius Kirk from Star Trek! On his wikipedia site we can read that ‘James Kirk’s brother, George Samuel Kirk, is first mentioned in “What Are Little Girls Made Of?” and introduced and killed in “Operation: Annihilate!”, leaving behind three children.’

His middle name, Samuel, solves the challenge 😉

{"email":"jim@juice-sh.op",
"answer":"Samuel",
"new":"12345","repeat":"12345"}

⭐⭐⭐Login Bender (Injection)

Let’s make this one quick.  This one is same as Login Jim, so after simple search through comments we know the email address:

Bloody comments…

After simple SQL Injection we are good to go:

login: bender@juice-sh.op’--
pass: x
Success!

⭐⭐⭐Admin Registration (Improper Input Validation)

In this one we have to register as user with administration privileges.

So let’s inspect the register form. After filling the form:

Register form

Our POST /api/Users/ HTTP/1.1 is:

{"email":"x@x.com",
"password":"12345","passwordRepeat":"12345",
"securityQuestion":{"id":11,
"question":"Your favorite book?",
"createdAt":"2020-06-27T11:03:05.009Z",
"updatedAt":"2020-06-27T11:03:05.009Z"},
"securityAnswer":"1"}

With response:

{"status":"success",
"data":{"username":"",
"role":"customer",
"deluxeToken":"","lastLoginIp":"0.0.0.0",
"profileImage":"/assets/public/images/uploads/default.svg",
"isActive":true,"id":19,"email":"x@x.com",
"updatedAt":"2020-06-27T14:48:23.084Z",
"createdAt":"2020-06-27T14:48:23.084Z",
"deletedAt":null}}

But the hint is: you have to assign the unassignable. My best guess would be to repeat the post but with assigned role (and different email):

{"email":"z@z.com",
"password":"12345","passwordRepeat":"12345",
"securityQuestion":{"id":11,
"question":"Your favorite book?",
"createdAt":"2020-06-27T11:03:05.009Z",
"updatedAt":"2020-06-27T11:03:05.009Z"},
"securityAnswer":"1",
"role":"admin"}
“status”:”success”

⭐⭐⭐Payback Time (Improper Input Validation)

This one in real time would make me rich 😊 and that’s the point! We have to ‘place an order that makes you rich.’ With the hint ‘you literally need to make the shop owe you any amount of money’.

So let’s inspect the order process.

I’m going to purchase 1 apple juice (1000 ml) for 1.99¤ .

To make me rich I would like to order -1000 apple juice (to make Juice Shop owe me 1999¤). But this is impossible via UI.

But changing the quantity makes PUT request:

Changing basket

So after simple changing last row to:

{"quantity":-1000}

Response is still:

HTTP/1.1 200 OK

And we can see the magic in our basket 😊

Basket

Order summary is still satisfying:

Order Summary

And… boom! I’m rich 😉

⭐⭐⭐Upload Size & Type (Improper Input Validation)

Now I would like to solve two challenges simultaneously.

I have to: Upload a file larger than 100 kB that has no .pdf or .zip extension. Both challenges contains hints to use Complaint form.

In ‘more hints’ we will find out that:

The Juice Shop offers its customers the chance to complain about an order that left them unsatisfied. One of the juice bottles might have leaked during transport or maybe the shipment was just two weeks late. To prove their claim, customers are supposed to attach their order confirmation document to the online complaint. To prevent abuse of this functionality, the application only allows file uploads of 100 kB or less.

First we should try to understand how the file upload is actually handled on the client and server side.

Then  we will be able to find “weak spot”.

Again, after inspecting main-es2015.js there is uploader() function:

this.uploader = new ra.c({
                        
url: "./file-upload",
authToken: `Bearer ${localStorage.getItem("token")}`,
                        
allowedMimeType: ["application/pdf",
"application/xml", "text/xml", "application/zip", 
"application/x-zip-compressed", "multipart/x-zip"],
                        maxFileSize: 1e5
                    }),

So allowed MimeType is pdf/xml/zip and a maxFile is 1e5, which is 100 000 bytes, so around (little less than) 100 kb.

Let’s check the request for valid, 24kb pdf file (empty word as pdf) that will not be blocked by JS:

File upload request

So the request looks exactly the same, as PDF opened in the Notepad++.

Now I’ll craft a pdf little bit bigger than 100 kB with changed extension and try with the repeater:

Test files

And changed request:

Changing request (different file)

Simultaneously is the new success 😊

Two birds with one stone

⭐⭐⭐Deluxe Fraud (Improper Input Validation)

Last one! Now I have to obtain a Deluxe Membership without paying for it – what a culmination!

We need to look closely at what happens when you attempt to upgrade your account.

Ok… deluxe membership offers me deals and special offers, free fast delivery as well as unlimited purchase. For 49¤ it’s a bargain. Let’s inspect what happens after clicking ‘become a member’.

Deluxe-Membership POST request

Looks like it’s simple POST request with paymentMode.

After chaingng paymentMode into anything else:

{"paymentMode":"HeadFullOfCiphers"}
We become a deluxe member!

Conclusion

Another part of this competition: done!

It was harder this time, so I’m really glad that my ‘hacker mind’ started to growing. To be honest, some of task was challenging. The hardest was of course Database Schema (Injection) with UNION SELECT injection 😊 So my scoreboard looks all-green as I wanted:

Challenge succeeded

I’m in the middle of threstar challenges:

11/22!

And I’m after 34% of all tasks! So I’m after one third!!!

That’s it for today 😊 I’m going for my well-deserved rest and I hope you enjoyed this article!

If you have any questions do not hesitate to contact me!

Reference list:

  1. Pwning the Juice Shop
  2. GDPR-Info
  3. SQL Injection WSTG OWASP
  4. SQLite FAQ Docs
  5. James Tiberius Kirk wiki

Check out related posts:

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: