代碼審計系列題目CTFD部署(上)


關於簡單部署題目請參考:https://www.cnblogs.com/Cl0ud/p/13783325.html

如果需要進行較復雜部署,可參考本篇

PHP代碼審計系列題目的部署,較之前的部署方案,改變的地方除了題目代碼之外,還將題目權限進行了限制,題目結構更正規化,基礎鏡像沒有進行修改,還是原來的 php:5.6-fpm-alpine,其不足在於該環境沒有php.ini 文件,如果你出題不需要修改這個這一點可以直接忽略,優點在於該環境相比直接使用ubuntu的鏡像環境占用的空間更小,這里當然就直接選擇使用占用空間更小的php:5.6-fpm-alpine

目錄結構如下:

-模板
	--dockerfile
	--docker-compose.yml
	--start.sh
	--www(這里面放題目的源代碼)
		---...
		---...

這里以CTFTraining中0ctf_2016_unserialize題目的Dockerfile為例進行講解:

其題目目錄環境為:

FROM php:5.6-fpm-alpine

LABEL Author="Virink <virink@outlook.com>"
LABEL Blog="https://www.virzz.com"

COPY files /tmp/

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories \
    && apk add --update --no-cache nginx mysql mysql-client \
    && docker-php-source extract \
    && docker-php-ext-install mysql \
    && docker-php-source delete \
    && mysql_install_db --user=mysql --datadir=/var/lib/mysql \
    && sh -c 'mysqld_safe &' \
	&& sleep 5s \
    && mysqladmin -uroot password 'qwertyuiop' \
    && mysql -e "source /tmp/db.sql;" -uroot -pqwertyuiop \
    && mkdir /run/nginx \
    && mv /tmp/docker-php-entrypoint /usr/local/bin/docker-php-entrypoint \
    && mv /tmp/nginx.conf /etc/nginx/nginx.conf \
    && mv /tmp/vhost.nginx.conf /etc/nginx/conf.d/default.conf \
    && mv /tmp/src/* /var/www/html \
    && chmod -R -w /var/www/html \
    && chmod -R 777 /var/www/html/upload \
    && chown -R www-data:www-data /var/www/html \
    && rm -rf /tmp/* \
    && rm -rf /etc/apk

EXPOSE 80

VOLUME ["/var/log/nginx"]

CMD ["/bin/sh", "-c", "docker-php-entrypoint"]

簡單查看這段dockerfile,很容易注意到這一點:(簡單截取一部分

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories \
    && apk add --update --no-cache nginx mysql mysql-client \

為什么這里要用兩個&&而不是直接使用兩個RUN

原因在於從 Docker 1.10 開始,COPY、ADD 和 RUN 語句會向鏡像中添加新層。前面的示例創建了兩個層而不是一個。

鏡像的層就像 Git 的提交(commit)一樣。

Docker 的層用於保存鏡像的上一版本和當前版本之間的差異。就像 Git 的提交一樣,如果你與其他存儲庫或鏡像共享它們,就會很方便。

實際上,當你向注冊表請求鏡像時,只是下載你尚未擁有的層。這是一種非常高效地共享鏡像的方式。

但額外的層並不是沒有代價的。

層仍然會占用空間,你擁有的層越多,最終的鏡像就越大。Git 存儲庫在這方面也是類似的,存儲庫的大小隨着層數的增加而增加,因為 Git 必須保存提交之間的所有變更

所以在這里我們將其合並成一條命令,就是為了減少其層數而降低占用空間的大小。

現在從頭開始閱讀Dockerfile代碼

FROM php:5.6-fpm-alpine

LABEL Author="Virink <virink@outlook.com>"
LABEL Blog="https://www.virzz.com"

FROM 命令指定基礎鏡像

LABEL指令用於為鏡像添加元數據,多用於聲明構建信息,作者、機構、組織等,每一個LABEL指令會生成一個新的鏡像層,如果你使用多個label,將導致構建出一個低效的鏡像,跟RUN命令類似,同時對我們幾乎沒啥幫助,可以略過了。

COPY files /tmp/

復制主機當前文件夾下的files文件夾到容器/tmp文件夾下

詳細講解一下RUN命令下的各條指令

sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories

在國內訪問 apk 倉庫較緩慢,修改docker容器下載源為中科大鏡像,加速后面幾步的更新和下載

apk add --update --no-cache nginx mysql mysql-client

Alpine 提供了自己的包管理工具 apk,可以通過 https://pkgs.alpinelinux.org/packages 網站上查詢包信息,也可以直接通過 apk 命令直接查詢和安裝各種軟件。

這里使用apk進行下載nginx,mysql,mysqli-client

接着是三條:

docker-php-source extract 
docker-php-ext-install mysql 
docker-php-source delete

關於docker-php-source , docker-php-ext-install ,docker-php-enable-docker-configure,詳情參考:https://www.cnblogs.com/yinguohai/p/11329273.html

這里簡單介紹:

docker-php-source extract 

在php容器中創建一個/usr/src/php目錄,里面放了一些自帶的文件

docker-php-ext-install mysql 

安裝並啟動PHP擴展,命令格式:

docker-php-ext-install “源碼包目錄名”

這里即安裝並啟動了mysql服務

docker-php-source delete

這里對 docker-php-source extract 初始化的 /usr/src/php目錄進行了刪除

接着是一段mysql的操作

mysql_install_db --user=mysql --datadir=/var/lib/mysql 
sh -c 'mysqld_safe &' 
sleep 5s 
mysqladmin -uroot password 'qwertyuiop' 
mysql -e "source /tmp/db.sql;" -uroot -pqwertyuiop

使用mysql_install_db命令初始化MySQL數據庫目錄

mysql_install_db --user=mysql --datadir=/var/lib/mysql 

mysqld_safe是服務端工具,用於啟動mysqld,並且是mysqld的守護進程,在后面加&符號令其在后台運行,而因為mysqld_safe是mysqld的守護進程,所以mysqld_safe會在啟動MySQL服務器后繼續監控其運行情況,並在其死機時重新啟動它。

sh -c 'mysqld_safe &' 

等待五秒

sleep 5s 

一般dockerfile里面的sleep都是為了等待一些服務啟動,防止運行到后面的命令時前面的服務還沒啟動,這樣就會導致報錯退出,sleep很大程度上降低了出現這種情況的概率。

mysqladmin -uroot password 'springbirdtcl11111' 

mysqladmin命令是mysql服務器管理任務的客戶端工具,它可以檢查mytsql服務器的配置和當前工作狀態,創建和刪除數據庫,創建用戶和修改用戶密碼等操作。

這里用於修改密碼了

mysql -e "source /tmp/db.sql;" -uroot -pqwertyuiop

導入並執行sql文件

mkdir /run/nginx 
mv /tmp/docker-php-entrypoint /usr/local/bin/docker-php-entrypoint 
mv /tmp/nginx.conf /etc/nginx/nginx.conf 
mv /tmp/vhost.nginx.conf /etc/nginx/conf.d/default.conf

這一段是創建nginx文件夾以及導入我們自己寫的配置文件

mv /tmp/src/* /var/www/html 
chmod -R -w /var/www/html 
chmod -R 777 /var/www/html/upload 
chown -R www-data:www-data /var/www/html

移動源代碼到html文件夾下,這樣外部可訪問

mv /tmp/src/* /var/www/html 

進行權限限制

chmod -R -w /var/www/html 
chmod -R 777 /var/www/html/upload 
chown -R www-data:www-data /var/www/html

-R : 對目前目錄下的所有文件與子目錄進行相同的權限變更(即以遞歸的方式逐個變更)

+表示增加權限、- 表示取消權限、= 表示唯一設定權限。

r 表示可讀取,w 表示可寫入,x 表示可執行,X 表示只有當該文件是個子目錄或者該文件已經被設定過為可執行。

這里遞歸取消了html目錄下的可寫入權限

因為7的二進制數為111,即遞歸增加了任意用戶對於/upload目錄下的讀寫執行權限

然后將/html目錄下的權限限制為www-data權限

rm -rf /tmp/* 
rm -rf /etc/apk

刪除之前產生的源文件,以及清除apk安裝包們

對外暴露80端口

EXPOSE 80

接着聲明容器中/var/log/nginx為匿名卷

VOLUME ["/var/log/nginx"]

當Dockerfile中聲明了匿名卷但是run的時候沒有使用 -v綁定匿名卷的話那么docker就會在/var/lib/docker/volumes這個目錄下創建一個目錄來綁定匿名卷。

也就是容器內的nginx的log日志會被掛載到主機的/var/lib/docker/volumes的一個新的目錄下

最后是

CMD ["/bin/sh", "-c", "docker-php-entrypoint"]

該docker-php-entrypoint文件在原目錄的files下,其內容為:

#!/bin/sh

sed -i "s/flag{0ctf_2016_unserialize_is_very_good!}/$FLAG/" /var/www/html/config.php

export FLAG=not_flag
FLAG=not_flag

php-fpm &

nginx &

mysqld_safe &

tail -F /var/log/nginx/error.log /var/log/nginx/access.log

其實就是實現動態flag,並且啟動相關服務,校內平台暫時還沒有用到動態flag,所以暫時不需要考慮該問題。

下面的部分摘抄自v0n師傅的博客(寫到這里的時候才發現v0n師傅寫過相關的文章了,早知道分析另外一個dockerfile了嗚嗚嗚

摘抄:

從上面的過程中,我們看到對於一道題目來說,除了源碼以外,最大的不方便之處就是還要有相關的nginx文件配置,在這里我推薦virink寫的base_image_nginx_mysql_php_56來輔助我們快速出題。 這個鏡像主要好在不需要我們去配置其他的nginx設置,而且還支持自動導入db.sql文件,支持自動執行flag.sh文件。以我在minil出的一道題為例。題目中主要是需要配置數據庫.
我們只需要src文件夾中放入源碼、flag.sh、db.sql(flag.sh、db.sql文件名不能變),現在我們dockerfile只需要這么寫:

FROM ctftraining/base_image_nginx_mysql_php_56

COPY src /var/www/html

RUN mv /var/www/html/flag.sh / \
    && chmod +x /flag.sh

這個鏡像就會自動為我們配置相關的nginx文件,同時自動導入要執行的db.sql文件來配置數據庫(默認用戶為root,密碼也為root,執行后db.sql會被刪掉)
同時鏡像還會自動執行flash.sh來從環境變量中讀取flag寫入到flag.php中(需要注意的是,flag.sh必需在根目錄下,也就是我們需要執行mv /var/www/html/flag.sh /這一步的原因所在)。 可以看到,這個鏡像極大的方便了我們對Dockerfile的編寫,把Dockerfile簡化到只需要兩三句話就能搞定。
如果是要在php7的環境下出題,可以采用base_image_nginx_mysql_php_73
至於python還是java環境的出題,我暫時還沒嘗試過,就不班門弄斧了。
如果還想通過更多的環境學習如何出題,可以在這個項目中查看更多的題目。

參考鏈接:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM