OWASP Juice Shop : Challenge Pack 2018 (GSoC project report)

OWASP Juice Shop Challenge Pack 2018

This post is supposed to be a report of work done under the project “ChallengePack 2018” of Juice Shop which I did as Student Developer at OWASP as part of Google Summer of Code 2018. For those who are unaware of what Juice Shop is, please do check it out. Its an intentionally kept vulnerable web application which aims to be a learning/practising resource for Web Developer as well as Web Security Enthusiasts. Instead of just making a dry report I will try to document the things that I learned while completing each task that was proposed. I hope it will benefit the future contributers/GSoC students of Juice Shop/WebDevelopers/Hackers as a documentation and will hold the information about what has been happening to Juice Shop over the course of Summer 2018. I will also show exactly which lines of code were made vulnerable to introduce each challenge. Before hand I would like to say that I am still a noob 🤷‍ and have no expertise in WebSecurity and Web Development, So if you feel that something is incorrect then I am totally open to positive criticism. Please comment your thoughts below :). So without further ado, Lets get this started.

Under Google Summer of Code 2018, Juice Shop had two projects, One was my Challenge Pack 2018 whose work is under gsoc-challenges branch and other project was Frontend Upgrade by @Aashish whose work is under gsoc-frontend branch.

Tests For “Old-School XSS” Challenge

Previously (Before start of official coding phase of GSoC), I had designed and added the functionality of tracking user orders and challenge of “Reflected XSS” around it but Unit, Integration and E2E tests for the functinality and challenge were remaining because I was not very good at the test writing technologies of Juice Shop. This PR took quite a lot of time to get complete and merge but along the way I learned about those technologies and purpose of writing tests.

Link to PR : XSS Challenge Tests

“Lateral Privilege Escalation/Insecure Direct Object Reference” Challenge

Although Juice Shop is meant to be fully vulnerable, this bug was unintentinal one and was reported by another user in an issue. Any user was able to post product reviews as any user. The challenge got designed as to post a forged review as another user. It was kind of reassuring to see that even security aware developers can write vulnerable code and vulnerabilities will be always out there.

Link to PR : Forged Review
Vulnerable Code-Snippet :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = function productReviews () {
return (req, res, next) => {
// No check of object ownership :)
db.reviews.insert({
product: req.params.id,
message: req.body.message,
author: req.body.author,
likesCount: 0,
likedBy: []
}).then(result => {
res.status(201).json({ staus: 'success' })
}, err => {
res.status(500).json(err)
})
}
}

“Vulnerable Node Module” Challenge

Node ecosystem heavily relies on node modules and a lot can go wrong if the modules you are using are vulnerable and outdated. This challenge got designed around the recent vulnerability disclosure called Zip-Slip. Archive extraction packages which are used for unzipping archives were allowing arbitrary file write at server-side. I added functionality of Multiple complaint submission through archive upload and designed the challenge of overwriting an important file of the Juice Shop. The hurdle we came upon was to properly sandbox this so that people using Juice Shop over local instance don’t overwrite the important files of their own system by mistake as crafting payload archive for this can result in mistakes because of black-box scenario. I solved it by checking absolute paths of files before extraction.

Link to PR : Vulnerable node module
Vulnerable Code-Snippet :

1
2
3
"dependencies": {
"unzipper": "0.8.12"
}

“Tier 3 NoSQL Injection” Challenge

Juice Shop uses MarsDB as its NoSQL Database. After implementing the challenge of getting orders of all the users, I got quite a context about how and where this bug can happen in NoSQL Databases in general.

Link to PR : NoSQLi Tier 3
Vulnerable Code-Snippet :

1
db.orders.find({ $where: "this.orderId === '" + req.params.id + "'" }).then()

“HTTP Parameter Pollution” Challenge

HPP vulnerability primarily depends upon the reqest body parsers. In the case of Juice Shop, JSON parser was the default one which just takes the value of last paramater present. To implement this challenge I used different parser specifically for this challenge. Scenario of the challenge was very typical where the first occurance of paramater was used for validating but the value was taken for use from last occurance of the paramater in POST JSON body. Challenge was to succesfully edit other user’s basket.

Link to PR : HTTP Parameter Pollution
Vulnerable Code-Snippet :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if (user && basketIds[0] && basketIds[0] !== 'undefined' && user.bid != basketIds[0]) { // eslint-disable-line eqeqeq
res.status(401).send('{\'error\' : \'Invalid BasketId\'}')
} else {
const basketItem = {
ProductId: productIds[productIds.length - 1],
BasketId: basketIds[basketIds.length - 1], // Using value from second occurance bypasses the validation
quantity: quantities[quantities.length - 1]
}
const basketItemInstance = models.BasketItem.build(basketItem)
basketItemInstance.save().then((basketItem) => {
basketItem = {
status: 'success',
data: basketItem
}
res.json(basketItem)
}).catch(error => {
next(error)
})
}

“JSONP/XSSi” Challenge

Even though Juice Shop doesn’t have an actual use case for JSONP because it is just one application running on single domain but for making it a complete learning resource, I added JSONP on an endpoint which returns user’s personal information wrapped up in a function whose name is decided by a GET parameter called callback. The challenge was to guess/bruteforce for this JSONP endpoint.

