0x00 前言

再談Docker之前不知道大家有沒有遇過有漏洞想復現,或想要開發專案,結果在那邊改環境改了半天,測完又要把環境調回去,直接累死。
因此有人就會想到用虛擬機來做測試,像VulnHub就是把整個虛擬機器的檔案丟給你。

但是有用過虛擬機應該都會感受過,只要用虛擬機那效能就會大打折扣,並且在進行傳輸常常都幾個GB起跳,所以接下來就會是介紹Docker這個酷東西的時間。

Docker直接講可能會蠻抽象的,所以我們可以把它想成類似是虛擬機的東西,但如同前面所說虛擬機因為要從硬體開始模擬,還要把一部分的效能分給作業系統,結果就是常常大小都是GB起跳,且效能會明顯地感覺較差,Docker則是環境和硬體都是與本機共用,所以大小大多都是MB級的。


source: https://www.howtogeek.com/devops/what-does-docker-do-and-when-should-you-use-it/

這時候我們對於Docker的功能大概有了初步的認知,我們再來就來看看Docker的3大重點

  • 映像檔 (image)
  • 容器 (container)
  • 倉庫 (repository)

我們可以利用映像檔來建立容器,每個容器都是互相隔離開的,我們可以把映像檔丟到倉庫供大家使用。
Image想像成為虛擬機上的作業系統,用於建立Container所需的應用程式和相關環境。您可以從官方下載現有的Image,或將自己建立的Container或應用程式打包成Image。

Container則是透過Image建立的。且每個Container的環境都是相互隔離的。

Repository則是用於存放Images的地方,例如Docker Hub是由官方提供的公開線上倉庫。

接下來我們會一一示範如何建立容器

0x01 DockerFile介紹

要嘗試DockerFile之前我們先在有docker的環境下先建立一個資料夾。
並且在裡面建立一個app子資料夾,再建立一個main.py在app裡。
我們下面的code是一段有Command injection的漏洞的python網頁,我們把它複製到main.py裡面。

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
import os
from flask import Flask, render_template_string, request


app = Flask(__name__)

@app.route("/")
def home():
template = """
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>cmdi</title>
</head>
<body>
<h1>PING</h1>
<form method="POST">
<input type="text" name="ip" placeholder="IP">
<button s>submit</button>
</form>
</body>
</html>"""

return render_template_string(template)

@app.post("/")
def cmd_message():
return os.popen("ping " + request.form.get("ip")).read()

app.run(debug=True, host='0.0.0.0', port=80)

之後在app外建一個Dockerfile,結構大概像這樣

之後把下面的複製進去

1
2
3
4
5
6
7
FROM python:3.10.12-bullseye

WORKDIR /Simple_CMDI
COPY ./app .
RUN pip install flask
CMD ["python3","main.py"]

  • FROM 是用來決定我們要用什麼image
    example: FROM :<版本> (要找image可以去dockerhub)
  • WORKDIR 是決定容器指令執行的位置
  • COPY 是把主機的檔案丟給容器
    example: COPY <主機檔案>:<容器檔案>
  • RUN 容器要執行的命令
  • CMD 啟動要用的命令
    (CMD 在docker run 。 RUN 則在 docker build。)

之後我們把它build起來

1
sudo docker build -t simple_cmdi .

需要下載image所以會比較久一點
之後把他run起來我們就可以看到我們的web上線了

1
sudo docker run -p 8001:80 -d simple_cmdi 

  • -p 把指定容器的port映射到主機的port (example: -p <主機端口>:<容器端口>)
  • -d 後台執行

0x02 docker-compose 範例

剛剛我們實作了簡易dockerfile,我們可以用它來建構容器
但如果我們需要建立多個容器我們就可以用docker-compose

首先下面我們先把環境變成像這樣

1
2
3
4
5
6
7
8
./
├── app
│ ├── Dockerfile
│ └── main.py
├── docker-compose.yaml
└── web
└── index.php
2 directories, 4 files

之後我們需要寫一個docker-compose.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version: '3.5'

services:
web:
image: php:7.1-apache #容器的映像檔,本次用php:7.1-apache作範例
volumes:
- ./web:/var/www/html #將(主機)web掛到(容器)/var/www/html
ports:
- 8001:80/tcp #由(主機)8001port到(容器)80port
app:
build: ./app/ #利用我們剛剛寫的dockerfile進行build
volumes:
- ./app:/app
ports:
- 8002:80/tcp

把上面的放到docker-compose.yaml裡
之後在web裡面寫入一檔案index.php

1
2
3
4
<?php 
$curr_time = date("Y/m/d");
echo "now: " . $curr_time;
?>

我們再把app裡的COPY為改成當前位置

1
2
3
4
5
6
FROM python:3.10.12-bullseye

WORKDIR /Simple_CMDI
COPY . .
RUN pip install flask
CMD ["python3","main.py"]

我們就可以把他啟動看看

1
sudo docker-compose up -d

之後等一下後,去127.0.0.1:8001和127.0.0.1:8002有看到就是成功了!

參考資料

https://www.howtogeek.com/devops/what-does-docker-do-and-when-should-you-use-it/

https://dic.vbird.tw/network_project/zunit10.php

https://ithelp.ithome.com.tw/m/articles/10206556