3、Docker入门:Docker安装、镜像与容器概念、Dockerfile基础编写

3.1 为什么漏洞复现离不开Docker?

做漏洞复现这些年,我踩过最大的坑就是环境冲突。

你想想看,一个漏洞环境需要特定版本的PHP、特定的Apache模块、甚至特定的系统内核参数。搞完一个环境,再搞下一个,系统就乱成一锅粥了。

Docker就是来解决这个问题的。它把应用和依赖打包在一起,互不干扰。说白了,就是一个轻量级的虚拟机,但比虚拟机快得多、省得多。

我个人习惯,每个漏洞环境都用一个独立的Docker容器。用完就删,干净利落。

核心概念速览:

  • 镜像(Image):一个只读的模板,包含运行环境的所有文件
  • 容器(Container):镜像的运行实例,可以读写、可以启动停止
  • Dockerfile:构建镜像的配方文件,告诉Docker怎么一步步搭建环境

3.2 Docker安装:三分钟搞定

不同系统安装方式不一样。我主要用Linux,这里以Ubuntu为例。

# 更新包索引
sudo apt update

# 安装依赖
sudo apt install apt-transport-https ca-certificates curl software-properties-common

# 添加Docker官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# 添加稳定版仓库
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

# 安装Docker
sudo apt update
sudo apt install docker-ce

# 启动并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker

# 验证安装
sudo docker --version

小技巧:安装完后,把当前用户加入docker组,就不用每次sudo了。

sudo usermod -aG docker $USER
# 然后退出重新登录

Windows用户直接下载Docker Desktop安装包就行。Mac也一样。嗯,这里要注意,Windows上Docker依赖WSL2,安装前记得开启。

3.3 镜像与容器:先搞懂这两个概念

我记得刚学Docker时,镜像和容器傻傻分不清。后来一个老前辈打了个比方,我一下就懂了:

  • 镜像 = 类(Class):定义了有什么属性和方法,但不能直接运行
  • 容器 = 对象(Object):类的实例化,真正跑起来的那个东西

一个镜像可以启动多个容器,每个容器都是独立的。就像一份代码模板,可以生成多个运行实例。

3.3.1 常用镜像操作

# 拉取镜像(从Docker Hub下载)
docker pull ubuntu:20.04
docker pull nginx:latest

# 查看本地镜像
docker images

# 删除镜像
docker rmi ubuntu:20.04

# 搜索镜像
docker search nginx

3.3.2 常用容器操作

# 创建并启动容器
docker run -it --name my-ubuntu ubuntu:20.04 /bin/bash

# 查看运行中的容器
docker ps

# 查看所有容器(包括已停止的)
docker ps -a

# 停止容器
docker stop my-ubuntu

# 启动已停止的容器
docker start my-ubuntu

# 进入容器内部
docker exec -it my-ubuntu /bin/bash

# 删除容器
docker rm my-ubuntu

避坑指南:我曾经在漏洞复现时,忘记停止容器就直接删镜像,结果报错说镜像被占用。正确的顺序是:先停容器,再删容器,最后删镜像。

3.4 Dockerfile基础编写:从零构建漏洞环境

Dockerfile就是一份说明书。告诉Docker:用什么基础镜像、装什么软件、复制什么文件、暴露什么端口。

我写一个最常用的例子——搭建一个带漏洞的Apache+PHP环境:

# 使用官方Ubuntu 20.04作为基础镜像
FROM ubuntu:20.04

# 设置环境变量,避免安装时交互
ENV DEBIAN_FRONTEND=noninteractive

# 更新包列表并安装Apache和PHP
RUN apt update && \
    apt install -y apache2 php libapache2-mod-php php-mysql

# 复制漏洞代码到网站目录
COPY vulnerable.php /var/www/html/

# 暴露80端口
EXPOSE 80

# 启动Apache服务
CMD ["apachectl", "-D", "FOREGROUND"]

3.4.1 Dockerfile常用指令

指令 作用 示例
FROM 指定基础镜像 FROM ubuntu:20.04
RUN 执行命令(构建时) RUN apt install -y nginx
COPY 复制文件到镜像 COPY ./app /var/www
WORKDIR 设置工作目录 WORKDIR /app
EXPOSE 声明暴露端口 EXPOSE 80
CMD 容器启动时执行的命令 CMD ["nginx", "-g", "daemon off;"]

3.4.2 构建和运行

# 在Dockerfile所在目录执行
docker build -t my-vuln-env:v1 .

# 运行容器,映射端口
docker run -d -p 8080:80 --name vuln-app my-vuln-env:v1

实战经验:构建漏洞环境时,我习惯把漏洞代码和配置文件都放在一个目录下,用COPY指令一次性复制进去。这样Dockerfile干净,也方便管理。

3.5 一个完整的漏洞环境示例

最后,我分享一个实际用过的Dockerfile。它搭建了一个存在SQL注入的LAMP环境:

FROM ubuntu:18.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt update && \
    apt install -y apache2 mysql-server php php-mysql libapache2-mod-php

# 配置MySQL,创建漏洞数据库
RUN service mysql start && \
    mysql -e "CREATE DATABASE vuln_db;" && \
    mysql -e "CREATE USER 'vuln'@'localhost' IDENTIFIED BY 'vuln123';" && \
    mysql -e "GRANT ALL PRIVILEGES ON vuln_db.* TO 'vuln'@'localhost';" && \
    mysql -e "USE vuln_db; CREATE TABLE users (id INT, username VARCHAR(50), password VARCHAR(50));" && \
    mysql -e "USE vuln_db; INSERT INTO users VALUES (1, 'admin', 'admin123'), (2, 'user', 'user123');"

# 复制存在漏洞的PHP文件
COPY sql_inject.php /var/www/html/

EXPOSE 80

CMD service mysql start && apachectl -D FOREGROUND

构建这个镜像后,你就能在本地复现一个经典的SQL注入漏洞环境了。

嗯,Docker入门就这些。说白了,镜像就是模板,容器就是实例,Dockerfile就是配方。搞懂这三样,漏洞环境搭建就成功了一半。