Source Code Examples
OWASP Juice Shop
One route on the OWASP Juice Shop application allows for a CSRF exploit, the route to make changes to your user profile. The /profile HTTP POST route accepts a username body parameter and does not implement any anti-CSRF practices.
This can be exploited by the following code:
<form action="http://localhost:3000/profile" method="POST">
<input name="username" value="CSRF"/>
<input type="submit"/>
</form>
<script>document.forms[0].submit();</script>As seen in the code below, there are no anti-CSRF practices implemented in the code. The controller merely checks whether user is logged in on line 19, it then retrieves the id of the user from session cookie. The utils.solveIf function checks whether or not the user successfully solves the challenge. The only requirement for this one challenge is that the above payload form/script are used in the htmledit.squarefree.com domain. When the exploit code above is run on the squarefree domain it adds the HTTP Origin & Referer headers, successfully bypassing that control and allowing the username to be edited.
//https://github.com/bkimminich/juice-shop/blob/master/routes/updateUserProfile.js
//UpdateUserProfile.js
/*
* Copyright (c) 2014-2021 Bjoern Kimminich.
* SPDX-License-Identifier: MIT
*/
const models = require('../models/index')
const insecurity = require('../lib/insecurity')
const utils = require('../lib/utils')
const cache = require('../data/datacache')
const challenges = cache.challenges
module.exports = function updateUserProfile () {
return (req, res, next) => {
const loggedInUser = insecurity.authenticatedUsers.get(req.cookies.token)
if (loggedInUser) {
models.User.findByPk(loggedInUser.data.id).then(user => {
utils.solveIf(challenges.csrfChallenge, () => {
return ((req.headers.origin && req.headers.origin.includes('://htmledit.squarefree.com')) ||
(req.headers.referer && req.headers.referer.includes('://htmledit.squarefree.com'))) &&
req.body.username !== user.username
})
user.update({ username: req.body.username }).then(newuser => {
newuser = utils.queryResultToJson(newuser)
const updatedToken = insecurity.authorize(newuser)
insecurity.authenticatedUsers.put(updatedToken, newuser)
res.cookie('token', updatedToken)
res.location(process.env.BASE_PATH + '/profile')
res.redirect(process.env.BASE_PATH + '/profile')
})
}).catch(error => {
next(error)
})
} else {
next(new Error('Blocked illegal activity by ' + req.connection.remoteAddress))
}
}
}The only requirement to solve this challenge was to use the CSRF exploit code on the htmledit.squarefree.com application to have that domain in the Referer and Origin HTTP Headers. There is no CSRF token in use.
Damn Vulnerable Web App (DVWA)
The following contains source code files from the DVWA.
The examples reviewed below are for the CSRF vulnerability challenge in DVWA. The functionality in the CSRF challenges is for changing a users password.
DVWA CSRF Low Level Security
The number one thing that sticks out is that the password change functionality does not force the user to supply their existing password to validate it. This is a bad practice (unrelated to the CSRF finding).
Besides that there are no CSRF protections in this code, the code merely checks if both passwords supplied are the same then updates the password for that user. So any user supplied this link that clicks on it will have their password changed to 'abc123' if they are logged into the application in another browser tab:https://DVWA/dvwa/vulnerabilities/csrf/?password_new=abc123&password_conf=abc123&Change=Change
DVWA CSRF Medium Level Security
The Medium level of this csrf example controller password reset implements the addition of the code on line 5. This code checks whether the HTTP Header Referer and Server name match. Supplying the correct referer will bypass this protection. Referer: https://DVWA/DVWA-master/vulnerabilities/csrf/
DVWA CSRF High Level Security
The high level code implements a CSRF token that is generated and supplied with the form, in the user_token field, to change the password client side. The code on line 5 checks whether this unique nonce (CSRF token) is correct. This is not exploitable directly, but using a combined exploit with XSS it is possible to extract this token to bypass this protection. However by itself if there were no other vulnerabilities that could be chained on this app, this code would be a sufficient CSRF protection however the Impossible level code is superior in that it sanitizes and checks the existence of the supplied password (see section below).
DVWA CSRF Impossible Level Security
This code checks the CSRF token, checks the current existing user password to ensure the user knows it, and sanitizes user input for the SQL queries.
Last updated
Was this helpful?