• 代码审计系列题目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环境的出题,我暂时还没尝试过,就不班门弄斧了。
    如果还想通过更多的环境学习如何出题,可以在这个项目中查看更多的题目。

    参考链接:

  • 相关阅读:
    android socket传输序列化对象的代码
    python通过pil模块对图片格式进行转换的代码
    python获取命令行参数的代码
    【LEETCODE】41、905. Sort Array By Parity
    【LEETCODE】40、1051. Height Checker
    【LEETCODE】39、第561题 Array Partition I
    【LEETCODE】38、167题,Two Sum II
    【LEETCODE】37、122题,Best Time to Buy and Sell Stock II
    【LEETCODE】36、121题,Best Time to Buy and Sell Stock
    【LEETCODE】35、169题, Majority Element
  • 原文地址:https://www.cnblogs.com/Cl0ud/p/14018114.html
Copyright © 2020-2023  润新知