原视频:https://www.bilibili.com/video/BV16q4y1A74h
作者:智慧少年Xenny
简介:这是一个关于docker使用的教学。
包含
docker基础使用
dockerfile编写
docker-compose编写
docker在ctf中的实例
等内容进行介绍。

所需文件Xenny已上传至群里。如果不去一个个操作就看文章就行了,文章里给出了代码的。

文章目录

  • 为什么要写这篇文章
  • Docker的使用
    • Docker基础操作
    • Dockerfile
      • 举例1(test1)
      • 权限设置
      • 一些没人会告诉你的知识
      • 举例2(test2)
    • Docker compose(基本使用)
      • 举例3(test3)
    • CTF中的使用(不进行讲解,自行看代码)
      • 举例4(test4)(PWN)
      • 举例5(test5)(crypto)
    • 一些docker指令操作

为什么要写这篇文章

docker,简化配置、全平台、提高效率、方便共享、快速部署……
学习CTF的时候,无论是想用sqli-labs、upload-labs、pikachu、awvs。只需要打开docker,输入两行代码,即可完整“搭建”,在本地畅享服务。
制作动态靶机题的时候,使用docker那是再好不过的,但是怎么去实现自己想要达到的目的?这就是写这篇文章的主要原因。

Docker的使用

Docker基础操作

参考安装:百度
帮助:docker --help或者官方文档

要找资源、找帮助、找阿巴阿巴的东西、安装。都去dockerhub上找。

Dockerfile

举例1(test1)

Dockerfile:

FROM ubuntu:16.04COPY run.sh /run.shVOLUME /share/dataRUN useradd nssRUN sed -i s@/deb.debian.org/@/mirrors.aliyun.com/@g /etc/apt/sources.list && \sed -i s@/security.debian.org/@/mirrors.aliyun.com/@g /etc/apt/sources.listRUN ["apt-get", "update", "-y"]WORKDIR /home/nssRUN chmod +x /run.shENV FLAG=NSSCTF{test_flag}EXPOSE 80/tcpCMD [ "helloworld" ]USER nssENTRYPOINT [ "/run.sh" ]

run.sh:

#! /bin/bash
echo "Run with user `whoami`"
echo "Run with directory `pwd`"
echo "Run with environment $FLAG"
echo "Run with parameter $1"
tail -f /dev/nullread v
while [ "$v" == "n" ];
docat /share/data/dataread v
done;

1.FROM ubuntu:16.04:从某一基础镜像来构建我们的docker。除前面可以添加注释语句以外,docker语句的第一行必须是此类语句。
当然也可以直接FROM ubuntu,不跟冒号docker会自动去选择最新版本,跟上冒号+版本号可以指定版本。

2.COPY run.sh /run.sh:把run.sh移动到/run.sh
COPY:Copy files or folders from source to the dest path in the image’s filesystem

3.VOLUME /share/data:创建挂载点(并未实际挂载,只是创建挂载点)

4.RUN useradd nss:在镜像中运行命令,此语句即useradd nss(创建nss用户)

5.RUN sed -i s@/deb.debian.org/@/mirrors.aliyun.com/@g /etc/apt/sources.list && \ sed -i s@/security.debian.org/@/mirrors.aliyun.com/@g /etc/apt/sources.list:单纯换源

6.RUN ["apt-get", "update", "-y"]:与4不同,此格式是exec格式,而第4条相当于是shell格式。

7.WORKDIR /home/nss:指定工作目录,指定后的所有操作的相对路径都是/home/nss

8.ENV FLAG=NSSCTF{test_flag}:设置环境变量

9.EXPOSE 80/tcp:指定某个端口要被打开而不是一定会打开,这里相当于标记信息,写不写都可以,但是为了养成良好的编写习惯以及告诉其他人哪些端口应该被打开,尽量写上此语句,这样方便运维人员在使用容器时,知道要打开哪些端口。不指定/tcp或者其他链接则默认开启所有链接。

