> For the complete documentation index, see [llms.txt](https://3ric.gitbook.io/blog/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://3ric.gitbook.io/blog/about-websec.md).

# About WebSec

## 致谢

把这篇文章献给我的网络安全任课教授，李舜鹏教授。

他是我大一入门 CTF 的启蒙导师，感谢他。

## 开始

{% hint style="danger" %}
在开始文章之前，请确认自己的网络是可以访问 [Google](https://www.google.com)、[Wiki](https://zh.wikipedia.org/zh/Wiki) 等非常规网站。

因为本文大量链接引用了相关内容，若无法访问，可能会影响您的阅读质量。
{% endhint %}

{% hint style="danger" %}
本文章只用于分享知识、探讨问题，***笔者不保证所有内容的正确性***，请用辩证的眼光阅读本文章。
{% endhint %}

{% hint style="danger" %}
为了避免给初学者造成**误导**，请注意：

**在一个 Docker 容器中运行多个服务的行为是错误的！**
{% endhint %}

### 准备阶段

#### 课设目标

完成在 Docker 单个镜像下部署五个 flag ，最终做成 CTF 靶场夺旗的形式。

#### 本机环境

笔者采用的环境是 Arch Linux + Docker 。

不建议在 MacOS 下使用 Docker ，因为您可能会遇到无法扫描目标容器的情况，[具体原因](/blog/about-docker.md#wei-shen-me-zai-mac-xia-wu-fa-lian-jie-docker-rong-qi)。

#### 知识储备

* 有关 [Docker 的基本命令](https://www.runoob.com/docker/docker-command-manual.html)以及 [Dockerfile 的编写](/blog/about-docker.md#dockerfile)
* 本靶场使用 Nginx 作为 Web 服务中间件，所以需要了解[Nginx 配置文件的编写](https://zhuanlan.zhihu.com/p/31202053)
* CTF 常用的[隐写手段](https://en.wikipedia.org/wiki/Steganography)、[Base64编码方式](https://zh.wikipedia.org/wiki/Base64)、[JsFuck](https://zh.wikipedia.org/zh-hans/JSFuck)、[SQL注入](https://en.wikipedia.org/wiki/SQL_injection)相关知识

#### 漏洞设计

关于漏洞设计可以 Google 关键词 [writeup](https://www.google.com/search?q=writeup\&sxsrf=ALeKk01v3nrxzMDsUMp_xB52Yxg7qIDtdA:1590072789730\&source=lnt\&tbs=lr:lang_1zh-CN%7Clang_1zh-TW\&lr=lang_zh-CN%7Clang_zh-TW\&sa=X\&ved=2ahUKEwij1rHemsXpAhWuFjQIHYPyC_0QpwV6BAgMEBo\&biw=1478\&bih=702) ，参考别人的漏洞设计。

本靶场采用的 Flag 埋点以及流程为：

1. 大端口明文信息 flag0 + base64 下一步的提示。
2. 网站 robot.txt 模拟爬虫协议信息泄漏明文 flag1 + 下一步提示。
3. 网页白色字体隐写 + JsFuck flag2 +下一步提示。
4. Golang + Sqlite3 实现的 SQL 注入绕过登录鉴权获得 flag3 +下一步提示。
5. 一个简单的任意目录读漏洞，可以从提示信息中得到在 /root 下的最后一个 flag4 。

### 编写阶段

#### [Dockerfile](/blog/about-websec.md#fu-lu)

本次 Dockerfile **基础镜像**采用 Centos ，这是服务器最常用的 Linux 系统之一，笔者也比较熟悉，所以建议您采用您最熟悉的系统作为基础镜像。

因为本镜像的 flag0 以及 flag3 **相关程序**采用的是 Golang 编写，所以会在根目录下存放两个 Golang 文件，在构建镜像时采用 COPY 命令拷贝进 /root 文件夹。

而对于 Golang 连接数据库的**包依赖**采用的是直接下载在`Docker build`根文件夹，用 COPY 命令拷贝到相关路径下，而不是采用`go get`命令直接拉取，是因为该命令执行时间过长。

本镜像在构建时**写入文件**采用了`echo > 目标文件`以及 Dockerfile COPY 命令两种方式。前一种用于写入**较短的**文件内容，为保证 Dockerfile 的可读性，较长的文件内容采用了后一种文件拷贝方式。

本镜像数据库选用了 Sqlite3 而不是 MySQL 或者 MariaDB ，因为[在 Docker 容器中执行 Systemctl 指令会被禁止](/blog/about-docker.md#zai-docker-zhong-wei-shen-me-wu-fa-tiao-yong-systemctl)。

相关的漏洞复现的网页编写以及程序源代码就不在此展现了。

{% hint style="info" %}
在使用 Dockerfile 执行包管理软件时可能会遇到需要**输入 y 以继续执行**的情况，此时可以通过 -y 参数跳过所有的输入，此条建议适用于 Centos ，其他发行版本请自行查阅。
{% endhint %}

### 部署阶段

{% hint style="warning" %}
此部分不同机器操作差异较大，请按照步骤指引进行，不需要获得和屏幕一样的运行效果。
{% endhint %}

进入编写好 Dockerfile 根目录下。

![进入根目录](/files/-MAOd3ScQsI1P-9wMatY)

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

![构建镜像](/files/-MAOd3SfA9HPEKLG113x)

在运行一系列指令后显示构建成功，接下来开始运行容器。`docker run -d --rm --name 你为容器取得名字 你之前为镜像取得名字`

此处 -d 表示后台运行 --rm 表示容器停止后自动删除。

![运行容器](/files/-MAOd3SgxDM02DvgAyNg)

容器在运行成功后会返回一串标识码，此时就可以进入容器。`docker exec -it 你为容器取得名字 bash`

就进入了容器的 bash 。此时可以通过包管理软件安装 net-tools 程序，用 ifconfig 指令获得本容器的 ip 后，就可以进行渗透测试。

### 渗透阶段

我们得知容器的 ip 为 `http://172.17.0.2/` 。

首先，在宿主机下运行 Nmap 进行扫描。

![nmap 扫描](/files/-MAOd3ShE9o4HwhfOtKS)

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

![netcat 拉取](/files/-MAOd3Si0aXS1P3Lg0Lf)

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

![base64 在线解码](/files/-MAOd3Sj1UBQ5sfT1eZ-)

获得提示 /robot.txt 。

浏览器进入 `http://172.17.0.2/robot.txt` 。

![robot 内容](/files/-MAOd3SkpcEKMINuyaX0)

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

![index 页面](/files/-MAOd3Slhekdbu-TpYIM)

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

![提示 js 方法](/files/-MAOd3SmdzHlrAbfrMkA)

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

![js 方法](/files/-MAOd3SnvT0KgeesJduj)

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

![jsfuck](/files/-MAOd3SomRm5SHGzi-6l)

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

![获得 flag2](/files/-MAOd3SpRbn3cVrjaMSf)

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

![SQL 注入页面](/files/-MAOd3SqE7KURl3GrZa5)

测试。

![正常执行](/files/-MAOd3SrOy-53Vffq3h8)

![正常执行结果](/files/-MAOd3Ssrhb2aDVSyq9Q)

构造 SQL 注入语句。

![构造注入](/files/-MAOd3Ste9W0ZFkv7xQ5)

![注入成功](/files/-MAOd3SuTKviwuCgkSWJ)

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

![获得提示](/files/-MAOd3SvotTBKTzL9024)

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

![获得 flag4](/files/-MAOd3SwSBD5FF6m5bXB)

渗透结束，获得了所有的 flag 。

## 附录

{% hint style="info" %}
为保证课程设计的**多样性**，此处只放上相关的 Dockerfile 文件，而根目录下的其他文件都被省略，故**无法直接 build 镜像**。
{% endhint %}

```
#  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 构建镜像时会对未修改过的镜像层使用缓存，大大节约镜像构建的时间。

另外，笔者愿意为同学们解答我能解答的问题，[关于我](/blog/master.md#yin-yan)。

## 引用

* [Base64 在线解码](https://www.base64decode.org/)

## [许可协议](/blog/license.md)

{% hint style="info" %}
本作品采用[知识共享署名 4.0 国际许可协议(CC BY-NC-SA 4.0)](https://creativecommons.org/licenses/by-nc-sa/4.0/)进行许可，转载时请注明原文链接，图片在使用时请保留全部内容，可适当缩放并在引用处附上图片所在的文章链接。
{% endhint %}
