📙
AppSec
  • Overview
  • Write Ups Compilations/Resources
  • Main Resources
  • Labs
  • Cross Site Request Forgery
    • Cross Site Request Forgery (CSRF)
      • Write-ups
      • Source Code Examples
      • Labs
  • Missing Access Controls
    • Missing Access Controls
      • Write-ups
      • Source Code Examples
      • Resources
      • Testing Tips
  • LFI / Directory Traversal
    • Local File Inclusion
      • Local File Inclusion Writeups
      • Source Code Examples
      • Labs
  • XXE
    • XML External Entity (XXE)
      • Write-ups
      • Source Code Examples
      • Labs
      • More Writeups
      • Payloads
      • Resources
  • Injection
    • Command Injection
      • Writeups
    • Server-Side Template Injection
      • Server-Side Template Injection Writeups
      • More Write-ups
      • Source Code Examples
      • Labs
      • Resources
      • Payloads
      • Tools
    • SQL Injection
      • SQLI Write-ups
      • Source Code Examples
      • More Write-ups
      • Labs
      • Resources & Tools
  • SSRF
    • Server-Side Request Forgery (SSRF)
      • SSRF Write-ups
      • Source Code Review
  • Unvalidated Redirects and Forwards
    • Unvalidated Redirects and Forwards
      • Writeups
      • Source Code Examples
  • Verbose Error Messages and Stack Traces
    • Verbose Error Messages and Stack Traces
      • Write-ups
Powered by GitBook
On this page
  • OWASP Juice Shop
  • Damn Vulnerable Web App

Was this helpful?

  1. SSRF
  2. Server-Side Request Forgery (SSRF)

Source Code Review

PreviousSSRF Write-upsNextUnvalidated Redirects and Forwards

Last updated 4 years ago

Was this helpful?

OWASP Juice Shop

There is a SSRF vulnerability on OWASP Juice Shop on the profile page via the image upload functionality. When clicking on the Link Gravatar button with a user supplied input, the backend server reaches out to the supplied URL to download the image. When a user supplies a URL and clicks 'Link Gravatar' the server sends a HTTP request with the imageUrl parameter that is vulnerable to SSRF.

The code below is profileImageUrlUpload.js. This code handles the functionality for URL image upload.

The profileImageUrlUpload function checks if the user is logged in on line 18, if so it sends a HTTP request to the specified URL. There are no input checks done on the URL such as an allow-list check to make sure the URL being accessed is explicitly allowed. In the challenge you need to supply a backend URL in the imageUrl parameter to complete the challenge and perform SSRF on a backend server. The URL to supply is http://localhost:3000/solve/challenges/server-side?key=tRy_H4rd3r_n0thIng_iS_Imp0ssibl3

/*
 * Copyright (c) 2014-2021 Bjoern Kimminich.
 * SPDX-License-Identifier: MIT
 */

const fs = require('fs')
const models = require('../models/index')
const insecurity = require('../lib/insecurity')
const request = require('request')
const logger = require('../lib/logger')

module.exports = function profileImageUrlUpload () {
  return (req, res, next) => {
    if (req.body.imageUrl !== undefined) {
      const url = req.body.imageUrl
      if (url.match(/(.)*solve\/challenges\/server-side(.)*/) !== null) req.app.locals.abused_ssrf_bug = true
      const loggedInUser = insecurity.authenticatedUsers.get(req.cookies.token)
      if (loggedInUser) {
        const imageRequest = request
          .get(url)
          .on('error', function (err) {
            models.User.findByPk(loggedInUser.data.id).then(user => { return user.update({ profileImage: url }) }).catch(error => { next(error) })
            logger.warn('Error retrieving user profile image: ' + err.message + '; using image link directly')
          })
          .on('response', function (res) {
            if (res.statusCode === 200) {
              const ext = ['jpg', 'jpeg', 'png', 'svg', 'gif'].includes(url.split('.').slice(-1)[0].toLowerCase()) ? url.split('.').slice(-1)[0].toLowerCase() : 'jpg'
              imageRequest.pipe(fs.createWriteStream(`frontend/dist/frontend/assets/public/images/uploads/${loggedInUser.data.id}.${ext}`))
              models.User.findByPk(loggedInUser.data.id).then(user => { return user.update({ profileImage: `/assets/public/images/uploads/${loggedInUser.data.id}.${ext}` }) }).catch(error => { next(error) })
            } else models.User.findByPk(loggedInUser.data.id).then(user => { return user.update({ profileImage: url }) }).catch(error => { next(error) })
          })
      } else {
        next(new Error('Blocked illegal activity by ' + req.connection.remoteAddress))
      }
    }
    res.location(process.env.BASE_PATH + '/profile')
    res.redirect(process.env.BASE_PATH + '/profile')
  }
}

//profileImageUrlUpload.js
//https://github.com/bkimminich/juice-shop/blob/master/routes/profileImageUrlUpload.js

Damn Vulnerable Web App

Juice Shop Gravatar Link Input