使用Docker快速搭建漏洞分析环境

起因

需求源于痛苦。很多人可能已经深有体会,搭建环境的时间可能会远大于真正做事时间。我最近在看一些Java的漏洞,但我不是Java开发者,并没有现成的Java环境。而且最近我没有自己的电脑用,需要管理员权限的操作我都不能执行。用着并不熟悉的IDEA,拉下来的代码编译无数遍都没有通过。检查了各种配置无果后,萌生了一个想法:为什么不能把我在开发中经常用到的Docker拿过来用做Java代码编译和部署,并且可以进行远程断点调试?而且我们可以通过不同的镜像去切换不同的JDK和Maven版本,岂不爽哉?闲话少说,行不行跟我一起试试看就知道了。

准备

  • Docker

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口...官方的话就不继续说了,有关Docker的具体用法请看官方文档

  • IDEA

这是一个我也不咋熟悉的IDE,在本文中只用来做远程调试。

  • 含有漏洞的showcase

本文以 S2-045 为例,需要下载struts-2.5.10的showcase,下载地址:https://archive.apache.org/dist/struts/

文件结构

+- debug_in_docker/
    +- src/
    |  +- [showcase files]
    !
    +- tomcat/
    |  +- context.xml
    |  +- tomcat-users.xml
    |  +- run.sh
    |
    +- docker-compose.yml
    |
    +- Dockerfile
    |
    +- run.sh

从文件结构中可以看出,我将含有漏洞的showcase代码拿出来放在一个新文件夹,tomcat文件夹主要是Tomcat的一些配置和运行脚本。Dockerfile用于构建部署环境需要的镜像,docker-compose.yml用于运行镜像,run.sh为整个系统的运行脚本。我会在搭建思路中一一讲解它们。

搭建思路

Maven Build

Struts2的showcase是一个可以用Maven编译和运行的项目。我在使用IDEA编译的时候使用了Maven生命周期的两个命令:cleaninstall

maven lifecycle

那么,移步Docker Hub,找一下Maven相关的镜像

maven in docker hub

恰好,Docker Hub中的运行示例使用的正是 cleaninstall 这两个命令。直接拿过来跑一下试试。

cd debug_in_docker/src
docker run -it --rm --name my-maven-project -v "$(pwd)":/usr/src/mymaven -w /usr/src/mymaven maven:3.3-jdk-8 mvn clean install

docker_run_maven

看起来不错,已经开始跑了。让它先跑着,我们研究下其他的。

Tomcat Server

我们需要构建一个Tomcat服务器镜像并且把我们Bulid好的程序部署上去然后开启远程调试,那我们来写一个Dockerfile吧。这里我借鉴docker/labs 这个项目。我跟着它的步骤走了一遍整个流程,然后进行了一些优化。

首先是Tomcat的配置。我希望能在Tomcat的主页通过 Manager App看到我所有部署好的项目,需要更改两个Tomcat配置。

  • tomcat/context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context antiResourceLocking="false" privileged="true" >
  <!-- <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" /> -->
  <Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap"/>
</Context>

这个配置文件主要把 ...RemoteAddrValve... 注释掉用于允许远程访问管理页面。

  • tomcat/tomcat-users.xml
<?xml version='1.0' encoding='cp1252'?>
<tomcat-users>
    <user username="system" password="manager" roles="admin-gui,manager-gui" />
    <role rolename="manager-script"/>
    <user username="admin" password="admin" roles="manager-script"/>
</tomcat-users>

这个配置文件用来设置管理页面的账号和密码。

  • tomcat/run.sh
#!/bin/sh

exec ${CATALINA_HOME}/bin/catalina.sh jpda run

这个shell文件用来启动Tomcat并启动远程调试。

现在回到Dockerfile,我们使用 tomcat 作为基础镜像,然后把我们刚刚搞的Tomcat配置文件和 run.sh 放到它们应该在的位置并且给run.sh执行权限。然后在镜像内 webapps/ 中为 struts2-showcase 创建一个文件夹。设置一下远程调试的相关环境变量,引出8080端口,执行 run.sh

  • Dockerfile
