注:只是自己学习记录,若有不对的地方请指出,文章有过一次修改,修改了关于order by函数的知识点


SQL注入基本教程

    • 数据库的结构
    • 注释符
    • SQL注入简单教程

数据库的结构

学习SQL注入首先要知道数据库的结构
数据库由三个部分组成:数据库——表——列

在初始化安装MySQL数据库后有四个默认的库:
information_schema
mysql
performance_schema
test

information_schema
保存着数据库中所有数据库的信息,具体有数据库中有那些表,和表中的字段。
tables表,其中tales表中含有数据库中所有的表,有一个检索的功能:

•	table_schema列:存放着所有数据库的名字
•	table_name列:存放着所有数据库的表的名字

columns表中:

•	table_schema列:存放着所有数据库的名字
•	table_name列:存放着所有数据库的表名
•	column_name列:存放着所有数据库的列名

schemata表:
存放着所有数据库的名字

•	schema_name列:存放着所有数据库的的名字。只有数据库的名字

所以注入时常用information_schema

mysql:
这个是mysql的核心数据库,类似于sql server中的master表,主要负责存储数据库的用户、权限设置、关键字等mysql自己需要使用的控制和管理信息。不可以删除,如果对mysql不是很了解,也不要轻易修改这个数据库里面的表信息。

performance_schema
mysql5.5 版本 新增了一个性能优化的引擎,performance_schema这个功能默认是关闭的。

test
没有东西

基础的查询语句:
查询语句:select table_schema from information_schema.tables
数据库和表的连接用”.
这条指令是查询information_schema数据库的tables表中查询table_schema表的值

查询语句:select group_concat(table_schema) from information_schema.tables
函数:group_concta(将相同的行组合起来)

执行语句:insert into information_schema.tables(id,name,password) values(9,zxt,toor)
添加东西到表里面

注释符

搭建好环境后可以开始做题了
先记录一个知识点注释符:–+和#和/**/的使用
在mysql中–和#代表的是注释符
mysql中单行注释#号,使用方法是注释符后直接加注释内容
而–则是要在后面加一个空格才能生效,实现注释的作用。

能看到这里的命令没有执行-- 后面的语句。
这也就是在做题中输入–
显示语法错误的原因,为什么要输入–+呢?因为+等于空格,所以在注入中才要输入–+

SQL注入简单教程

在做题前,先修改一下环境,在环境中加入:echo "有效语句:".$id."<br>";echo "MySQL执行语句:"."$sql"."<br>";
如下:

if(isset($_GET['id']))
{
$id=$_GET['id'];
echo "有效语句:".$id."<br>";
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity 
 
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
echo "MySQL执行语句:"."$sql"."<br>";

然后按照要求输入参数id
输入:?id=1
可以看到我在url中输入的参数就相当于在sql中执行了:SELECT * FROM users WHERE id=‘1’ LIMIT 0,1

判断注入类型,注入类型分为两种:字符型,数字型。
那么如何判断呢?
就拿这个题目来说,我输入:?id=1 and 1=1,正常回显,输入:?id=1 and 1=2,正常回显。

观察这个地方,注意,我输入的参数是 ?id=1 and 1=2 ,如果是数字型注入的话,这里就会有一个逻辑判断,会判断出1不等于2,没有语法错误但有逻辑错误,所以返回一个null值,返回错误页面。
也就是在url中输入: id=1 and 1=1?正常回显,输入: ?id=1 and 1=2 报错就说明这是数字型注入。注意不一定要输入?id=1 and 1=1,主要是要进行一个逻辑判断,如果逻辑错误就会返回错误。从而判断是数字型注入。

那这个为什么没有报错呢?因为在sql中字符串应该要被单引号或者双引号来闭合声明这是一个字符串,所以url的参数传入到sql里的语句就是:SELECT * FROM users WHERE id=‘1 and 1=2’ LIMIT 0,1,也就是说我输入的值变成了字符串,整个值都传给了id,数据库此时接收到语句后会把admin and 1=1当作是一个查询条件,而不会进行逻辑判断,怎么解决呢?

输入:?id=1' and 1=2

在1的后面添加一个’号。于前面的’引号闭合,声明了1是一个字符串,这样后面的and 1=2就不会被闭合,判断为字符串。
在sql中的语句就变成了SELECT * FROM users WHERE id=‘1’ and 1=2’ LIMIT 0,1
执行一下,显示结果报错,但这个报错不是逻辑报错,是sql语句错误。

因为sql中的语句SELECT * FROM users WHERE id=‘1’ and 1=2’ LIMIT 0,1,多了一个单引号,我们添加了一个单引号,导致后面的单引号没有闭合,所以sql语句报错,在and 1=2后面添加注释符–或者#,来注释掉这一个单引号。

输入:?id=1' and  1=2 --+

逻辑错误,返回一个空值,这就是字符型注入。

简单来说就是构建一个逻辑判断,and 1=1可以执行,那么and 1=2,1不等于2,正常来说应该返回一个空值。如果返回,就是数字型。
不返回就说明他加上了单引号或者双引号,我们输入的值变成了字符串,整个值都传给了id,就是字符型注入

为什么要在注释符--后面加+号呢?因为--在sql中要在后面加一个空格才能实现注释的作用,而+号在sql中是空格的意思
and 1=2正常执行了,可以把and 1=2换成正常的查询语句,来执行一些查询语句。

输入:?id=1' order by 3 --+

没有报错

输入:?id=1' order by 4 --+

输入4报错,没有第4列,说明一共有3列

通过order by来判断字段数,通过字段数得知多少列,因为order by 是通过字段数量进行排序,也就是列数排序,我后面要使用联合查询,联合查询必须要知道第一个select语句查询了几列
如下:
查询数据库security.users表里面所有的列,可以看到有三列,这里我order by后面输入小于3的数字都是显示的三列,但如果输入的数字大于三就会报错,因为它没有第4列。

报错信息:

输入:?id=-1' union select 1,2,3 --+

判断显示位,可以看到2,3字段是显示位,那么下面就可以查询数据库了

输入:?id=-1' union select 1,2,database() --+

可以用database()来代替2,3中的其中一个来显示查询结果
使用联合查询查询数据库,union select是联合查询语句,这里?id=1,改成?id=1,如果不改的话执行后就不显示显示后面的内容,仍然查询的第一个的内容,也就是仍然查询?id=1,那么把?id=1的写成0或-1就可以了,写成它查询不到的内容,它比较发现是-1或者0那么它返回的值就是null,就会执行后面的内容。

database()函数作用是返回当前数据库名称

这一步也可以输入:?id=-1' union select 1,2,group_concat(schema_name) from information_schema.schemata --+

这条语句的意思是从数据库information_schema的schemata的表里面查询schema_name这一列的值,schema_name列:存放着所有数据库的的名字。只有数据库的名字,也就是读取所有数据库的名称,这schema_name这一列的值,这一列的值有很多,但浏览器只显示第一行,所以用group_concat()将相同的行组合起来,组合成一行,显示在浏览器。如下:

注意:报错会告诉你,语法哪里错误,回显是能告诉你查询的结果
知道了数据库的名称,下面就该查询数据库的表

输入:?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+

where子句是用来设置查询条件的
这句意思就是从数据库information_schema的tables表中查询security的表名,tables表中table_name列存放着所有数据库的表名。
查询出四个表,users表一般都存放着用户和密码,查看一下

查到了数据库的表,接着查询数据库的列

输入:?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where  table_schema='security' and table_name='users'--+

从数据库information_schema的columns表中查询security的列名,columns中存放着数据库所有的列名,表名。column_name是存放着数据库中所有的列名。
前面查询数据库的表也可以用columns表来查询,不过显示结果会显示重复表名
现在已经查询到列名,可以看到username和password用户名和密码,到这一步基本上就可以获取用户信息了

查询用户信息,俗称爆表

输入:?id=-1' union select 1,2,group_concat(username),group_concat(password) from security.users --+

报错

提示我们使用的select查询有不同的列数

修改一下,输入:?id=-1' union select 1,group_concat(username),group_concat(password) from security.users --+

从数据库security的users表中查询username和password列的值

更多推荐

SQL注入基本教程