About WebSec
这是网络安全课程设计的一部分思路。
致谢
把这篇文章献给我的网络安全任课教授,李舜鹏教授。
他是我大一入门 CTF 的启蒙导师,感谢他。
开始
本文章只用于分享知识、探讨问题,笔者不保证所有内容的正确性,请用辩证的眼光阅读本文章。
为了避免给初学者造成误导,请注意:
在一个 Docker 容器中运行多个服务的行为是错误的!
准备阶段
课设目标
完成在 Docker 单个镜像下部署五个 flag ,最终做成 CTF 靶场夺旗的形式。
本机环境
笔者采用的环境是 Arch Linux + Docker 。
不建议在 MacOS 下使用 Docker ,因为您可能会遇到无法扫描目标容器的情况,具体原因。
知识储备
本靶场使用 Nginx 作为 Web 服务中间件,所以需要了解Nginx 配置文件的编写
CTF 常用的隐写手段、Base64编码方式、JsFuck、SQL注入相关知识
漏洞设计
关于漏洞设计可以 Google 关键词 writeup ,参考别人的漏洞设计。
本靶场采用的 Flag 埋点以及流程为:
大端口明文信息 flag0 + base64 下一步的提示。
网站 robot.txt 模拟爬虫协议信息泄漏明文 flag1 + 下一步提示。
网页白色字体隐写 + JsFuck flag2 +下一步提示。
Golang + Sqlite3 实现的 SQL 注入绕过登录鉴权获得 flag3 +下一步提示。
一个简单的任意目录读漏洞,可以从提示信息中得到在 /root 下的最后一个 flag4 。
编写阶段
本次 Dockerfile 基础镜像采用 Centos ,这是服务器最常用的 Linux 系统之一,笔者也比较熟悉,所以建议您采用您最熟悉的系统作为基础镜像。
因为本镜像的 flag0 以及 flag3 相关程序采用的是 Golang 编写,所以会在根目录下存放两个 Golang 文件,在构建镜像时采用 COPY 命令拷贝进 /root 文件夹。
而对于 Golang 连接数据库的包依赖采用的是直接下载在Docker build
根文件夹,用 COPY 命令拷贝到相关路径下,而不是采用go get
命令直接拉取,是因为该命令执行时间过长。
本镜像在构建时写入文件采用了echo > 目标文件
以及 Dockerfile COPY 命令两种方式。前一种用于写入较短的文件内容,为保证 Dockerfile 的可读性,较长的文件内容采用了后一种文件拷贝方式。
本镜像数据库选用了 Sqlite3 而不是 MySQL 或者 MariaDB ,因为在 Docker 容器中执行 Systemctl 指令会被禁止。
相关的漏洞复现的网页编写以及程序源代码就不在此展现了。
部署阶段
此部分不同机器操作差异较大,请按照步骤指引进行,不需要获得和屏幕一样的运行效果。
进入编写好 Dockerfile 根目录下。

打包构建 Docker 镜像 Docker build -t 你打算取的镜像名称 .
,注意不要丢掉最后的点,这代表构建的根目录处于当前目录下。

在运行一系列指令后显示构建成功,接下来开始运行容器。docker run -d --rm --name 你为容器取得名字 你之前为镜像取得名字
此处 -d 表示后台运行 --rm 表示容器停止后自动删除。

容器在运行成功后会返回一串标识码,此时就可以进入容器。docker exec -it 你为容器取得名字 bash
就进入了容器的 bash 。此时可以通过包管理软件安装 net-tools 程序,用 ifconfig 指令获得本容器的 ip 后,就可以进行渗透测试。
渗透阶段
我们得知容器的 ip 为 http://172.17.0.2/
。
首先,在宿主机下运行 Nmap 进行扫描。

使用 nc 命令连接 1234 号端口获得如下。

获得了第一个 flag0 ,以及一串 Base64,我们对 Base64 进行多次解码。

获得提示 /robot.txt 。
浏览器进入 http://172.17.0.2/robot.txt
。

获得 flag1 ,以及下一个的提示。进入页面,显示找一找。

按 Ctrl+A 网页全选,获得内容:查看JS方法。

F12 打开控制台,找到 JS 方法。

然后执行方法,获得一串括号,这个一眼可以看出是JsFuck。

复制括号,在控制台输入这串括号,得到 flag2 以及下一个的提示。

进入该页面,一眼看出是SQL注入。

测试。


构造 SQL 注入语句。


SQL 注入成功并反选网页获得 flag3,获得下一个提示。

获得提示信息,通过拼接 URL 查看目录 /root。

渗透结束,获得了所有的 flag 。
附录
# centos
FROM centos as prod
# 定义后层镜像根目录
WORKDIR /root/
# 复制flag0的源码到容器内
COPY flag*.go ./
# 安装 Nginx
RUN yum install -y nginx sqlite-devel golang
# 拷贝 Flag2 文件
COPY index.html /usr/share/nginx/html/FindSomething/
# 拷贝 Nginx 配置文件
COPY nginx.conf /etc/nginx/nginx.conf
# 写入 robot.txt
RUN echo -e "User-agent: *\nDisallow: /FindSomething/index.html\nDisallow: /flag1{this_f1ag1_easy}" > /usr/share/nginx/html/robot.txt \
# 写入网页
&& mkdir /usr/share/html/ && echo "<html><head><meta charset="utf-8" /><title>登陆成功</title></head><body><h2>恭喜你登陆成功</h2><font color="#FFFFFF">flag3{Y0u_G0t_F1ag3} ----> /FileUpload</font></body></html>" > /usr/share/html/success.html \
&& echo "<html><head><meta charset="utf-8" /><title>用户登录</title><style>form{width: 30vw;height: 30vh;min-height: 300px;margin: 10vh auto;border: 1px solid;border-radius: 4px;}form .username,.password{display: block;float: right;}div {width: 300px;height: 80px;margin: 30px auto 0;}input label {float: left;display: inline-block;}input {height: 30px;}.button {width: 100px;margin: auto;clear: both;display: block;}</style></head><body><form action="/GotYourSQL" method="post"><div><label>username: </label><input class="username" type="text" name="username"></div><div><label>password:</label><input class="password" type="text" name="password"></div><input class="button" type="submit" value="查询"></form></body></html>" > /usr/share/html/sqlIndex.html \
# 写入最后一个 flag
&& echo "flag4{W0w_y0ur_diffcu1t_f1ag4}" > /root/flag4{W0w_y0ur_diffcu1t_f1ag4} \
# 写入 sh 脚本
&& echo -e "#!/bin/bash\n go run flag0.go & \n go run flag1.go & \n nginx\n tail -f /dev/null" > run.sh && chmod 777 run.sh
# 导入依赖
ADD mattn.tar.gz /usr/lib/golang/src/github.com/
# 启动时执行linux命令
CMD ["./run.sh"]
后记
本次实验从客观上说难度比较大,但是如果善用 Google ,还是可以完成本次实验的。
本次实验主要的难度在于开头的漏洞设计,这个需要查询相关资料了解相关漏洞程序编写的方法,以及后期在实现漏洞时的 Linux 命令操作。
在构建 Docker 镜像时,笔者建议采用将不会改变的内容放在 Dockerfile 的前面,这样在 Docker 构建镜像时会对未修改过的镜像层使用缓存,大大节约镜像构建的时间。
另外,笔者愿意为同学们解答我能解答的问题,关于我。
引用
最后更新于
这有帮助吗?