FROM tomcat

# sets up user accounts and access permit for the Tomcat manager GUI
# and script access for Maven deployments
ADD tomcat/tomcat-users.xml $CATALINA_HOME/conf/
ADD tomcat/context.xml $CATALINA_HOME/webapps//manager/META-INF/

# ADD tomcat/catalina.sh $CATALINA_HOME/bin/
ADD tomcat/run.sh $CATALINA_HOME/bin/run.sh
RUN chmod +x $CATALINA_HOME/bin/run.sh

# create mount point for volume with application
RUN mkdir $CATALINA_HOME/webapps/struts2-showcase

# add tomcat jpda debugging environmental variables
#ENV JPDA_OPTS="-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n"
ENV JPDA_ADDRESS="8000"
ENV JPDA_TRANSPORT="dt_socket"

# start tomcat with remote debugging
EXPOSE 8080
CMD ["run.sh"]

写好Dockerfile后,我们写一个docker-compose来为容器运行做准备。

  • docker-compose.yml
version: "3"
services:
  webserver:
    build: .
    image: debug-webserver
    volumes:
      - ./src/target/struts2-showcase:/usr/local/tomcat/webapps/struts2-showcase
    ports:
      - "8080:8080" 
      - "8000:8000"
    restart: always

docker-compose就简单多了,主要就是引出对应的端口和把使用Maven Build好的 target 文件夹挂载到容器内新建的struts2-showcase文件夹中,完成部署的同时方便远程调试。

运行

还记得刚才我们用 docker run 跑的build吗?回头看已经成功了。

maven build success

现在我们运行 docker-compose up 让服务跑起来。

docker-compose up

可以在这里看到镜像构建过程和服务运行状态。现在在浏览器中访问http://localhost:8080 就可以看到Tomcat主页

tomcat index

点击 Manager App 可以看到刚刚部署的showcase项目,可直接点击访问。

tomcat index

connected to remote debug

远程调试

服务跑起来后,使用IDEA打开 src/ 目录,在菜单中依次点击RUN —— Edit Configurations,弹出页面点击 + 号添加一个 Remote 配置,命名为 tomcat-docker

add debug config

修改Debug端口为8000如下图设置:

debug config

保存后依次点击菜单中 RUN —— debug "tomcat-docker" ,Console中输出如下内容即连接远程调试成功。

connected to remote debug

确认没有问题了就可以打断点触发漏洞了。以 S2-045 为例,断点打在 struts2-core-2.5.10.jar!/org/apache/struts2/interceptor/FileUploadInterceptor.class

break point

断点打好后,来一段payload触发断点,因为没有管理员权限,我使用Postman代替Brupsuite。

trigger breakpoint

如上面动图所见,断点已命中。现在看来差不多了。但是有一个不大的问题,我要跑两个命令,一个是 docker run maven 用于build项目。一个是 docker-compose up 用于将build好的项目部署到服务器中并开启远程调试,那么有没有办法用一个命令呢?我试了写两个 services 的 docker-compose 即使增加 depends_on 或者 links ,docker-compose也并不知道build有没有完成。官方提供了一个解决方案是在服务A运行完成后创建一个文件,服务B一直监控是否存在这个文件,如果不存在就一直等待,存在继续跑。这个方案应该可行但是过于麻烦了,而且在这个官方方案的投票中踩远大于顶,很有意思。有兴趣的可以去看下。我没有参考官方方案,直接写个shell脚本吧。

  • run.sh
#!/bin/sh

docker run -it --rm --name build-maven-project -v "$(pwd)"/src:/usr/src/mymaven -w /usr/src/mymaven maven:3.3-jdk-8 mvn clean install
docker-compose up

至此全部搞定。不过,我只是抛个砖~

参考

Comments
Write a Comment