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就是配方。搞懂这三样,漏洞环境搭建就成功了一半。