10.CMD [ "helloworld" ]:启动的时候执行,格式有3种

shell CMD echo 1
exec CMD [“echo”,“1”]
param CMD [“xxxx”] (给一个参数,后面需要有ENTRYPOINT)

11.USER nss:后面的操作都用nss用户来运行

12.ENTRYPOINT [ "/run.sh" ]:进入点(挂载点),在进入容器的时候就会执行/run.sh
配合上面CMD [ "helloworld" ],这里在进入docker时执行了/run.sh helloworld

运行测试:
这是test1目录:

先build镜像

docker build . -t mumuzi7760/test1

第一次build有点慢,如果之前就已经build过而且没有改变,会有一个CACHED的标志并使用缓存,非常的人性。
(PS:第一次太慢啦)

运行一下镜像

docker run -it --rm mumuzi7760/test1


这里再去看run.sh,首先是开头几行

echo "Run with user `whoami`"
echo "Run with directory `pwd`"
echo "Run with environment $FLAG"
echo "Run with parameter $1"

执行命令whoami输出nss,因为dockerfile执行了USER nss

工作目录/home/nss因为执行了WORKDIR /home/nss

环境变量中的FLAG因为有ENV FLAG=NSSCTF{test_flag}

parameter那里是最后说的CMD [hellowolrd]

之前的CMD [helloworld]再ENTRYPOINT["/run.sh"]和ENTRYPOINT["/run.sh",“helloworld”]是等价的。为什么要用前者呢。等会说
然后看后面几行

tail -f /dev/nullread v
while [ "$v" == "n" ];
docat /share/data/dataread v
done;

读取v这个变量,如果$v=n,就会去读取/share/data/data里面的值
可以看到,在dockerfile开头,写了一个VOLUME /share/data作为挂载点。用上面的启动方式,找不到data文件,会返回cat: /share/data/data:No such file or directory。
此时用另一种方式启动

docker run -it --rm -v 路径:/share/data mumuzi7760/test1

像这样:
再去执行,就会输出data里面的内容,当然此时再去改一下data内容再去输出,可以发现输出的内容也变了。
这里的挂载就相当于是映射,里面的文件内容改变了,物理机上面的内容也会改变;如果物理机上指定的文件内容改变了,容器里面的文件内容也会改变,这样有什么好处。比如当你在进行网站的维护时,可能要经常看日志文件,每次要看日志文件都要进入docker就变得很麻烦,但如果把这个文件给映射出来可以直接在物理机上面看和修改还有保存,就显得很方便。

如果不使用-v命令,那么会被执行到哪里呢?这里打开docker desktop


可以看到是挂载到了/var/lib/docker/volumes/阿巴阿巴/_data

回看,解释一下ENTRYPOINT,如果去掉这个再去执行会怎样呢?这里注释掉10和12,重新去启动一下(顺便就能看到CACHED)
然后再docker run -it --rm mumuzi7760/test1

可以看到,是直接进入了docker,执行操作也是没有问题的。
那么现在退出来,使用后台运行的方式去操作

docker run -dt mumuzi7760/test1
docker ps


这里可以看到,COMMAND为"/bin/bash",这里是ubuntu自动设置的,自动挂载了一个/bin/bash,没有指定ENTRYPOINT就自动去用父目录的ENTRYPOINT(相当于继承)。
这里想说,如果没有ENTRYPOINT,一般就会直接退出或者用其他的ENTRYPOINT
那么现在取消掉之前的注释,run.sh只留#!和echo那几行,后面8行注释掉会发生什么呢
操作一下看看(build、run、后台、ps)

可以发现,刚刚run起来的镜像直接退出了。因为run.sh要执行的已经执行完了,所以执行完之后他就自己退出了。因此我们在编写的时候要进行一个阻塞(比如第6行的tail、后面的死循环)来保证容器能一直运行下去。

权限设置

有时候会遇到这种情况:

