我发表在drops上的一篇娱乐文章(http://drops.wooyun.org/tips/9405),大家看过笑笑就好。
XDCTF2015是我觉得很给力的一次CTF,题目难度适中,也没出什么乱子,圆满结束了。
向来CTF是很容易出乱子的,有时候乱子来自于自身,比如某年的XDCTF因为学校机房停电导致初赛停顿了几个小时。当然,更多的乱子来自于“黑客”。
因为CTF是安全相关的竞赛,自然会吸引很多安全研究者的目光。这里的“黑客”就是指通过各种手段让其他选手没法正常做题的人。
这样的选手一般自称“搅屎棍”~嘿。
当然我没有谴责他们的意思,比赛就是和他人竞争的过程,通过各种手段阻止对手拿分我觉得也是一种能力。但是作为主办方,我们需要尽量让所有选手正常比赛,以保证一定的公平。所以我写这份文档,记录这次比赛我的处理方法。
这是一切防御手段的本源。
题目需要难度适中。如果太刁钻,容易让人放弃,并产生报复心理,放弃过后余下的时间就是给你捣蛋的时间。也不能太白痴,太白痴的题目被人分分钟秒了,余下的时间也是用来捣蛋的。
感觉题目难度要让人有这种感觉:这题我会,应该这样做,但好像有个坑,我想想怎么绕过……在一段时间的辛苦后,把题目做出来;或者题目在规定时间没有做出来,看了writeup后恍然大悟。
这样的题目,才会让大家有成就感、学到东西、感激主办方。这样下来,就能减少很多麻烦,一是大家不愿再给主办方添麻烦,二是做题很累也没工夫想别的。
有些权限限制,在代码上防御就可以了。
比如这次的web2-100,是一个任意用户密码修改的漏洞。选手在挖掘出漏洞并成功修改前台管理员的密码后,登录进去就能看到flag。
Flag是保存在用户文件中的,正常情况下xdsec-cms允许自己删除自己的文件。那么,如果第一个做出这个题目的同学拿到flag后,随手把文件一删,那就没有第二个了。
所以我在删除的代码中,加了个判断:
如果是管理员用户,就直接返回false,不允许其删除。
增删改查四个操作,删、改都要加这个判断。
当然,好事者可以写个脚本,增加999999个假文件,flag样式都类似,谁也不知道哪个是真flag,也很影响接下来的选手做题。所以严格来说,“增”的地方也需要加这个判断。
搅屎棍还有一个常用的手段,就是“暴力竞争法”。
比如某个题目需要两个步骤,第一步修改用户名为xxx,第二步触发二次注入获得注入结果。
那么我写一个脚本,用50个线程不停去修改用户名为一个不相关的名字,这样其他用户就没法正常执行第二个步骤了。(第一个步骤刚完成又被别人改没了)
这样的情况下,其他参赛者一般会认为是自己的操作方法错了,直接导致做题的方向偏离。即使参赛者发现是有人在搅屎,也只能去同样写一个脚本,用100个线程跑,才有可能继续做题。
我觉得这样的BUG在出题的时候就可以避免。就拿我举得这个例子来说,我们完全可以出一个多用户的环境,不同用户只能操作自己的用户名,这样就完全避免了上述问题。
如果这一点做不到,那么我们就应该按照12306对付刷票产业的方法对付“竞争派搅屎棍”——使用验证码。
这样将给竞争脚本的编写带来很大难度,一般也就可以避免这种问题了。
PWN暂时不说,WEB肯定会涉及一些系统服务:web服务、数据库服务、缓存服务等。
其中,Web服务又涉及中间件权限和脚本权限。我这里以nginx+php为例,数据库以mysql为例。
在很多ctf初赛中,web题目因为都比较“小”,所以经常是一台服务器放多个web题目。这种情况下权限设置就极为重要。
如果一个比赛因为权限没有设置好,导致选手用一个题目的任意文件读取漏洞,或者一个root注入+load_file直接读取到所有题目的源文件。结果好好一个ctf就瞬间变成代码审计比赛了。
所以沙盒环境是这类ctf必不可少的了,沙盒可以是近几年的docker,前几年的“虚拟主机”,或者只是简陋的open_basedir,有总比没有强。
Linux沙盒具体怎么布置可以看我的文章:https://cloud.tencent.com/developer/article/1717370,我就不再赘述了。
建议就是,一个题目放在一个独立的虚拟主机里。
在同一个题目中,服务权限设置也是极为重要。
比如一个题目是将flag藏在后台管理员密码位置,那么你可以用0x02里说的法方法,这样防范搅屎棍:
一旦有忘记的就悲剧了。
那么,不妨从根本上解决这个问题:直接去除当前数据库用户对于管理员表的“增”、“删”、“改”权限。
在mysql里就是类似GRANT select ON db.admin TO xxx@localhost,只给予select权限。当然,具体情况具体分析,可以制定出更细致的权限规划。
在pwn中,也有同样的问题。
我们遇到了一个需要用户执行命令的题目,在选手成功完成执行命令的目标以后,顺手写了个循环kill,将pwn自己的服务杀掉了,导致其他队伍不能继续做题。
这确实是个棘手的问题,因为pwn fork出的进程权限正常情况下是和pwn一样的,那么不管你再怎么给pwn降权,你也避免不了用户直接kill掉pwn进程。
我能想到的有这样三种解决方法:
法1最简单,但可能考虑不周的,毕竟linux命令那么多。法2比较粗暴,可能导致正常的操作都执行不了。法3应该是最合适的,但配置起来也最麻烦。这个需要看个人能力与ctf的复杂程度、重要性。
如果ctf涉及到文件操作(读取、上传、删除、修改、重命名)的话,就得合理设置文件权限了。
首先,要先了解自己的题目对于文件的操作具体可以允许到怎样的程度:是读取、还是修改,是否允许getshell。
这里有个劝告,CTF初赛鱼龙混扎,尽量不要允许选手getshell。Getshell以后,搅屎棍就有无数种方法让你的游戏没法继续进行。
但有时候,题目的考点就是文件上传漏洞,或者任意文件操作漏洞,不getshell怎么验证选手是否达到要求?
我这里以此次的web2为例子:web2-400的最终目的是用户getshell,利用的是一个任意文件重命名漏洞,将正常文件重命名为.php后getshell。
实际上我这题,最终要检测的是“选手是否成功将文件重命名成.php后缀”。所以是可以不允许选手真正getshell的,我的做法是:
这样就有效的保证了任意其他php文件都无法执行,这一步主要是为了保证服务器的安全。
因为我这个环境,原本整个web目录只有两个php文件,如果发现存在第三个php文件,那么就肯定是用户的webshell了。
这三步下来,就完成了一个“getshell”漏洞的配置,模拟了getshell的情况,却并不真正getshell。
那么,一个文件操作造成的getshell,除了防止选手真正getshell,还需要防范什么?当然是防范搅屎棍。
搅屎棍有一千种方式可以让游戏玩不了:删除/覆盖/重命名正常文件、将正常文件mv走,甚至是“帮助”主办方修改flag,或者修改漏洞文件。
对付起来也很简单,我将所有已存在的文件(正常文件)的权限全部改成755,所有者改成root:
这样即使有任意文件操作漏洞,也没权限修改正常文件了。
但大多数cms都会涉及缓存、上传目录、备份目录等等需要写的目录,如果也设置成不可写,cms就运行不了了。比如这次题目,后台有个静态文件下载功能,我不得不将css、js、img等目录的所有者设置为www,使静态目录可写。
熟悉linux权限的同学应该知道,一个文件是否允许被删除,是要看其所在目录的权限。如果我对他所在的目录有写权限,我就可以将其删掉,即使这个文件不属于我。
所以,通过后台的删除功能,搅屎棍可以将网站静态文件“删光光”,直接影响后面的选手做题体验。
这种情况怎么办?
Linux下的文件有一些“隐藏属性”,我们可以通过lsattr来查看,chattr来修改:
如上图,这是我配置的js目录文件的隐藏权限。
我将所有已存在的js文件全部加上了i标志(chattr +i *),i的意思就是,不允许对文件进行任何修改(包括删除)。
这时候我们可以试试rm:
如图,root用户也没法删除flag文件了。
这就有效地保证了网站文件的安全,搅屎棍没法破坏网站结构与正常功能。
巧妙地利用这些系统自带的权限控制能力,就能有效地防范搅屎棍啦!
这类搅屎棍就是真正的“坏人”了,损人不利己,是直接来捣蛋的。
比如自己拿下了flag,然后就把flag通过官方QQ群、IRC等渠道告诉所有人,直接破坏游戏的可玩性与公平性。还有比赛的时候DDOS比赛服务器的人。(那是跟你有多大仇)
对于这类人,我觉得也没什么好说,该封号的封号,该拉黑的拉黑,尽量让他无法接触参赛选手。
同时,服务器的日志要多看看,异常状态可以及时发觉。推荐一个实时日志查看工具——ngxtop:
源码和使用方法可以github上搜。
如果主办方保持一个好的态度,对参赛选手有足够的尊重与耐心,一般是不会出现这类搅屎棍的。
归根到底,CTF是一个玩耍与学习的活动,不管是主办方还是参赛者,都可以通过比赛学到很多东西。保持一个良好的心态处理问题,慢慢积累经验,收获都会大大的。
XDCTF2015的一些writeup和资料:
选手writeup:http://t.cn/RyleXYm 密码: imwg
web2 writeup:https://github.com/phith0n/XDCTF2015