SSRF To RCE in MySQL

01

背景介绍

SSRF(Server-Side Request Forgery)服务端请求伪造,是一种由攻击者构造形成由服务器端发起请求的一个漏洞,一般情况下,SSRF 攻击的目标是从外网无法访问的内部系统。

在互联网上已经很多介绍SSRF漏洞的原理,漏洞场景,漏洞利用方法的文章,但是大多数的SSRF漏洞利用都是内网扫描,内网服务识别,内网漏洞盲打,写计划任务获取shell,写私钥获取shell,利用SSRF漏洞结合Gohper或者Dict协议攻击Redis、MongoDB、Memcache等NoSQL,但是很少见有利用SSRF漏洞攻击内网MySQL、PostgreSQL、MSSQL等关系型数据库,所以本文我们将介绍如何利用SSRF漏洞结合Gopher系统攻击内网未授权MySQL,并且获取系统shell的方法。

02

MySQL通信协议

MySQL连接方式:

在进行利用SSRF攻击MySQL之前,先了解一下MySQL的通信协议。MySQL分为服务端和客户端,客户端连接服务器使存在三种方法:

  1. Unix套接字;
  2. 内存共享/命名管道;
  3. TCP/IP套接字;

在Linux或者Unix环境下,当我们输入mysql–uroot –proot登录MySQL服务器时就是用的Unix套接字连接;Unix套接字其实不是一个网络协议,只能在客户端和Mysql服务器在同一台电脑上才可以使用。

在window系统中客户端和Mysql服务器在同一台电脑上,可以使用命名管道和共享内存的方式。

TCP/IP套接字是在任何系统下都可以使用的方式,也是使用最多的连接方式,当我们输入mysql–h127.0.0.1 –uroot –proot时就是要TCP/IP套接字。

所以当我们需要抓取mysql通信数据包时必须使用TCP/IP套接字连接。

MySQL认证过程:

      MySQL客户端连接并登录服务器时存在两种情况:需要密码认证以及无需密码认证。当需要密码认证时使用挑战应答模式,服务器先发送salt然后客户端使用salt加密密码然后验证;当无需密码认证时直接发送TCP/IP数据包即可。所以在非交互模式下登录并操作MySQL只能在无需密码认证,未授权情况下进行,本文利用SSRF漏洞攻击MySQL也是在其未授权情况下进行的。

MySQL客户端与服务器的交互主要分为两个阶段:Connection Phase(连接阶段或者叫认证阶段)和Command Phase(命令阶段)。在连接阶段包括握手包和认证包,这里我们不详细说明握手包,主要关注认证数据包。

认证数据包格式如下:

这里以无需密码认证情况登录,看看认证数据包内容:

这里Packet Length为整个数据包的长度,Packet Number为sequence_id随每个数据包递增,从0开始,命令执行阶段遇到命令重新重置为0。这两个Packet为真个MySQL通协议的基础数据包。

客户端请求命令数据包格式如下:

比如这里select* from flag;命令的数据包如下:

03

构造攻击数据包

通过上面MySQL通信协议的分析,现在需要构造一个基于TCP/IP的数据包,包括连接,认证,执行命令,退出等MySQL通信数据。

环境:

ubuntu174.4.0-62-generic #x86_64

mysql  Ver 14.14 Distrib 5.7.20, for Linux (x86_64)

首先我们需要新建一个MySQL用户,并且密码为空,使用root用户登录mysql后执行如下命令即可:

CREATEUSER ‘ usernopass’@’localhost’;

GRANTUSAGE ON *.* TO ‘ usernopass’@’localhost’;

GRANTALL ON *.* TO ‘ usernopass’@’localhost’;

上面我们新建了一个用户usernopass,只允许本地登录,接下来开始抓包分析。

第一步开一个窗口抓包:

root@ubuntu17:/#tcpdump–i lo port 3306 –w mysql.pcay

第二步开一个窗口使用TCP/IP模式连接MySQL服务器:

root@ubuntu17:/#mysql–h 127.0.0.1 –r usernopass

为了抓到更多数据,然后随便select一个内容,在exit退出。

第三步使用Wireshark打开上面抓到的mysql.pcap包:

打开数据包后过滤mysql数据包,然后随便选一个mysql数据包邮件追踪流,TCP流,然后过滤出客户端发送到MySQL服务器的数据包,将显示格式调整为原始数据即可,此时获取的就是整个MySQL客户端连接服务器并且执行命令到退出发送的数据包内容,如上图所示。

然后将原始数据整理为一行,并将其url编码,最后的内容如下图所示:

将MySQL原始数据进行编码的脚本如下:

04

利用SSRF获取Shell

上面我们构造好了一堆TCP数据包,如果需要使用SSRF漏洞来攻击MySQL的话,那么我们可以使用gopher协议来发送上面的一堆TCP数据包,最后使用curl发送请求即可。

这里我们select了flag表中的数据,最后构造的请求如下:

但是很多情况下,SSRF是没有回显的,及时发送了数据而且MySQL也执行了,但是我们看不到执行后的返回数据,最后我们要的是系统的一个shell。

正常情况下,通过MySQL获取系统shell一般通过selectinto outfile系统文件,或者使用udf来搞,那么这里同样我们将获取shell的数据包提取出来,通过gopher协议发送这些数据包同样可以达到getshell的目的。

通过select xxx into outfile yyy写shell的数据包获取方法同上面构造攻击数据包的过程,将执行完写文件sql语句的抓包内容提取出来构造好即可,如下图成功写shell文件到系统目录:

通过udf直接执行系统命令过程同样,执行完一系列导出udf到plugin的命令后,即可直接执行系统命令执行,如下图所示反弹shell:

(注意:在导出文件时,当前mysql用户必须存在file权限;部分MySQL服务器运行时启用了–secure-file-priv选项,导出文件时只能导出到规定的目录下,一般为/var/mysql/data命令,要自定义目录时必须修改配置文件设置secure-file-priv = “”;并且导入目录需要有写权限。)

05

实战演练

例如下面这段常见的php代码,经常在审计代码时,遇到这类问题导致的SSRF漏洞,通过这里的SSRF,如果存在未授权的MySQL即可利用上面的攻击方法获取数据库敏感信息,甚至获取系统shell。

将我们构造好的获取信息的请求发送到url参数,结果如下:

可以看到成功获取到了表中的信息,利用导出文件或者udf获取系统shell的方法一样,只要构造好数据包直接发送即可。

此方法再前不久的一个CTF中就有一个SSRF题目,就是利用未授权的MySQL获取数据库中的信息。

06

其他

这里我们只是介绍了如何构造MySQL数据库的数据包,并通过SSRF漏洞进行利益,其实他的关系数据库只要满足类似的场景都是可以利用的,比如PostgreSQL同样可以通过此过程进行攻击,PostgreSQL数据库的具体利用过程这里不再讲解,请期待后续相关内容介绍。

07

参考链接

http://codingo.xyz/index.php/2017/12/27/mysql_protocol/

http://vinc.top/2017/04/19/mysql-udf%E6%8F%90%E6%9D%83linux%E5%B9%B3%E5%8F%B0/

 

作者:逢魔安全实验室