从此记录SQL-labs的学习经历和笔记,主要留下在学习过程中遇到的难点和顿悟点
集成环境:Wampserver(直接安装即可,可能php.ini需要修改)
题目地址:https://github.com/Audi-1/sqli-labs
安装:
- 从https://github.com/Audi-1/sqli-labs下载压缩包
- 将zip文件复制到mysql中的www文件夹下
- 打开sql-connections文件夹下的“db-creds.inc”文件
- 修改mysql用户名和密码为你自己的(没有设置过用户名可以不用管这步)
- 访问localhost下的文件夹:点击页面第一栏setup/resetDB 链接自动回在你的mysql中创造数据库
参考链接:
一、lesson 1:GET-基于错误-单引号字符型
1.如何理解单引号没有闭合会报错
回顾注入类型:
数字型注入 select * from news where id=$id
字符型注入 select * from news where username='$name'
搜索型注入 select * from news where password like %best%
首先在http://localhost/sqli-labs-master/Less-1/中加入?id=1(用数值型注入得到一个id参数,?表示传参)。这个链接在SQL语言中可以理解为查询语句:$sql=” SELECT * FROM users WHERE id=’1’或者id=1或者like %1%;这是合法的。在hackerbar中输入excute之后是会返回数据库值的。
以字符型为例,如果加入?id=1’。那么查询语句变为$sql=”SELECT * FROM users WHERE id=’1’‘。excute后返回错误信息:
You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax
to use near ''1'' LIMIT 0,1' at line 1
上述错误信息可以说明:
- 现在注入的是mysql数据库
- 验证了现在真正的查询语句可能是
- $sql=” SELECT * FROM users WHERE id=’$id’ LIMIT 0,1 “
在输入?id=某某的时候,也就是给$id传参了($id=1’)。传参之后语句变为
$sql=" SELECT * FROM users WHERE id='1'' LIMIT 0,1 "
三个引号不成对了,mysql_query()不接受了,不知道引号怎么配对了,所以就报错了。 如果改成?id=1’‘,那么查询语句是
$sql="SELECT * FROM users WHERE id='$id''' LIMIT 0,1"
现在引号是双数,成对了,单引号都闭合了,就能返回数据库的值,不报错(说明不是搜索型)。
再者,将查询语句变为:?id=4’ and 1=1 +–+不报错,说明有单引号闭合,不是数字型也不是双引号型。
由此判断less 1是字符型(可以参考less2中的数值型)
2.LIMIT语句:偏移筛选
在语句中的 LIMIT 0,1 这一句是对查询结果的一个偏移,因为$sql=”SELECT * FROM users WHERE id=’$id’ LIMIT 0,1”;语句会显示这个id列中所有的行,但是网站在搭建的时候筛选了能显示的信息量(本题是两个—因为通过前面?id=1,返回两个信息dumb,dumb),因此我们就没法通过加上?id=1来显示id=1列的所有的行。但是又想知道这个列的所有数据,这时候就用limit来遍历(每次显示两个数据,偏移多次,显示多个不同的两个数据)。
这就要通过limit语句。 LIMIT 语句第一个表示起点,第二个表示步长。 因此 LIMIT 0,1这个语句将会显示第一行。同理,如果要显示第 6-15 行,我们需要使用 LIMIT 5,10 来进行限制。
3.注释
- MySql 的注释符号有 “+–+, – (后面有空格符), #”等
- #…:从‘#’字符从行尾。
- – …: 从‘– ’序列到行尾。请注意‘– ’(双破折号)注释风 格要求第2个破折号后面至少跟一个空格符(例如 空格、tab、换行符等等)
- /…/:从/序列到后面的/序列。
- 但是实际在操作的时候 %,#,– 都不能达到效果,需要将其转化为 URL 编码才能被正确的传到后台。
- 因此在地址栏注入时,可以直接使用+–+但是不可以使用#,而要写成为%23
- 比如:union select 1,2,table_name from information_schema.tables where table_schema=’数据库名’ +–+或
- union select 1,2,table_name from information_schema.tables where table_schema=’数据库名’ %23
- 为什么要注释掉后面?
- 因为要$sql=”SELECT * FROM users WHERE id=’$id’ LIMIT 0,1”在传参时例如传入1’ union select 1,2,3 +–+
- 这时候利用输入值中的1’中的’时使得原来的引号sql语句中前引号闭合,加入注释使得后引号被注释掉,不起作用。那么这时候就可以形成自定义的查询语句不受引号闭合影响。
- 查询语句具体为:SELECT * FROM users WHERE id=’1’ union select 1,2,3 +–+’ LIMIT 0,1
- 其中的’ LIMIT 0,1被注释掉了
爆字段
使用 order by 函数加上多行来爆字段,当数字为 3 时没有报错;当数字加到 4 的时候提示没有该列,因此字段数为 3。
order by 1,2,3,4 表示按照 1,2,3,4, 列去排列查找到的数据,由于只有 3 列,当我们试图用第 4 列去排序的时候自然会报错。
或者用order by 加上数字。例如order by 3或者order by 4
union查询数据库,版本,数据库用户
由爆字段order by可知 union select中要求的:
- 两个查询返回的列数必须相同
- 两个查询语句对于列返回的数据类型必须相同
可知前一个select的列数为3,所以现在select 后面只能跟3个待查询值。
此外:union select 和前面的查找是并集的关系(两个select语句查询的结果合并成一个表统一显示,列名按照第一个select的列)。由于显示的位置只有两个,我们必须让前面查找不出结果,这样合并后,就会显示出我们需要查找的内容。比如把 id 设置为 - 1,注意在查找时仍然要闭合好前面的单引号。
相关union指令的使用参见: 菜鸟教程:SQL UNION指令
之后,使用 union select 1,2,3 来判断下网页上会显示哪一列,然后再把相应的位置来替换成需要的信息。此时显示出:Your Login Name:2,Your Password:3。说明应该把2,3位置替换成需要的信息。
查找以下项目来收集所需信息:
- 版本信息:version()
- 数据库信息:database()
- 用户信息:user()
- 当前用户:current_user()
- 数据库路径:@@datadir
- MySQL 安装路径:@@basedir
- 操作系统:version_compile_os
查询表、查询列、查询数据
枚举数据库并提取数据的步骤: 数据库名称->表->列->数据
若要想获取远程数据库的表、列,就要访问专门保存描述各种数据库结构的表。(通常将这些结构描述的信息成为元数据)。
在Mysql中,这些表都保存在information_schema数据库中。
提取数据库:
在MySQL中,数据库名存放在information_schema数据库下schemata表schema_name字段中
`?id=-1' union select null,schema_name,null from information_schema.schemata +--+`
如果要遍历所有数据库名可以加上limit k,1
例如:
?id=-1' union select 1,schema_name,null from information_schema.schemata limit 2,1 +--+
可以爆出表名:information_schema,mysql,security……
提取表名:
在MySQL中,表名存放在information_schema数据库下tables表table_name字段中。
union select 1,2,table_name from information_schema.tables where table_schema='数据库名' +--+
此时可以使用where子句来筛选了,只返回上述以提取过的数据库名中某个数据库下的表名。若想返回所有表名,去掉where子句就行了(但是由于本题只可以显示两个信息位,因此还是需要limit k,1来进行遍历)。 例如:
?id=-1' union select 1,schema_table,null from information_schema.tables
where table_schema='security' +--+
提取字段名(列名):
在MySQL中,字段名存放在information_schema数据库下columns表column_name字段中。用where子句限制哪个数据库的哪个表。
union select 1,2,column_name from information_schema.columns where table_schema='数据库名'
and table_name='表名' limit 0,1 +--+
例如:id=-1’ union select null,column_name,null from information_schema.columns where table_schema=’security’and table_name=’emails’ +–+
提取数据:
按照需要select某个列的数据信息。
union select 1,2,username from users limit 3,1 +--+ 来获取具体的数据信息。
总结上述,是提取security数据库中的users表的id/username/password列的数据的过程。
concat_ws 函数
使用 concat_ws 函数可以获取多条数据并用所要求的符号分割开。
详见:concat、concat_ws、group_concat函数用法
例如:concat_ws(char(32,58,32),username,password)就可以同时显示出用户名和密码,用 “空格、冒号、空格” 来分割 PS:char()将ascii码转化为字符
- 32ascii表示’ ‘
- 58ascii表示: