1. 概述

在本教程中,我们将探讨攻击者如何在 Java 代码中使用反序列化来利用系统。

我们将首先研究攻击者可能用来利用系统的一些不同方法。然后,我们将看看成功攻击的影响。最后,我们将研究一些有助于避免此类攻击的最佳实践。

2. 反序列化漏洞

Java 广泛使用反序列化从输入源创建对象。

这些输入源是字节流,有多种格式(一些标准形式包括 JSON 和 XML)。 L**** 合法的系统功能或跨网络与可信源的通信使用反序列化。 然而,不受信任或恶意的字节流可以利用易受攻击的反序列化代码。

我们之前关于Java 序列化的文章介绍了序列化和反序列化如何更深入地工作。

2.1.攻击向量

让我们讨论攻击者如何使用反序列化来利用系统。

对于可序列化的类,它必须符合 Serialized 接口。实现 Serialized 的 类使用 readObjectwriteObject 方法。 这些方法分别反序列化和序列化类的对象实例。

一个典型的实现可能如下所示:

public class Thing implements Serializable {
    private static final long serialVersionUID = 0L;

    // Class fields

    private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
        ois.defaultReadObject();
        // Custom attribute setting
    }

    private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.defaultWriteObject(); 
        // Custom attribute getting
    }
}

当类具有通用或松散定义的字段并使用反射来设置这些字段的属性时,类就会变得容易受到攻击

public class BadThing implements Serializable {
    private static final long serialVersionUID = 0L;

    Object looselyDefinedThing;
    String methodName;

    private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
        ois.defaultReadObject();
        try {
            Method method = looselyDefinedThing.getClass().getMethod(methodName);
            method.invoke(looselyDefinedThing);
        } catch (Exception e) {
            // handle error...
        }
    }

    // ...
}

让我们分解上面的内容,看看发生了什么。

首先,我们的 BadThing 类有一个 looselyDefinedThing 字段,其类型为 Object。 这是模糊的,允许攻击者将此字段设置为类路径上可用的任何类型。

接下来,该类容易受到攻击的原因是 readObject 方法包含调用 looselyDefinedThing 上的方法的自定义代码。 我们想要调用的方法通过反射使用字段 methodName (也可以由攻击者控制)。

如果类 MyCustomAttackObject 位于系统的类路径上,则上面的代码在执行时等效于以下代码:

BadThing badThing = new BadThing();
badThing.looselyDefinedThing = new MyCustomAttackObject();
badThing.methodName = "methodThatTriggersAttack";

Method method = looselyDefinedThing.getClass().getMethod(methodName);
method.invoke(methodName);
public class MyCustomAttackObject implements Serializable {
    public static void methodThatTriggersAttack() {
        try {
            Runtime.getRuntime().exec("echo \"Oh, no! I've been hacked\"");
        } catch (IOException e) {
            // handle error...
        }
    }
}

通过使用 MyCustomAttackObject 类,攻击者能够在主机上执行命令。

这个特定的命令是无害的。然而,如果这种方法能够接受自定义命令,那么攻击者可以实现的可能性是无限的。

仍然存在的问题是,“为什么有人会在他们的类路径上有这样一个类?”。

允许攻击者执行恶意代码的类广泛存在于许多框架和软件使用的开源和第三方库中。 它们通常不像上面的示例那么简单,而是涉及使用多个类和反射来执行类似的命令。

以这种方式使用多个类通常称为小工具链。开源工具ysoserial维护着可用于攻击的小工具链的活动列表。

2.2.影响

现在我们知道攻击者如何获得远程命令执行的访问权限,让我们讨论一下攻击者可能在我们的系统上实现的一些影响。

根据运行 JVM 的用户拥有的访问级别,攻击者可能已经在计算机上拥有更高的权限,这将允许他们访问系统中的大多数文件并窃取信息。

某些反序列化漏洞允许攻击者执行自定义 Java 代码,这可能导致拒绝服务攻击、窃取用户会话或未经授权的资源访问。

由于每个反序列化漏洞都不同,每个系统设置也不同,攻击者能够实现的目标差异很大。因此, 漏洞数据库认为反序列化漏洞具有高风险。

3. 预防的最佳实践

现在我们已经介绍了我们的系统可能如何被利用,接下来我们将介绍一些可以遵循的最佳实践,以帮助防止此类攻击并限制潜在利用的范围。

请注意,漏洞预防没有灵丹妙药,本节并不是所有预防措施的详尽列表:

  • 我们应该使开源库保持最新状态。优先更新到可用的最新版本的库。
  • 主动检查漏洞数据库,例如国家漏洞数据库CVE Mitre (仅举几例)是否有新声明的漏洞,并确保我们不会暴露
  • 验证反序列化输入字节流的来源(使用安全连接并验证用户等)
  • 如果输入来自用户输入字段,请确保在反序列化之前验证这些字段并授权用户
  • 创建自定义反序列化代码时,请遵循owasp 反序列化备忘单
  • 限制 JVM 在主机上可以访问的内容,以减少攻击者能够利用我们的系统进行的操作范围

4。结论

在本文中,我们介绍了攻击者如何使用反序列化来利用易受攻击的系统。此外,我们还介绍了一些在 Java 系统中保持良好安全卫生的实践。

与往常一样,源代码可以在 GitHub 上获取。