Link to PR : JSONP
Vulnerable Code-Snippet :

1
2
3
4
5
6
7
8
9
10
11
12
module.exports = function retrieveLoggedInUser () {
return (req, res) => {
const user = insecurity.authenticatedUsers.from(req)
const response = { user: { id: (user && user.data ? user.data.id : undefined), email: (user && user.data ? user.data.email : undefined) } }
if (req.query.callback === undefined) {
res.json(response)
} else {
res.jsonp(response)
}
}
}
}

“Race Condition/Timing Attack” Challenge

This was my favorite challenge to implement because of its complexity and unavailability in any other vulnerable application (as far as I know). Juice Shop can not have race condition bug naturally because it uses MarsDB and it has no reason of having that much observable latency. So we had to add that artificially. Vulnerability and Challenge structure was like following :

Link to PR : Race Condition/Timing Attack
Link to Vulnerable Code-Snippet :

1
https://github.com/bkimminich/juice-shop/pull/617/files#diff-fb4c8fba3911529be7878d2553b1fed1

“Mass Assignement” Challenge

Mass assignment Vulnerability is very prevalent in web technologies where request’s body is mapped to objects directly using some library etc. In Juice Shop the users can become admin while signing up by adding an ingeniosly guessed extra parameter called isAdmin by looking at reponses. which gets mapped to database column without any check and users get admin privileges.

Link to PR : Mass Assignement
Link to Vulnerable Code-Snippet :

1
https://github.com/bkimminich/juice-shop/pull/629/files#diff-45182e43f88790a0b1fdc8479ebb66b1

“Exploit Chain 1” Challenge

From the start I wanted to add a cool vulnerability chain in the Juice Shop. The exploit chain was supposed to be a chain of Login CSRF paired with Self XSS where XSS payload was sent through True-Client-IP header. But due to Juice Shop’s solution checking mechanism and standalone nature, We decided to convert the chain to simple XSS.

Link to PR : Exploit Chain 1
Vulnerable Code-Snippet :

1
$rootScope.lastLoginIp = $sce.trustAsHtml(user.lastLoginIp)

As you can see, Even adding XSS intentionally in angular apps is tough. So my advice to all hunters, As soon as you see target is using angular, stop spraying XSS payloads.

“Server Side Template Injection” Challenge

This was one of my another favorite challenge to add. Initially Juice Shop used Client side rendering and was totally secure to SSTi. For adding this challenge I added the user profile page which was rendered using the jade template engine. Username field was made vulnerable to SSTi. SSTi is basically RCE for modern application which use Server Side template engine. To make this new RCE bug more cool, @Jannik suggested a very cool challenge around it which involved exploiting this RCE to infect the Juice Shop server with malware. Yep 😎 !

Link to PR : Server Side Template Injection Yet to be merged.
Vulnerable Code-Snippet :

1
2
3
templateString = templateString.replace('usrname', user.dataValues.username)
var fn = jade.compile(templateString)
res.send(fn(user.dataValues))

“Server Side Request Forgery” Challenge

SSRF is a critical vulnerability if attacker is able to pivot into internal network of the target. As Juice Shop being a standalone application, doesn’t have it. So a very basic version of SSRF was implemented around the functinality of image upload using URL. The challenge gets solved when you request a hidden resource of Juice Shop server. The hidden resource is supposed to be obtained from the malware of SSTI challenge 😁.

Link to PR : Server Side Request Forgery Yet to be merged.
Vulnerable Code-Snippet :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module.exports = function profileImageUrlUpload () {
return (req, res, next) => {
var url = req.body.imageUrl
request
.get(url) // Requesting without any check
.on('error', function (err) {
console.log(err)
})
.pipe(fs.createWriteStream('frontend/dist/frontend/assets/public/images/uploads/' + loggedInUser.data.id + '.jpg'))
}
res.location('/profile')
res.redirect('/profile')
}

Abandoned/Postponed Challenges

  1. ImageTragick Challenge
    The reason behind abandoning this challenge was that it required a vulnerable imagemagick binary to be installed on users personal system which might cause big concerns regarding safety of users systems.
  2. Angular Template Injection Challenge
  3. Facebook Oauth Challenge
    I planned to add this challenge as soon as the SSTi-SSRF PR gets merged.

Miscellaneous

Apart from working on challenge pack, I also helped fix some of the broken functinalities after the major merging of Frontend Upgrade project into Challenge Pack. This was quite time taking as only @Aashish knew about the new frontend codebase. But this frontend technology upgrade was very much required for Juice Shop as it aims to properly be like modern JS web applications.

Contributions before official start of GSoC-2018


  1. CAPTCHA on feedbackform and Challenge
  2. Easter Egg Customization
  3. Rate Limiting and its circumventionn challenge
  4. Customization in Product Tampering Challenge
  5. Order Tracking Dashboard

Hope you learnt something new after reading this. If you haven’t already read my Google Summer of Code 2018 blog then please read it ☝.
I had very good learning experience while working for OWASP Juice Shop. I will recommend every student who loves web security and developement to contribute to the Juice Shop Project.

Thanks for reading the blog post.
GodSpeed and Happy Hacking 😎.