看图可以发现,现在已经是root用户了,但是还是会提示permission denied。
因为容器不是虚拟机,他用的是宿主机的资源,像mount之类的操作,容器管理时是不会分配这些权限(因为这些权限可能会存在一些安全问题)
如果实在想用这些,就需要给docker一个特权,可以看这里链接:https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilitie

一般的话是用不到这个,如果是出pwn题可能就会遇到

一些没人会告诉你的知识

  • ADD or COPY
  • CMD or ENTRYPOINT
  • *Shell or Exec
  • *ARG or ENV
  • docker run -it --rm的i和t

1.ADD:更加高级的"copy"
ADD命令:copy files,folders,or remote URLs from source to the dest path in the image’s filesystem
可以明显看到ADD命令可以从远处下载内容。
此外,ADD命令还可以打包和解包,比如
ADD flag.tar.gz /xxxx,add命令会自动解包这个到/xxxx
当然最好情况下就用COPY就行了

2.用dockerfile最后的举例,如果把ENTRYPOINT["/run.sh"]换成CMD ["/run.sh"],其实是一样的。和之前说的一样命令是相同的,但是ENTRYPOINT更加符合一个容器的挂载点,而CMD更加适合作为命令来执行,最好用ENTRYPOINT吧。

3.如果用shell,执行的并不是那个命令,实际执行的是sh -c "echo 1",但是万一某个精简版的没有sh呢?而且执行shell还会开启sh进程。而exec就直接执行/bin/echo 1。所以两者一般来说是没有什么区别的。

4.这里就是两种东西,ENV是给靶机环境变量,而ARG是给dockerfile在build过程中的环境变量,build完之后即消失。

5.i:构建标准输入,t:进入一个默认的终端

举例2(test2)

build by build
举例:有一个需要编译的语言要放在docker中,这个时候不是所有的语言都可以如同python一样去动态执行。那如果提前编译再放进容器里面可以吗?答案是不行,因为操作系统的不同会导致动态链接库等不一样,所以需要一个本地的去编译。
银杏化的解释是 从一个工具人那里编译,编译完之后再从工具人那里拿过来。
dockerfile:

FROM golang:1.13.4-stretch AS worker
COPY src /srcENV KEY=NSS{test_key}WORKDIR /srcRUN go buildFROM ubuntu:16.04COPY --from=worker /src/main mainENV KEY=NSS{test_key2}RUN chmod +x /mainCMD ["/main"]

main.go:

package mainimport ("os""fmt"
)func main() {var key string = os.Getenv("KEY")fmt.Println(key)
}

1.FROM golang:1.13.4-stretch AS worker:拿了个golang的镜像,取名叫worker

后面的操作都同test1讲的一样了。
copy文件、设置环境变量、设置工作目录、执行编译、第二台、从worker拿文件、再次设置一个环境变量、加权限、CMD。

build看看

docker build . -t mumuzi7760/test2

然后run起来

docker run -it --rm mumuzi7760/test2


可以看到只输出了最后的key,是来自于ubuntu的。

清理缓存:清理build中所有的CACHED、所有的

docker duilder prune
docker image prune
docker system prune

Docker compose(基本使用)

yaml:自己看文档

举例3(test3)

docker-compose.yml:

version: '3'
# Linux + Nginx + Mysql + PHP
services:nginx:build: ./nginxcontainer_name: "nginx"ports:- 8080:80restart: alwayscap_add:- SYS_ADMINdepends_on:- php1- php2networks:default:my_net:ipv4_address: 172.2.0.3php1:build: ./php1container_name: nssctfphp2:build: ./php2container_name: xennymysql:build: ./mysqlcontainer_name: mysqlenvironment:- MYSQL_ROOT_PASSWORD=password- MYSQL_DATABASE=appcommand: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --sql-mode='' --max-execution-time=1000networks:my_net:driver: bridgeinternal: trueipam:config:- subnet: 172.2.0.0/16

