sql-labs
Last updated on 6 months ago
sqlilabs安装
下载
1.下载phpstudy
2.在www文件夹下https://github.com/Audi-1/sqli-labs.git
3.在sql-connections文件夹下,打开db-creds.inc文件(用notepad++方便),更改密码为root,复制security
配置
1.phpstudy面板,打开mysql工具,mysql命令行
2.create database security;
3.use security
4.sql文件导入数据库,此处需要用到sql-lab.sql文件,source (C:\software\phpstudy\WWW\sqli-labs\sql-lab.sql)(sql-lab.sql的文件路径)
打开
http://localhost/sqli-labs
点开第一个set up,再返回即可
基础查询
information_schmea
这个是自带的数据库,从这里可以查询建立的数据库名及表名
查表名
select table_name from information_schema.tables where table_schema=database()
(table_name存储所有表名,table_schema存储所有数据库名)
(这里的顺序是先用database()得到数据库名,用数据库名赋值给table_schema,从而限定information_schema.tables的查找范围限定在当前数据库,再查询对应的表名)
1 |
|
前面的查询可能会只查询出一条结果,但是实际要查的表名可能很多,比如passwd和key,这样用group_concat就可以联合查询,让所有内容一起输出
假设查出的表名为stu
查列名
select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name = 'stu'
(加where table_schema=database()是为了防止有不同数据库内有重复表名的存在)
查信息
1 |
|
常见函数
函数名 | 例子 | 作用 |
---|---|---|
group_concat() | group_concat(id,name,passwd) / group_concat(version(),database()) | 将()内的内容聚合到一行输出 |
database() | 查询数据库名 | |
version() | 查询版本信息 | |
union查询
原理
正常使用:
select * from stu where id = 1 union select * from coach where id = 1
1 |
|
id | name | age |
---|---|---|
1 | xiaoming | 12 |
1 |
|
id | name |
---|---|
1 | dk |
结果会回显stu的id,name,age的内容和coach的id和name的内容,但是coach少了一列,而union查询必须要前后列一致,所以需要补齐查询
1 |
|
这样查询的结果就都是三列了
注入查询:
通常在页面内的回显只会是返回查询stu的内容而不是coach的内容,所以可以查询stu中空的内容来显示coach的内容,比如查询stu的id为-1,在查询时使用union 查询,通常会查询数据库名或者服务器版本信息等
1 |
|
字符类型
如果输入的变量是字符类型(string),那么查询之后要加上单引号或者双引号,id=’1’这样的
如果输入的变量是整型(int),那么不需要加上引号或各种括号进行闭合,比如id=1
列的数量
order by或者group by都可以,group by可能会出现一些奇怪的东西,但是order by会被waf记录,而group by则不会
原理
order by
正常使用
比如一个数据表有每个人的成绩,第一列是学号,第二列是姓名,第三列是成绩(score),那么order by 3
跟order by score
就是等效的,是按照学生的成绩对表单进行排序
注入查询
这个表单只有三列,到order by 3还可以正常显示,order by 4就会报错,所以表明表单只有3列
group by
正常使用
表单有三列,第一列是名字,第二列是性别(gender),第三列是成绩(score),通常group by会和其它查询函数联合使用,比如avg() average平均值,联合查询后,就会只有两列,group将按照gender将表单的所有行分成男女两组,并分别求平均值
注入查询
同上
报错查询
extractvalue()
1 |
|
用于查询xml数据,正确用法是extractvalue(数据类型,数据路径)
这里只能用concat而不能用group_concat(),concat是单纯将两个及以上字符连接起来,而group_concat是将查询的结果连接起来,而且group_concat()后要跟上group by才能正常使用,而select group_concat(table_name) from information_schema.tables where table_schema=database()
可以不跟group by就直接使用是因为information_schema.tables本身就是一个group(理解成隐式群组)
必须要用concat()进行联合查询是因为extractvalue()必须是数据类型和数据路径,在数据类型这里可以选择错误的内容,而数据路径要更改为需要查询的内容,直接select是进行一个查询,而这里需要一个字符串(用括号将select查询包裹起来也不可以,不知道为什么)
笔记
Lession1
2.用sqlmap跑一下试试(主要是没看懂教程网课说的是什么意思)sqlmap.py -u http://localhost/sqli-labs/Less-1/?id=1
返回给我四个类型的注入
基于布尔型盲注
1.概念:构造可以判断为真或假的SQL逻辑语句,根据页面返回的结果是否正常来判断语句结果是真或假。典型的构造方式是使用“AND 1=1”(真)或“AND 1=2”(假)。(源自claude)
就是在url界面输入值后,是否会在页面进行显示内容,比如本题,进行注入'and 1=1 --+
此时结果为真,可以返回id=1的值,如果结果为假,例如1=2,由于是and语句,前后都为真才可执行,id=1为真,1=2为假,所以语句不执行,则返回空值
2.步骤:确认注入点、信息收集和利用(同样来源于claude)现在应该还学不到那种程度,现在可以利用简单的函数来判断一些数据,比如length(database())这个函数,可以判断数据库名称的长度是多少,比如现在的数据库(database)的名称是security,那么length(database())返回值就是8(应该可以配合burpsuite的爆破使用,爆破出正确的值,然后根据这个正确的值注入,后面的ascii同理)
ascii判断:?id=1’ and ascii(substr(database(),1,1))=33 –+ 比如security这个数据库第一个字母为s,ascii码值为115,所以
(剩下的还没学明白)
注释符号
单引号报错
两个单引号可以
原语句select * from table where id = '$id'
假设现有的两个’分别记为1号,2号
注入语句为?id=1'
这里的’记为3号,注入后select * from table where id = '$id''
,此时’分别为1,3,2号,那么拼接后的语句1,2号为引号但是3号没有与之配对的,所以会报错,但注入双引号之后,就是1332,12正常配对,33配对引起的内容为空,但是不会报错(传入参数的分号配对优先级低于原来的’’,所以前面可以用3号分号跟原来的1号配对,而2号则被注释掉了)select * from table where id = '1'and 1=2''
Lession2
注入语句 | y/n |
---|---|
?id=1 and 1=1--+ |
y |
?id=1' and 1=1--+ |
n |
?id=1' and 1=1 |
n |
?id=1 and 1=1 |
y |
所以后台语句为select * from table where id = $id
Lession3
单引号起手尝试
报错,但是看到报错里有),推测原查询语句为select * from table where id = ('1')
或select * from table where id = '(1)'
先尝试?id=1)' and 1=2 --+
,这里猜测原语句为select * from table where id = '(1)'
如果是这个则注入之后就是select * from table where id = '(1)'and 1=2--+)'
如果是这个,则原来的括号和引号被注释掉
报错,所以这个不对,那么猜测原语句为select * from table where id = ('1')
然后再尝试注入?id=1') and 1=2 --+
,如果是这个则注入后为```select * from table where id = (‘1’)and 1=2–+)’
Lession4
Lession5
找原语句还是没什么太大问题,但是看着不少教程从这一关开始搞爆破了,所以跟着走一遍
注入代码?id=1' and 1=2--+
不报错,但是不显示内容,所以原语句是select * from table where id = '$id'
爆破数据库名称 substr(database(),1,1)
不是s的情况
但是bp还没搞明白怎么逐个字母爆破,所以改成ascii码值,a-z的ascii码值分别是97-122,所以注入语句改为?id=1' and ascii(substr(database(),1,1))=115
以及非115的情况
现在用bp爆破一遍
1.代理抓包
2.右键,发送到intruder
3.清除原有payload,选定115为新的payload
4.
5.爆破
捯饬了一下找到怎么用字母爆破了
前三步一样,但要用ascii()包起来原来的参数,payload集还是1,类型由数值改为简单列表,点击payload设置>>从列表添加
Lession6
一开始傻了,以为双引号就是两个单引号,一直找不到语法报错提示,改成shift+”就有正常报错提示了,跟第五关差不多
Lession7 GET-Dump into outfile
这个可以注入文件 dump是临时存储的数据,outfile是上传文件,就是通过url框向服务器传入一个文件,文件的内容就是在url框里查询出来的内容
注入语句?id=1')) union select 1,3,4 into outfile "E:\\phpstudy\\PhpStudy2018\\PHPTutorial\\WWW\\sqli-labs\\Less-7\\a.php"--+
union必须带 后面只能穿3个参数,可能是因为源文件就这么设置的 into outfile是固定语句
踩得一些坑:SHOW VARIABLES LIKE "secure_file_priv";
查看状态 ,如果是空值就可以成功注入,如果是null则不行
如果是null的话需要打开mysql.ini文件(claude说的是mysql.cnf),添加secure_file_priv = ''
一开始添加在文件的最下面,但是不行,然后加在[mysqld]的下面,重新重启phpstudy可以注入了
Lession8
又是布尔盲注,但看攻略也没发现跟前面的基于错误报错有什么区别,试一下爆出版本号
mid()函数?id=1' and mid(version(),1,1)=5 --+
?id=1' and mid(version(),1,2)=5.0 --+
Lession9
不知道为什么0 1都是一样的you are in…,再用sqlmap跑一次
用时间注入,从29秒开始可以注入,应该是?id=1'and if(length(database())=7,sleep(3),1) --+
if(判断,如果对则,错则) 错的返回值(结果集)填什么都可以,但必须要填,就比如select * from table where id = 1
返回值就是id=1的所有字段,所有字段就是结果集
Lession10
跟9差不多,但是双引号
1 |
|
Lession11 Post
一上来界面就不一样了,变成一个输入账密的代码框,一开始各种乱试瞎猜都没成功,唯一一次有点沾边的想法是username框不能给注释掉,要不然password就输入不进去了,搜了教程才想明白
1 |
|
所以想要注入应该是在username框输入 admin' and 1='1
这样admin左边原来有一个分号,右边在代码框输入了一个分号,而’1 右边有原来属于’$username’的右边的分号,这样就齐活了select * from table where uname='$username' or 1=1 and passwd = '$password'
这个语句包括了三个判断条件,$username存在,1=1,$password存在,但是因为1=1为永真,所以剩下两个只要一个有就能查出来
Lession12
单引号边双引号