前言:一、搭建测试环境二、编写测试代码-动态创建容器
1、编写配置文件 pom.xml 与 application.yaml2、编写 indexController3、编写 DockerClientUtils4、编写前端界面 三、编写测试代码-模拟题目环境四、打包、部署、测试
1、服务器 docker 配置2、腾讯云防火墙端口3、dockerfile 编写 4、镜像生成
5、运行测试
前言:
前面的几天时间里,学习了 docker 的安装与使用,学会使用命令行控制 docker 容器的创建、删除等。然后学习了 springboot 框架的基本使用、了解其框架基本原理与运行机制。完成了这些准备后,接下来我主要面临的一个比较关键的技术难点是如何使用 springboot 连接远程服务器上 docker 服务,实现容器的动态创建与删除。如果实现了这个技术点,那么我们的靶场题目环境便可以打包成镜像,然后放到服务器中,通过动态的创建、删除容器,来实现题目环境的部署。
一、搭建测试环境
后端动态创建容器使用 springboot 框架搭建
模拟靶场环境使用 springboot 框架。
前端就简单使用 HTML 写一个测试页面即可。
二、编写测试代码-动态创建容器 1、编写配置文件 pom.xml 与 application.yaml
pom.xml 导入项目需要用到的相关依赖
4.0.0 org.springframework.boot spring-boot-starter-parent 2.6.4 com.example SDU_SpringBoot_font 0.0.1-SNAPSHOT SDU_SpringBoot_font SDU_SpringBoot_font 1.8 com.github.docker-java docker-java 3.1.5 com.alibaba fastjson 1.2.28 org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-web org.slf4j slf4j-log4j12 org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engina javax.servlet javax.servlet-api provided javax.servlet jstl org.apache.tomcat.embed tomcat-embed-jasper provided org.springframework.boot spring-boot-maven-plugin
application.yaml 对项目进行配置,配置一下 html 文件的匹配路径
spring:
thymeleaf:
prefix:
classpath: /templates/
2、编写 indexController
用于 index 页面的匹配
实现浏览器请求 “/” 或 “/index.html” 时,匹配到 index.html 页面。
package com.example.sdu_springboot_font.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Controller
public class indexController {
@RequestMapping(value={"/","/index.html"})
public String index(){
return "index";
}
}
接下来是比较重要的部分,即 java 远程操控服务器上的 docker 服务,实现容器的创建、删除等基本操作。在思考如何实现这个功能的时候,查看了大量的文章,在网上搜索了很多的相关博客,也简单看了一下几篇关于 docker 在 CTF 比赛中容器创建的相关应用的论文。经过尝试,最后使用 docker-java 成功实现该功能。
docker-java 简介:
docker-java 是一个开源的项目,发布在 GitHub 上,此项目提供了很多接口,可以用于连接远程服务器上的 docker 服务,并进行基本的操控。使用时导入 jar 包即可。相关文档及使用博客并不是很多,需要自己进行学习探索。
使用前需导入 jar 包,因为是 springboot 框架,集成了 maven ,所以直接在 pom.xml 导入依赖
com.github.docker-java docker-java 3.1.5
导入相关依赖后,编写 newContainer 类,利用 docker-java 的相关接口,实现远程服务器的 docker 服务的连接,并进行动态的创建容器、删除容器等基本操作。
package com.example.sdu_springboot_font.controller;
import com.alibaba.fastjson.JSONObject;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.model.Info;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.example.sdu_springboot_font.service.*;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/yaoyao/")//接口注解
//接收index.HTML的请求,创建一个容器,然后把跳转到容器界面
public class newContainer {
@Autowired //与service层进行交互
//private LoginClservice loginClService;
//private DockerClientUtils dockerClientUtils;
public static int port=8080;
public static int containerName = 0;
@RequestMapping("user")
public ModelAndView getLoginCl() throws InterruptedException {
port+=1;
containerName+=1;
//boolean b;
//b=loginClService.Find(name, password);//调用service层的方法
DockerClientUtils dockerClientUtils = new DockerClientUtils();
//连接Docker服务器
DockerClient client = dockerClientUtils.connectDocker("tcp://82.157.124.157:2275");
//创建容器
CreateContainerResponse container = dockerClientUtils.createContainer(client, "ctf-test-"+containerName, "ctf-test",8080,port);
//启动容器
dockerClientUtils.startContainer(client, container.getId());
//Info info = client.infoCmd().exec();
//String infoStr = JSONObject.toJSonString(info);
//System.out.println(infoStr);
//return "success";
//Thread.sleep(1000);
return new ModelAndView("redirect:http://82.157.124.157:"+port);
}
}
上面代码实现的测试功能为:浏览器请求 “/yaoyao/user”,服务端接收到请求后,会连接到远程服务器(82.157.124.157)的 docker 服务(2275 端口,需要在服务器端提前配置好,否则会出现拒绝连接现象)
创建容器,镜像名为 “ctf-test”,容器名为:ctf-test-编号,映射端口为服务器IP:8080
CreateContainerResponse container = dockerClientUtils.createContainer(client, "ctf-test-"+containerName, "ctf-test",8080,port);
启动容器
dockerClientUtils.startContainer(client, container.getId());
然后重定向到新创建的容器界面
return new ModelAndView("redirect:http://82.157.124.157:"+port);
3、编写 DockerClientUtils
DockerClientUtils 为 service 层文件,主要实现 docker-java 接口调用,进一步实现容器的创建删除。
package com.example.sdu_springboot_font.service;
import java.util.List;
import com.github.dockerjava.api.model.ExposedPort;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.Ports;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONObject;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.model.Info;
import com.github.dockerjava.core.DockerClientBuilder;
//import com.example.smalldemo.dao.*;
//import com.example.smalldemo.model.*;
@Service
public class DockerClientUtils {
public DockerClient connectDocker(String dockerInstance){
DockerClient dockerClient = DockerClientBuilder.getInstance(dockerInstance).build();
dockerClient.infoCmd().exec();
return dockerClient;
}
public CreateContainerResponse createContainer(DockerClient client, String containerName, String imageName,
int exposedTcpPort, int bindTcpPort) {
ExposedPort exposedPort = ExposedPort.tcp(exposedTcpPort);
Ports portBindings = new Ports();
portBindings.bind(exposedPort, Ports.Binding.bindPort(bindTcpPort));
CreateContainerResponse container = client.createContainerCmd(imageName)
.withName(containerName)
.withHostConfig(HostConfig.newHostConfig().withPortBindings(portBindings))
.withExposedPorts(exposedPort).exec();
return container;
}
public void startContainer(DockerClient client,String containerId){
client.startContainerCmd(containerId).exec();
}
public void stopContainer(DockerClient client,String containerId){
client.stopContainerCmd(containerId).exec();
}
public void removeContainer(DockerClient client,String containerId){
client.removeContainerCmd(containerId).exec();
}
}
4、编写前端界面
前端界面仅仅作为测试使用,真正项目的前端界面由组内其他成员完成,所以这里简单的使用 HTML 编写测试界面。
- index.html
Insert title here
- success.html
创建容器成功
已成功创建靶场容器,即将自动跳转到靶场
三、编写测试代码-模拟题目环境
这各部分主要是编写一个模拟的靶场环境,用于测试是否可以远程操控。
代码也很简单,相关的其他配置与上面一部分类似,这里便不再赘述。
package com.example.ctfzone.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class index {
@RequestMapping("/")
public String indexpage(){
return "靶场环境-处于新建容器中";
}
}
四、打包、部署、测试 1、服务器 docker 配置
环境:
centos7
开始
想要在java中还是在其他方式访问 dockerAPI 都需要设置一个端口
运行以下命令:进入docker.service
vi /lib/systemd/system/docker.service
找到Execstart=/usr/bin/dockerd 后加上 -H tcp://0.0.0.0:2275 -H unix://var/run/docker.sock
退出并且保存
运行以下命令:
systemctl daemon-reload service docker restart //重启启动docker systemctl stats docker //可以查看相关内容,看看2275是否已经设置好
运行:netstat -nlp |grep 2275 可以查看2275是否已经被监听
如果你是阿里的云服务器这种,应该需要在安全组中加入2275或者其他的操作。
如果是在本地搭建的虚拟机,则需要把防火墙关闭或者在防火墙中开启相应端口以供外部使用
2、腾讯云防火墙端口
开启 2275 端口
FROM java:8 COPY *.jar /app.jar CMD ["--server.port=8080"] EXPOSE 8080 ENTRYPOINT ["java","-jar","/app.jar" ]
4、镜像生成
- 生成 jar 包
把 jar 包和 dockerfile 文件均上传到服务器
生成镜像
sudo docker build -t="ctf-front-test" .
5、运行测试
参考文章:
https://www.cnblogs.com/lsgxeva/p/8746644.html
https://blog.csdn.net/qq_36956154/article/details/81335886
参考论文:
https://www.fx361.com/page/2021/0728/8631053.shtml
https://xueshu.baidu.com/usercenter/paper/show?paperid=1x280t10ut280mx06m080p10qj548641&site=xueshu_se
https://xueshu.baidu.com/usercenter/paper/show?paperid=1u7u0v70e02c0200j85w08h0m0022660&site=xueshu_se
https://cdmd.cnki.com.cn/article/cdmd-10013-1018097424.htm