构造了一个LNMP(Linux + Nginx + Mysql + PHP)

1.version: '3':指定操作系统的版本

2.services:指定有多少服务,这里有nginx、php1、php2、mysql

3.build: ./nginx:从nginx目录里面去build,如果是已经存在的镜像,可以用image:imageName去拿

4.container_name: "nginx":运行起来的容器名字、主机名

5.ports: - 8080:80:指定映射,dockerfile就不能指定启动的操作,dockerfile如果要映射在run的时候必须自己指定,如docker run -p xxxx:xxxx,而docker-compose就可以像这样直接在里面指定8080:80

6.restart: always:服务挂了自动重启

7.cap_add:特权

8.depends_on::等php1和php2启动了再启动Nginx

9.networks:如果没有配置network,会把所有镜像单独配置在default网络中,这里还给Nginx单独配置了my_net网络,并配置了ip为172.0.0.3

10.environment: - MYSQL_ROOT_PASSWORD=password - MYSQL_DATABASE=app:指定环境变量

11.command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --sql-mode='' --max-execution-time=1000:跟参数就可以了。这里就相当于之前说的param CMD ["xxxx"] (给一个参数,后面需要有ENTRYPOINT)的用法

12.网络配置:名字my_net、网桥、internal:true不出网(默认出网)、配置ip地址

下面是文件夹中的部分文件内容:
nginx:Dockerfile:

FROM nginx:latestCOPY default.conf /etc/nginx/conf.d/default.conf

nginx:default.conf配置文件:

