docker教程其实很早就在酝酿了,但因为自己天赋不高,搞不明白,一直没有出,近期由于有出题需求,不得不又拾起vm里藏灰了的docker,又深入学习了一番,这里就不得不提到网上的各种博客,看了好长时间都看不懂,浪费了大把时间,由此被我授予了无良博客的头衔。这篇博客主要是介绍一下CTF中出题所需要的docker操作。持续更新中……

docker配置教程

更换镜像源(阿里云)

选择性更换,如果再进行下面指令时没有报错,可以选择不更换

1
2
3
4
5
sudo vim /etc/apt/source.list   //打开存源文件
i //进入编辑模式
将地址黏贴进去
按ESC //退出编辑模式
输入:wq //保存并退出

镜像源地址,全部复制进去

1
2
deb https://mirrors.aliyun.com/kali kali-rolling main non-free contrib
deb-src https://mirrors.aliyun.com/kali kali-rolling main non-free contrib

创建docker

1.下载docker镜像

1
apt install docker.io    

2.搜索\下载 服务器镜像

1
2
docker search pull   //搜索服务器镜像,可以不搜
docker pull 镜像名 //例如docker pull tutum/lamp

3.创建docker

1
2
3
4
5
docker run -id --name 给docker取个名 -p 想开放的端口:80 服务器镜像名

例如:
docker run -id --name dockername1 -p 180:80 tutum/lamp
//创建tutum/lamp服务器,命名为dockername1,开放180端口供访问

4.普通题目复制

1
2
3
把文件拉到linux目录下
docker cp 文件名 docker名:/var/www/html
//把文件复制到docker的/var/www/html目录下,记得命名一个index.php,文件的其他人权限得设置成可读

5.(可有可无)进入docker查看

1
2
3
docker exec -it docker名 /bin/bash  

//进入之后就随便命令执行就好了,没问题就访问宿主机ip+端口看看,能访问就没问题

常用指令

查看docker容器状态

1
2
docker ps  
docker ps -a

查看docker镜像状态

1
docker images

新建docker容器

1
2
3
4
5
docker run -id --name 起个名 -p 开放端口:映射端口 tutum/lamp
#映射端口前首先确定端口没有被占用
#-d //容器后台运行。
#-p //指定映射端口。
#-P //随机映射高端口
1
docker run -d -p 9999:80 tutum/lamp

复制文件进入docker

1
2
3
docker cp [本地路径] [container id]:[container 路径]
例如:
docker cp flag.php docker名字:/var/www/html

查询宿主机ip

1
ifconfig

进入指定docker

1
2
3
4
docker exec -it docker名字 /bin/bash
#如果从这个容器退出,不会导致容器的停止,推荐使用 docker exec
#-i //让容器的标准输入保持打开。
#-t //让docker分配一个伪终端并绑定到容器的标准输出上。

退出当前docker容器

1
exit

导出容器

1
docker export [dockerID] > Find.tar

启动容器

1
docker start 容器ID

查看所有存在的容器

1
docker container ls -a

删除容器

1
2
docker rm [container id]或者是[container name]
#需要先把容器停掉

模板介绍

十分感谢nss的师傅提供的模板啦,这里附上链接

1
https://github.com/CTF-Archives/ctf-docker-template

利用dockerfile和docker-compose出题

这里感谢f12大佬提供的帮助

这俩东西是什么?

在此之前,我们先来明确两个个概念;

(1)镜像:
什么是镜像?当我们在虚拟机启动docker后,运行docker images,我们所看到的就是我们docker里所拥有的镜像

上面的五列依次是 镜像名称 镜像标签 镜像id 镜像创建时间 镜像大小

(2)容器:

镜像是用来干什么的呢?当然是创建容器啦,当我们输入docker ps(查看在运行的容器)或者docker ps -a(查看所有容器)就可以看到容器

了解了这些基础,我们就可以继续下面的内容了

先介绍dockerfile:

dockerfile将一些需要执行的命令存储在这个文件中,在需要的时候自动执行。我们应该如何使用这个文件捏?这个时候就要提到docker builid这个指令了,使用格式如下

1
2
3
4
docker build -t <镜像名称>:<镜像标签> <上下文路径>
例如:
docker build -t sql:v1 .
这里的.是当前目录的意思,这主要是给docker一个引用路径,告诉docker你需要的文件都在当前目录以及其子目录下

通常情况下,该命令会自动搜索.及其子目录下的名为dockerfile的文件

1
2
-f 路径
此方法可以指定文件作为dockerfile使用

参考博客:https://blog.csdn.net/m0_46090675/article/details/121846718?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169046011616800180651767%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=169046011616800180651767&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-2-121846718-null-null.142^v91^insertT0,239^v3^insert_chatgpt&utm_term=dockerfile&spm=1018.2226.3001.4187

对于以下代码的理解可以参考NSS的模板web-nginx-mysql-php73,附上截图

FROM

指定基础镜像,必须为第一个命令

1
2
3
4
5
6
7
8
9
格式:
  FROM <image>
  FROM <image>:<tag>
  FROM <image>@<digest>

示例:  
FROM mysql:5.6
注:
tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像
RUN

构建镜像时执行的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
RUN用于在构建镜像时执行命令,其有以下两种命令执行方式:
shell执行
格式:
RUN <command>
exec执行
格式:
RUN ["executable", "param1", "param2"]
示例:
RUN ["executable", "param1", "param2"]
RUN apk update
RUN ["/etc/execfile", "arg1", "arg1"]
注:RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,
可以在构建时指定--no-cache参数,如:docker build --no-cache
ADD

将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget

1
2
3
4
5
6
7
8
格式:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"] 用于支持包含空格的路径
示例:
ADD hom* /mydir/ # 添加所有以"hom"开头的文件
ADD hom?.txt /mydir/ # ? 替代一个单字符,例如:"home.txt"
ADD test relativeDir/ # 添加 "test" 到 `WORKDIR`/relativeDir/
ADD test /absoluteDir/ # 添加 "test" 到 /absoluteDir/
COPY

功能类似ADD,但是是不会自动解压文件,也不能访问网络资源

CMD
1
2
3
4
5
6
7
8
9
格式:
CMD ["executable","param1","param2"] (执行可执行文件,优先)
CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
CMD command param1 param2 (执行shell内部命令)
示例:
CMD echo "This is a test." | wc -l
CMD ["/usr/bin/wc","--help"]

注:CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。

docker-compose:

docker-compse像是一个中控系统,他可以控制由他启动的所有容器,同时启动、同时关闭、同时删除等,命名一般为xxxxx.yaml,内容格式如下,以NSS模板web-nginx-mysql-php73为例

1
重点关注services部分,缩进一次的web和www为镜像名,缩进两次的为容器参数,例如开放端口、映射端口、容器名、启动的dockerfile位置(build参数),这样可以实现同时启动多个不同容器。

启动命令

1
2
3
在该目录下执行
docker-compose up -d
docker-compose -f docker-compose.yml up -d //指定目录

这里就可以清楚的看到,我们执行docker-compose up -d后,启动了name4和name5这两个容器,然后构建了docker_www和docker_web这两个服务器镜像,此处的镜像是可以通过上述run命令二次使用的,注意docker-compose只能管理由docker-compose所启动的容器,而run启动的是不可以控制的。

1
2
3
4
5
6
docker-compose restart   //重启服务容器。
docker-compose start //启动服务容器。
docker-compose stop //停止服务容器。
docker-compose rm //删除服务(停止状态)容器。
docker-compose down //停止并删除所有服务的容器、网络、镜像、数据卷。
docker-compose images //打印服务容器所对应的镜像。

出题建议(web-nginx-mysql-php73)

基本框架
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.
├── docker
│ └── docker-compose.yml
├── Dockerfile
├── db.sql
├── service
│ └── docker-entrypoint.sh
└── src
├── shell.php
├── index.php
├── flag.php
├── connect.php
├── source
└── assets
└── bootstrap
├── css
└── js

附上大佬的讲解视频,非常详细

1
https://www.bilibili.com/video/BV1xW4y1Z7aa/?spm_id_from=333.999.0.0&vd_source=757ded406aff262d5f6010cb1a347a9a

题目框架已经是非常完整的了,只需要按照自己的需求稍加修改就可以轻松出题啦!

删除部分
1
2
3
4
5
shell.php
flag.php
docker-compose.yml中的环境变量设置

以上部分为测试用途,没用一定得删,防止出现非预期解
修改部分

(1):connect.php

1
主要用于数据库连接,其中的参数可以进行修改,但一定注意要和dockerfile中的参数值保持一致,二者必须同时修改

(2):index.php、docker-entrypoint.sh、docker-compose.yaml

1
2
3
4
5
6
7
这三者主要是用于个性化的修改:

index.php不必多说,主要是完善你自己想出的sql语句以及过滤等

docker-entrypoint.sh 里面有两种flag的生成格式,可以根据自己的需要进行修改

docker-compose.yaml 可以调整开启的端口以及环境变量等因素

(3):Dockerfile

1
根据上述介绍,将自己所需要执行的操作写入dockerfile,不放心的话可以自己本地测试一下

启动

完成上述操作后就可以启动容器啦,方法有2:

(1):如果只有一个容器,可以直接在你的dockerfile目录使用docker build命令进行创建

(2):如果有多个容器需要用到compose,那么可以在.yaml目录中执行docker-compose up -d