SSRF To RCE in MySQL

xfkxfk發表於2018-04-11

背景介紹

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/