server {listen 80 default_server;listen [::]:80 default_server;server_name _;location /nssctf {proxy_pass http://nssctf/;}location /xenny {proxy_pass http://xenny/;}
}

location那里设置了反代、nssctf和xenny就是主机名。解析nssctf就会被解析到http://nssctf/中

php1:Dockerfile:

FROM php:7.2-apacheRUN docker-php-ext-install mysqliCOPY src/ /var/www/html

php1:src/index.php

<?php$conn = mysqli_connect('mysql', 'root', 'password', 'app');
$query = "select * from user";
$result = mysqli_query($conn, $query);
$row = mysqli_fetch_array($result);print_r($row);

去链接mysql。
当然php1的dockerfile里RUN docker-php-ext-install mysqli是可以不要的,docker-php-ext-install是去安装了一个拓展,这个命令在手册里面有讲解,需要用的时候再去看就可以了。

php2就和php1一样,但是少了RUN docker-php-ext-install mysqli,然后index.php的内容为echo “hello”;

mysql:dockerfile:

FROM mysql:5COPY app.sql /docker-entrypoint-initdb.d/app.sql

mysql:app.sql:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`username` varchar(400) NOT NULL,`password` varchar(400) NOT NULL,PRIMARY KEY (`id`) USING BTREE,UNIQUE KEY `username` (`username`) USING HASH
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;BEGIN;
INSERT INTO `user` VALUES (1, 'nss', 'nssctf');
COMMIT;SET FOREIGN_KEY_CHECKS = 1;

启动来看一下吧
进入test3文件夹,然后输入docker-compose up
中途遇到报错自行百度。

然后去访问一下8080,之前说过了有反代,所以访问那个地址去试试

没有问题啊。就通过这样的compose,就完成了还算毕竟复杂的操作。之前提到了网络,看一下他的网络如何。
首先是docker ps,记得开个新的终端

通过bin bash去Nginx看看

docker exec -it ID /bin/bash

比如我就要执行docker exec -it 91e /bin/bash

那么可以看到有两个ip,第一个172.18.0.5就是default的ip,而172.2.0.3就是自己配置的my_net

除了上面的指令以外,还有个指令

docker attach 91e

之前的docker exec -it ID /bin/bash其实并没有进入这个容器,而是弹了一个bash出来让我们能在容器里操作,而attach才算进入了容器内部。

CTF中的使用(不进行讲解,自行看代码)

举例4(test4)(PWN)

flag.sh:

#! /bin/bashecho $FLAG > /home/ctf/flag.txt
FLAG=flag_not_here
export FLAG=flag_not_here
rm /home/ctf/flag.sh

service:题目

xingtd_config:

service ctf
{disable = nosocket_type = streamprotocol = tcpwait = nouser = ctftype = UNLISTEDbind = 0.0.0.0port = 9999server = /home/ctf/service
}

Dockerfile:

FROM ubuntu:18.04
RUN dpkg --add-architecture i386ENV FLAG=NSSCTF{test_flag}RUN apt update
RUN yes Y | apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386
RUN apt-get install multiarch-supportRUN apt install -y xinetdRUN groupadd -r ctf && useradd -r -g ctf ctf
RUN mkdir -p /home/ctf/COPY service /home/ctf/
COPY flag.sh /home/ctf/
COPY xinetd_config /etc/xinetd.d/RUN chown -R root:ctf /home/ctf/
RUN chmod -R 750 /home/ctf/
RUN chmod +x /home/ctf/flag.shEXPOSE 9999CMD /home/ctf/flag.sh && service xinetd restart && /bin/sleep infinity

举例5(test5)(crypto)

Dockerfile:

FROM python:2-slimCOPY main.py /ENV FLAG=NSSCTF{123456}RUN sed -i s@/deb.debian.org/@/mirrors.aliyun.com/@g /etc/apt/sources.list && \sed -i s@/security.debian.org/@/mirrors.aliyun.com/@g /etc/apt/sources.list && \apt-get update -y && \apt-get install socat -y && \pip install pycryptodomeEXPOSE 9999
ENTRYPOINT socat TCP4-LISTEN:9999,tcpwrap=script,reuseaddr,fork EXEC:"python -u /main.py"

main.py:题目,这里不放了。想要完整打包代码可以进Xenny的群里看看。

一些docker指令操作

docker version:查看docker版本
docker images:查看docker镜像
docker run -it ubuntu /bin/sh:交互运行
docker exec -it ID /bin/bash:进入一个后台启动的容器
docker ps:查看运行的docker
docker log ID:查看docker输出
docker stop ID:停止容器,如果安装了docker desktop也可以在这里面关闭
docker start ID:开启一个已经停止的容器
docker export ID > 容器名称.tar:导出某个容器到压缩包

docker port ID:查看端口映射
docker top ID:查看内部进程
docker run -d -p 外部:内部 容器名称:映射端口运行容器 (这里就体现了docker-compose的好处了吧)

然后一般要用某些东西,比如想要安装pikachu可以这样:
docker search pikachu:搜索镜像
docker pull xxx/xxxx:获取镜像
docker rmi xxx:删除本地镜像

就像这样:

其他要用的到时候再去找百度吧,总之docker忒好用了。

[视频改]Docker技术从0到1全覆盖 docker入门向 文字版相关推荐

  1. Docker 安装和使用日常命令全覆盖

    Docker安装和使用 一. Centos7安装docker 1.1 Docker 要求 CentOS 系统的内核版本高于 3.10 uname –r 1.2 使用 root 权限登录 Centos一 ...

  2. [总结]视频质量评价技术零基础学习方法

    前段时间略忙,因此一直计划要总结的很多东西都没来得及写,这两天趁着空闲时间写上一篇.以后等时间充裕了再补充一些内容.本文总结一下学习视频质量评价技术的方法.视频质量评价是我研究生阶段主要的工作,包括发 ...

  3. 视频质量评价技术零基础学习方法

    前段时间略忙,因此一直计划要总结的很多东西都没来得及写,这两天趁着空闲时间写上一篇.以后等时间充裕了再补充一些内容.本文总结一下学习视频质量评价技术的方法.视频质量评价是我研究生阶段主要的工作,包括发 ...

  4. Docker安装mysql8.0

    1.准备工作 已安装Docker.如阿里云服务器注意开通服务器安全组访问规则端口号 2.下载mysql8.0docker镜像 docker pull mysql:8.0 3.查看下载的docker镜像 ...

  5. WEB前端有必要学会docker吗?0基础-45分钟带你学会(包含视频笔记案例源代码)

    文章目录 一.为什么要使用docker 二.Windows10/11系统安装Docker Desktop 三.如何判断电脑已经安装好docker 四.docker前端应用实战:将vue项目打包为doc ...

  6. SRS视频服务器-docker部署srs4.0.198-ubuntu系统:配置低时延实现srt推流和拉流

    一.docker安装srs4.0.198 推荐使用docker来安装srs视频服务器,简单方便 我使用的是ubuntu18.04系统. 1.1.docker的安装 我参考的是:https://blog ...

  7. SRS视频服务器-docker部署srs4.0:带SRT功能

    0.docker的简单命令 #镜像命令 docker pull 镜像名:版本 docker search  镜像 docker rmi 镜像id #运行 docker run [可选参数] 镜像id ...

  8. ​苏宁回应股权质押给淘宝:正常合作;苹果App Store被越狱商店指控垄断;Docker 20.10.0发布|极客日报...

    整理 | 郑丽媛 头图 | CSDN 下载自东方 IC 快来收听极客头条音频版吧,智能播报由出门问问「魔音工坊」提供技术支持. 「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「 ...

  9. 极客日报第 28 期:苹果为取代高通芯片,开始研发蜂窝网调制解调器;Docker 20.10.0 发布

    文章目录 互联网快讯 程序员专属 Github 每日精选 CSDN 社区优质博文精选 互联网快讯 1.360 周鸿祎:用户对个人信息使用应享有知情权.选择权 近日,360 集团董事长兼 CEO 周鸿祎 ...

最新文章

  1. AME_Oracle自带AME审批链详解AME Standard Handler(概念)
  2. 用switch写收水费的c语言程序,超级新手,用switch写了个计算器程序,求指导
  3. HDU 1026 Ignatius and the Princess I(BFS)
  4. db2去除字段内容空格_Vue CLI3.x 配置指南生产环境去除console
  5. 诡异的防火墙故障,能PING通,但访问ORACLE不稳定
  6. go语言服务器运行,Go语言实现Web服务器
  7. 九里机器人_电子科技大学九里堤校区青少年科教基地为农民工留守子女开展科技讲学公益活动...
  8. windows下执行testng用例
  9. OpenCV-图像金字塔cv::buildPyramid
  10. dnsmasq, ipset和iptables配置
  11. TC与CATIA集成使用说明
  12. Qt创建Qt Designer自定义控件及使用
  13. 单元二:全桥MOS/IGBT电路(后端全桥电路的搭建)
  14. linux系统下安装qq,Ubuntu 12.04安装QQ2012
  15. 陈立杰的励志演讲. 充满动力地走下去吧!
  16. windows配置好用的RSS
  17. svn 添加忽略后解除被忽略的文件或文件夹
  18. 水稻CBL家族蛋白质查找
  19. qevent 事件的accept()和ignore()
  20. # Android实习周记-9.29

热门文章

  1. “被骗”的1600万,QQ飞车多久能赚回来?
  2. 推荐系统实践读书笔记-05利用上下文信息
  3. 你曾后悔进入 IT 行业吗?为什么?(转自知乎)--一生不悔入IT
  4. html网页播放器编辑代码大全
  5. 用U盘启动盘给Dell服务器装系统找不到RAID阵列解决办法
  6. 汽车市场勇进派 乐车邦林金文的逆周期生意
  7. Autojs 谁是卧底-炸弹猫计牌辅助
  8. iOS 学习之旅 - OC 篇
  9. python对新媒体运营的帮助_一年新媒体工作积累的经验
  10. 杭州地区IT公司招聘分析与求职建议