昨夜西风凋碧树。独上高楼,望尽天涯路。
SQL注入基础
1. SQL注入原理
什么是sql
SQL是一门ANSI的标准计算机语言,用来访问和操作数据库系统。用于增删改查数据库中的数据。
sql可以与数据库程序协同工作,常见的数据库如:
- MS Access
- DB2
- infomix
- MS SQL Server
- Mysql
- Oracle
- postgresql
- …
虽然存在很多不同版本的SQL语言,但为了与ANSI标准相兼容,必须以相似的方式共同支持一些主要关键词(如select、update、delete、insert、where等)。
SQL语句常见操作方式
select 查询数据
在网站应用中进行数据显示查询操作
例:
1 | select * from news where id=$id |
insert 插入数据
在网站应用中进行用户注册添加等操作
例:
1 | insert into news(id,url,text) values(2,'x','$t') |
delete 删除数据
后台管理里面删除文章删除用户等操作
例:
1 | delete from news where id=$id |
update 更新数据
会员或后台中心数据同步或缓存等操作
例:
1 | update user set pwd='$p' where id=2 and username='admin' |
order by 排序数据
一般结合表名或列名进行数据排序操作
例:
1 | select * from news order by $id |
例:
1 | select id,name,price from news order by $order |
注:
- 可通过以上查询方式与网站应用的关系
- 注入点产生地方或应用猜测到对方的SQL查询方式
- 只要存在前后台交互的地方都可能存在注入漏洞
什么是sql注入
SQL注入攻击,是由于程序对用户的操作输入未进行正确或不严格的检查过滤,用户通过操作输入修改SQL语句,将用户的输入/payload以拼接的方式带入SQL语句中,并被SQL引擎解析成SQL代码,再将这些语句传递给后端的数据库执行,从而引发实际执行的语句与预期执行的语句不一样,达到攻击目的的技术。
注入条件
- 参数用户可控:用户可控的前后端参数传递
如: input标签传递到后端java MyBatis处理参数可控。
- 参数带入数据库操作:参数未限制输入,直接拼接入数据库操作
1 | $id = $_REQUEST[ 'id' ]; |
这里$id可控,可通过用户输入修改sql语句逻辑,即可达到攻击母的。
ps: 这里造成SQL注入漏洞原因有两个:一个是没有对输入的数据进行过滤(过滤输入),还有一个是没有对发送到数据库的数据进行转义(转义输出)
注入点
- 认证页面
- 搜索页面
- Post请求
- Get请求
- HTTP头部
- Cookie
- 边缘输入点
- 等
危害:
- 泄露系统中的敏感信息。
- 数据库信息泄漏:数据库中存放的用户的隐私信息的泄露。作为数据的存储中心,数据库里往往保存着各类的隐私信息,SQL注入攻击能导致这些隐私信息透明于攻击者。
- 网页篡改:通过操作数据库对数据内容被篡改、特定网页进行篡改。
- 登录认证被绕过
- 其他,例如服务器上的文件被读取或修改/服务器上的程序被执行、数据破坏、挂马攻击、服务器被控制等。
常见的修复方案
- 黑/白名单过滤、关键字替换、过滤
- 预编译、绑定变量
- 输入输出转义
- 参数化查询
- 安全机制防御
- RASP
- WAF
- 安全函数
注入流程
注入点检测–>>DBMS标识–>>构造相应payload–>>信息利用/提权/执行命令/横向移动/数据泄露/持久等
2. SQL注入的基本分类
参数类型分类
数字型注入:输入参数为整型时,如Id、年龄和手机号等;
字符型注入:输入参数为字符串型时,如姓名、公司、住址等;
最大的区别: 字符型注入一般要使用单引号进行闭合,而数字型注入则不需要。
注入点分类
GET注入:注入字符在URL参数中;
POST注入:注入字段在POST提交的数据中;
Cookie注入:注入字段在Cookie数据中,网站使用通用的防注入程序,会对GET、POST提交的数据进行过滤,却往往遗漏Cookie中的数据进行过滤。
HTTP头部注入:HTTP请求的其他内容触发的SQL注入漏洞。
搜索注入: 指在进行数据搜索时没过滤搜索参数,一般在链接地址、搜索框中。
其他:认证页面、万能密码等。
结果反馈分类
非盲注
非盲注入(正常SQL注入):执行注入SQL语句将敏感信息展示出来,并进行进一步的操作。
盲注
盲注是指获取的数据不能回显至前端页面,不会存在任何数据库报错内容,此时就需要利用一些方法进行判断或尝试,这个过程称之为盲注
它是依据构造真或假的问题对数据库进行“提问”,注入方式主要有两种:基于布尔值与基于时间。
盲注一般结合工具进行,纯手工难度大。
基于布尔值
简而言之,就是根据页面回显的不同来判断。
如:
MySQL中判断数据名长度的输入payload
1 | 1' and length(database()) = 10 # |
此时,可通过相应页面返回的正确与否来判断and后面的值是否为真,数据库名的长度是否为10。
如何获取每一个数据?
利用MySQL自带函数进行提取,如substring()、mid()、subst()、left(),、right()、substring_index()等。
1 | # --------------------利用ASCII码猜解当前数据库名称 |
字符串截取:substring_index(str,delim,count)
- 截取第二个 ‘.’ 之前的所有字符。
1
2
3
4
5
6 mysql> select substring_index('www.example.com', '.', 2);
+------------------------------------------------+
| substring_index('www.example.com', '.', 2) |
+------------------------------------------------+
| www.example |
+------------------------------------------------+
- 截取第二个 ‘.’ (倒数)之后的所有字符。
1
2
3
4
5
6 mysql> select substring_index('www.example.com', '.', -2);
+-------------------------------------------------+
| substring_index('www.example.com', '.', -2) |
+-------------------------------------------------+
| example.com |
+-------------------------------------------------+
- 如果在字符串中找不到 delim 参数指定的值,就返回整个字符串
1
2
3
4
5
6 mysql> select substring_index('www.example.com', '.coc', 1);
+---------------------------------------------------+
| substring_index('www.example.com', '.coc', 1) |
+---------------------------------------------------+
| www.example.com |
+---------------------------------------------------+
基于时间
在某些情况下,页面回显的内容一致,需借助其他手段来SQL注入判断,如服务器执行SQL语句所需要的时间。
基于时间的SQL盲注方式,通常是在SQL语句中添加延时函数,如通过sleep()函数,利用IF条件或ADN、OR函数的短路特性和SQL执行的时间来判断是否存在SQL注入。(实战于4.2介绍)
常用的延时函数或指令有sleep、repeat等。
其他类型
延时注入: 使用延时函数方式。
宽字节注入: 设置MySQL连接时错误配置为:set character_set_client=gbk,这样配置会引发编码转换从而导致的注入漏洞。
编码注入: 将输入的字符串进行编码,如base64、urldecode、base64_decode等。
报错注入: 由于开启错误调试信息,导致可看到语句执行后的报错信息输出,从而引发sql注入。
DNSLOG注入: 在注入无回显时,利用MySQL数据库的 LOAD_FILE() 读取文件的函数去拼接查询结果并访问用于拼接的dns平台,然后通过平台去进行查看接收到的数据。
堆查询注入: 同时执行多条语句。
联合查询注入: 使用union语句合并两条或多条SQL语句。
多阶注入: 由多个HTTP请求响应共同完成的注入。
二次注入: 根本问题是,开发者信任数据库中取出的数据是无害的。payload拼接进行SQL注入,在全局过滤后入库时,进行了转义,入库后,转义符会消失,这个时候出库被带入到其他SQL语句就会引入payload导致注入。
XFF注入: X- Forwarded-For头带入数据操作时,参数由用户可控,传递中存在SQL注入。
存储过程: 存储过程包含参数,在参数传递中存在SQL注入。
注入技巧使用优先级:
UNION注入>报错注入>布尔盲注>时间盲注
其他注入通常需要结合其他技巧使用才能获取数据
3. 常用函数及变量
常用的字符串/系统函数
1 | @@datadir #数据库路径 |
字符串连接函数
1 | GROUP_CONCAT(str1,str2,...)) # 返回由属于一组的列值连接组合而成的结果 |
SQL判断语句:
1 | or 1=1--+ |
PHP
PHP 中的许多预定义变量都是“超全局的”,这意味着它们在一个脚本的全部作用域中都可用。这些超全局变量是:
1 |
|
Bypass常用简记:
详细另开一篇来说
1 | -- and /or过滤 |
4. SQL注入点判断
常规手法
注入存在多种检测方式,最简单无外乎在各种参数后添加“或’,从而来通过服务器返回的数据响应报错信息来分析。
通过应用程序的报错触发及布尔逻辑,可以轻松判断易受攻击的参数。
注入简记
| 描述 | 语句 |
|---|---|
| 逻辑测试 | page.asp?id=1 or 1=1 – true page.asp?id=1’ or 1=1 – true page.asp?id=1" or 1=1 – true page.asp?id=1 and 1=2 – false |
| 算术 | product.asp?id=1/1 – true product.asp?id=1/0 – false |
| 基于盲注: 检测盲注可能需要识别或猜测DBMS, 并检查以找到适当的时间函数。 | Mysql: * SELECT IF(user() LIKE 'root@%', SLEEP(5), null) *Oracle: SELECT CASE WHEN (SELECT COUNT(*) FROM v$version WHERE banner LIKE 'Oracle%11.2%')=1 THEN (SELECT count(*) FROM all_users a, all_users b, all_users c, all_users d) ELSE 0 END FROM dualSQL Server *IF exists(SELECT @@version where @@version like '%12.0.2000.8%') WAITFOR DELAY '00:00:02'* |
| 基于错误: 注意:使用无效语法的逻辑测试和算术 也可能会导致错误。 | Mysql: * SELECT extractvalue(rand(),concat(0x3a,(select version()))) *Oracle: SELECT utl_inaddr.get_host_name((select banner from v$version where rownum=1)) FROM dualSQL Server *SELECT convert(int,(SELECT @@version)) '* |
时间注入判断法
<待补充实战>
批量判断法
- SQLMAP
- sqliv
- sqlmapapi.
- URL参数批量提取去重后再结合漏洞扫描工具
5. SQL注入常见注释符
常规注释:
SQL 语句注释方法有/* */ 和-- (空格)和# 三种
php中的注释符:
///*...*/#
JavaScript中的注释符:
///*...*/
html中的注释符:
<!--内容-->
MySQL中的注释符:
-
# -
内联注释
/*...*/
在mysql中是多行注释 但是如果里面加了! 那么后面的内容会被执行 -
--空格 -
--+--(空格)一般不能直接使用,因为只使用--(空格)的时候无法对sql语句进行闭合,在传输过程中空格会被忽略,导致无法注释,所以需要需要+或是’、%20*(把空格转换未urlencode编码格式)*来对其进行闭合完成注入语句。+会被解析成空格;--是SQL的注释标记,使用时后面的一切字符串都会比当做注释忽略掉
postgersql注释符号也是–+
Mssql 注释
| 操作 | 备注 |
|---|---|
-- |
SQL注释 |
; 00% |
空字节 |
/ * |
C语言风格注释 |
Oracle注释
-
单行注释符号是
-- -
多行注释符号
/**/
URL中#、?、&、+解释:
#说明
#的涵义
#在URL 中会被认为是锚点, sql注入中想要使用需要进行编码。 url 编码为%23。#代表网页中的一个位置。其右面的字符,就是该位置的标识符。比如,http://www.example.com/index.html#print就代表网页index.html的print位置。浏览器读取这个URL后,会自动将print位置滚动至可视区域
HTTP请求不包括 #
#是用来指导浏览器动作的,对服务器端完全无用。所以,HTTP请求中不包括#
#后的字符
- 在第一个#后面出现的任何字符,都会被浏览器解读为位置标识符。这意味着,这些字符都不会被发送到服务器端
?说明
连接作用
- 通过
?来带参数,连接域名和参数,经常会用到。
清除缓存
1 | http://www.xxxxx.com/index.html |
- 两个url打开的页面一样,但是后面这个有问号,说明不调用缓存的内容,而认为是一个新地址,重新读取。因为在做http请求的时候,如果浏览器检测到你的地址完全没变,会从缓存里读取先前请求过的数据,不再发送请求。有些时候是页面资源的加载,有些时候是API的get请求,都有可能。加上这个,会让浏览器认为这是一个新的地址,从而保证重新获取资源。
&说明
不同参数的间隔符
http://www.xxx.com/Show.asp?id=77&nameid=2905210001&page=1
+说明
+在URL 中会被认为是空格,所以--+和--空格在sql中都有注释的意思
参考链接:
- https://mp.weixin.qq.com/s/p_NHl975fhjUMlx5LKxRHw
- https://mp.weixin.qq.com/s/L5RuWT7V9q4b6OZwfdscjg
- https://www.cnblogs.com/xiaozi/p/5538380.html
-------------------------------------------------------------------------------- If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !