# CTF主办方指南之对抗搅屎棍

Author: 乌云历史资料库 (@wooyun_archive)
Published: 2015-10-08T06:57:00Z
Canonical: https://wepostx.com/topics/1092

> 乌云历史资料归档
>
> **原始作者：** phith0n
> **原始编号：** superkieran-wooyundrops:810
> **原始发布时间：** 2015-10-08 14:57
> **声明：内容仅用于技术研究和个人使用，版权归 wooyun.org。**

---

# 0x00 背景

XDCTF2015是我觉得很给力的一次CTF，题目难度适中，也没出什么乱子，圆满结束了。
向来CTF是很容易出乱子的，有时候乱子来自于自身，比如某年的XDCTF因为学校机房停电导致初赛停顿了几个小时。当然，更多的乱子来自于“黑客”。因为CTF是安全相关的竞赛，自然会吸引很多安全研究者的目光。这里的“黑客”就是指通过各种手段让其他选手没法正常做题的人。
这样的选手一般自称“搅屎棍”~嘿。当然我没有谴责他们的意思，比赛就是和他人竞争的过程，通过各种手段阻止对手拿分我觉得也是一种能力。但是作为主办方，我们需要尽量让所有选手正常比赛，以保证一定的公平。所以我写这份文档，记录这次比赛我的处理方法。

# 0x01 保证题目质量

这是一切防御手段的本源。
题目需要难度适中。如果太刁钻，容易让人放弃，并产生报复心理，放弃过后余下的时间就是给你捣蛋的时间。也不能太白痴，太白痴的题目被人分分钟秒了，余下的时间也是用来捣蛋的。
感觉题目难度要让人有这种感觉：这题我会，应该这样做，但好像有个坑，我想想怎么绕过……在一段时间的辛苦后，把题目做出来；或者题目在规定时间没有做出来，看了writeup后恍然大悟。
这样的题目，才会让大家有成就感、学到东西、感激主办方。这样下来，就能减少很多麻烦，一是大家不愿再给主办方添麻烦，二是做题很累也没工夫想别的。

# 0x02 防御第一招——代码层

有些权限限制，在代码上防御就可以了。
比如这次的web2-100，是一个任意用户密码修改的漏洞。选手在挖掘出漏洞并成功修改前台管理员的密码后，登录进去就能看到flag。Flag是保存在用户文件中的，正常情况下xdsec-cms允许自己删除自己的文件。那么，如果第一个做出这个题目的同学拿到flag后，随手把文件一删，那就没有第二个了。
所以我在删除的代码中，加了个判断：

![原文图片](/media/2016/06/71d4a09adb010321abb4315d651e2aea)

如果是管理员用户，就直接返回false，不允许其删除。增删改查四个操作，删、改都要加这个判断。当然，好事者可以写个脚本，增加999999个假文件，flag样式都类似，谁也不知道哪个是真flag，也很影响接下来的选手做题。所以严格来说，“增”的地方也需要加这个判断。
搅屎棍还有一个常用的手段，就是“暴力竞争法”。
比如某个题目需要两个步骤，第一步修改用户名为xxx，第二步触发二次注入获得注入结果。那么我写一个脚本，用50个线程不停去修改用户名为一个不相关的名字，这样其他用户就没法正常执行第二个步骤了。（第一个步骤刚完成又被别人改没了）这样的情况下，其他参赛者一般会认为是自己的操作方法错了，直接导致做题的方向偏离。即使参赛者发现是有人在搅屎，也只能去同样写一个脚本，用100个线程跑，才有可能继续做题。
我觉得这样的BUG在出题的时候就可以避免。就拿我举得这个例子来说，我们完全可以出一个多用户的环境，不同用户只能操作自己的用户名，这样就完全避免了上述问题。如果这一点做不到，那么我们就应该按照12306对付刷票产业的方法对付“竞争派搅屎棍”——使用验证码。这样将给竞争脚本的编写带来很大难度，一般也就可以避免这种问题了。

# 0x03防御第二招——服务权限层

PWN暂时不说，WEB肯定会涉及一些系统服务：web服务、数据库服务、缓存服务等。其中，Web服务又涉及中间件权限和脚本权限。我这里以nginx+php为例，数据库以mysql为例。
在很多ctf初赛中，web题目因为都比较“小”，所以经常是一台服务器放多个web题目。这种情况下权限设置就极为重要。如果一个比赛因为权限没有设置好，导致选手用一个题目的任意文件读取漏洞，或者一个root注入+load_file直接读取到所有题目的源文件。结果好好一个ctf就瞬间变成代码审计比赛了。
所以沙盒环境是这类ctf必不可少的了，沙盒可以是近几年的docker，前几年的“虚拟主机”，或者只是简陋的open_basedir，有总比没有强。Linux沙盒具体怎么布置可以看我的文章：[https://www.leavesongs.com/PENETRATION/nginx-safe-dir.html](https://www.leavesongs.com/PENETRATION/nginx-safe-dir.html)，我就不再赘述了。建议就是，一个题目放在一个独立的虚拟主机里。
在同一个题目中，服务权限设置也是极为重要。
比如一个题目是将flag藏在后台管理员密码位置，那么你可以用0x02里说的法方法，这样防范搅屎棍：

- 管理员不能修改密码

- 不能删除管理员

- 不能增加管理员
一旦有忘记的就悲剧了。那么，不妨从根本上解决这个问题：直接去除当前数据库用户对于管理员表的“增”、“删”、“改”权限。在mysql里就是类似GRANT select ON db.admin [email protected]，只给予select权限。当然，具体情况具体分析，可以制定出更细致的权限规划。
在pwn中，也有同样的问题。我们遇到了一个需要用户执行命令的题目，在选手成功完成执行命令的目标以后，顺手写了个循环kill，将pwn自己的服务杀掉了，导致其他队伍不能继续做题。这确实是个棘手的问题，因为pwn fork出的进程权限正常情况下是和pwn一样的，那么不管你再怎么给pwn降权，你也避免不了用户直接kill掉pwn进程。
我能想到的有这样三种解决方法：

- 重命名或删掉kill、pkill、skill之类的可执行程序

- 将/usr/bin、/bin、/usr/local/bin等目录的other权限设置为0

- 使用selinux ，设置security context
法1最简单，但可能考虑不周的，毕竟linux命令那么多。法2比较粗暴，可能导致正常的操作都执行不了。法3应该是最合适的，但配置起来也最麻烦。这个需要看个人能力与ctf的复杂程度、重要性。

# 0x04防御第三招——文件权限层

如果ctf涉及到文件操作（读取、上传、删除、修改、重命名）的话，就得合理设置文件权限了。
首先，要先了解自己的题目对于文件的操作具体可以允许到怎样的程度：是读取、还是修改，是否允许getshell。这里有个劝告，CTF初赛鱼龙混扎，尽量不要允许选手getshell。Getshell以后，搅屎棍就有无数种方法让你的游戏没法继续进行。
但有时候，题目的考点就是文件上传漏洞，或者任意文件操作漏洞，不getshell怎么验证选手是否达到要求？我这里以此次的web2为例子：web2-400的最终目的是用户getshell，利用的是一个任意文件重命名漏洞，将正常文件重命名为.php后getshell。实际上我这题，最终要检测的是“选手是否成功将文件重命名成.php后缀”。
所以实际上是可以不允许选手真正getshell的，我的做法是：

- 整站，只有指向index.php和th3r315adm1n.php两个文件的请求才会发送给fastcgi执行：

![原文图片](/media/2016/06/fefe243fc8ae2d4192fa125bae27b9c5)

这样就有效的保证了任意其他php文件都无法执行，这一步主要是为了保证服务器的安全。

- 所有其他以.php为后缀的请求，如果该文件存在，我就认为用户成功getshell了。这时就将请求rewrite到flag文本文件里，用户得到flag：

![原文图片](/media/2016/06/afac559d03458b9225dbd715c48c3425)

因为我这个环境，原本整个web目录只有两个php文件，如果发现存在第三个php文件，那么就肯定是用户的webshell了。

- 所有请求为“flag-”开头，以“.txt”结尾的，全部返回403。这是为了防止有人直接猜到flag文件名：

![原文图片](/media/2016/06/c28206e5c70f8cf4d2d70ac669cadf40)

这三步下来，就完成了一个“getshell”漏洞的配置，模拟了getshell的情况，却并不真正getshell。

那么，一个文件操作造成的getshell，除了防止选手真正getshell，还需要防范什么？
当然是防范搅屎棍。搅屎棍有一千种方式可以让游戏玩不了：删除/覆盖/重命名正常文件、将正常文件mv走，甚至是“帮助”主办方修改flag，或者修改漏洞文件。对付起来也很简单，我将所有已存在的文件（正常文件）的权限全部改成755，所有者改成root：

![原文图片](/media/2016/06/62ea5f89ad09d13cc6a03fcfc99dd46c)

这样即使有任意文件操作漏洞，也没权限修改正常文件了。
但大多数cms都会涉及缓存、上传目录、备份目录等等需要写的目录，如果也设置成不可写，cms就运行不了了。比如这次题目，后台有个静态文件下载功能，我不得不将css、js、img等目录的所有者设置为www，使静态目录可写。
熟悉linux权限的同学应该知道，一个文件是否允许被删除，是要看其所在目录的权限。如果我对他所在的目录有写权限，我就可以将其删掉，即使这个文件不属于我。所以，通过后台的删除功能，搅屎棍可以将网站静态文件“删光光”，直接影响后面的选手做题体验。
这种情况怎么办？Linux下的文件有一些“隐藏属性”，我们可以通过lsattr来查看，chattr来修改：

![原文图片](/media/2016/06/19e88f6bd54fae578ba82736e105248e)

如上图，这是我配置的js目录文件的隐藏权限。
我将所有已存在的js文件全部加上了i标志（chattr +i *），i的意思就是，不允许对文件进行任何修改（包括删除）。
这时候我们可以试试rm：

![原文图片](/media/2016/06/9fabac6c32a53ae6e7d1bd06036682b9)

如图，root用户也没法删除flag文件了。
这就有效地保证了网站文件的安全，搅屎棍没法破坏网站结构与正常功能。巧妙地利用这些系统自带的权限控制能力，就能有效地防范搅屎棍啦！

# 0x05防御第四招——对抗报复社会型搅屎棍

这类搅屎棍就是真正的“坏人”了，损人不利己，是直接来捣蛋的。比如自己拿下了flag，然后就把flag通过官方QQ群、IRC等渠道告诉所有人，直接破坏游戏的可玩性与公平性。还有比赛的时候DDOS比赛服务器的人。（那是跟你有多大仇）对于这类人，我觉得也没什么好说，该封号的封号，该拉黑的拉黑，尽量让他无法接触参赛选手。同时，服务器的日志要多看看，异常状态可以及时发觉。推荐一个实时日志查看工具——ngxtop：

![原文图片](/media/2016/06/00f5ef95d50abe74fef9aec6a86586cd)

源码和使用方法可以github上搜。
如果主办方保持一个好的态度，对参赛选手有足够的尊重与耐心，一般是不会出现这类搅屎棍的。归根到底，CTF是一个玩耍与学习的活动，不管是主办方还是参赛者，都可以通过比赛学到很多东西。保持一个良好的心态处理问题，慢慢积累经验，收获都会大大的。
XDCTF2015的一些writeup和资料：

- 选手writeup：[http://t.cn/RyleXYm](http://t.cn/RyleXYm) 密码: imwg

- web2 writeup：[https://github.com/phith0n/XDCTF2015](https://github.com/phith0n/XDCTF2015)

## Replies
