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

phith0n 2015-10-08 14:57:00

0x00 背景


XDCTF2015是我觉得很给力的一次CTF,题目难度适中,也没出什么乱子,圆满结束了。

向来CTF是很容易出乱子的,有时候乱子来自于自身,比如某年的XDCTF因为学校机房停电导致初赛停顿了几个小时。当然,更多的乱子来自于“黑客”。因为CTF是安全相关的竞赛,自然会吸引很多安全研究者的目光。这里的“黑客”就是指通过各种手段让其他选手没法正常做题的人。

这样的选手一般自称“搅屎棍”~嘿。当然我没有谴责他们的意思,比赛就是和他人竞争的过程,通过各种手段阻止对手拿分我觉得也是一种能力。但是作为主办方,我们需要尽量让所有选手正常比赛,以保证一定的公平。所以我写这份文档,记录这次比赛我的处理方法。

0x01 保证题目质量


这是一切防御手段的本源。

题目需要难度适中。如果太刁钻,容易让人放弃,并产生报复心理,放弃过后余下的时间就是给你捣蛋的时间。也不能太白痴,太白痴的题目被人分分钟秒了,余下的时间也是用来捣蛋的。

感觉题目难度要让人有这种感觉:这题我会,应该这样做,但好像有个坑,我想想怎么绕过……在一段时间的辛苦后,把题目做出来;或者题目在规定时间没有做出来,看了writeup后恍然大悟。

这样的题目,才会让大家有成就感、学到东西、感激主办方。这样下来,就能减少很多麻烦,一是大家不愿再给主办方添麻烦,二是做题很累也没工夫想别的。

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


有些权限限制,在代码上防御就可以了。

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

所以我在删除的代码中,加了个判断:

如果是管理员用户,就直接返回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,我就不再赘述了。建议就是,一个题目放在一个独立的虚拟主机里。

在同一个题目中,服务权限设置也是极为重要。

比如一个题目是将flag藏在后台管理员密码位置,那么你可以用0x02里说的法方法,这样防范搅屎棍:

  1. 管理员不能修改密码
  2. 不能删除管理员
  3. 不能增加管理员

一旦有忘记的就悲剧了。那么,不妨从根本上解决这个问题:直接去除当前数据库用户对于管理员表的“增”、“删”、“改”权限。在mysql里就是类似GRANT select ON db.adminTO xxx@localhost,只给予select权限。当然,具体情况具体分析,可以制定出更细致的权限规划。

在pwn中,也有同样的问题。我们遇到了一个需要用户执行命令的题目,在选手成功完成执行命令的目标以后,顺手写了个循环kill,将pwn自己的服务杀掉了,导致其他队伍不能继续做题。这确实是个棘手的问题,因为pwn fork出的进程权限正常情况下是和pwn一样的,那么不管你再怎么给pwn降权,你也避免不了用户直接kill掉pwn进程。

我能想到的有这样三种解决方法:

  1. 重命名或删掉kill、pkill、skill之类的可执行程序
  2. 将/usr/bin、/bin、/usr/local/bin等目录的other权限设置为0
  3. 使用selinux ,设置security context

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

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


如果ctf涉及到文件操作(读取、上传、删除、修改、重命名)的话,就得合理设置文件权限了。

首先,要先了解自己的题目对于文件的操作具体可以允许到怎样的程度:是读取、还是修改,是否允许getshell。这里有个劝告,CTF初赛鱼龙混扎,尽量不要允许选手getshell。Getshell以后,搅屎棍就有无数种方法让你的游戏没法继续进行。

但有时候,题目的考点就是文件上传漏洞,或者任意文件操作漏洞,不getshell怎么验证选手是否达到要求?我这里以此次的web2为例子:web2-400的最终目的是用户getshell,利用的是一个任意文件重命名漏洞,将正常文件重命名为.php后getshell。实际上我这题,最终要检测的是“选手是否成功将文件重命名成.php后缀”。

所以实际上是可以不允许选手真正getshell的,我的做法是:

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

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

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

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

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

    这三步下来,就完成了一个“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文件了。

这就有效地保证了网站文件的安全,搅屎棍没法破坏网站结构与正常功能。巧妙地利用这些系统自带的权限控制能力,就能有效地防范搅屎棍啦!

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


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

源码和使用方法可以github上搜。

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

XDCTF2015的一些writeup和资料:

评论

J

just_joker 2015-10-08 16:03:00

赞,。

Knight 2015-10-08 16:40:53

XDCTF刚好是国庆,就没玩,看看writeup算了。

R

Rainism 2015-10-08 17:10:24

真良心

B

Blood_Zero 2015-10-08 17:55:06

P牛大赞,就是有点难,没有搞出来几道题!

X

xsser 2015-10-08 19:55:47

有意思

W

winterFire 2015-10-09 00:45:44

这个有意思哈哈哈

H

HackBraid 2015-10-09 09:04:44

辛苦,题目质量真的很高

嘿ME 2015-10-09 09:51:22

可不可以这样啊,让每个队伍的flag都不一样。
队伍得到的flag为 加密算法(队伍名,flag)。

Z

zhangfei 2015-10-09 13:23:54

方法不错,[email protected]/* <![CDATA[ */!function(t,e,r,n,c,a,p){try{t=document.currentScript||function(){for(t=document.getElementsByTagName('script'),e=t.length;e--;)if(t[e].getAttribute('data-cfhash'))return t[e]}();if(t&&(c=t.previousSibling)){p=t.parentNode;if(a=c.getAttribute('data-cfemail')){for(e='',r='0x'+a.substr(0,2)|0,n=2;a.length-n;n+=2)e+='%'+('0'+('0x'+a.substr(n,2)^r).toString(16)).slice(-2);p.replaceChild(document.createTextNode(decodeURIComponent(e)),c)}p.removeChild(t)}}catch(u){}}()/* ]]> */

R

Riatre 2015-10-10 23:19:31

将owner设置成www其实是有问题的。如果有命令执行的条件的话,可以直接通过chmod 0000 .的方法搅屎。
可以考虑root:www,然后权限给775。再加上chattr +i。

A

Annabelle 2015-10-12 13:00:36

从文章获得启发,《CTF搅屎棍入门指南》

故滨 2015-10-14 17:20:51

赞。学弟。

Mark 2015-10-14 22:55:43

从文章获得启发,《CTF搅屎棍入门指南》

路人甲 2015-10-26 12:50:57

曾经我是多么单纯,自从看了这篇《CTF搅屎棍入门指南》...

昵称 2015-12-21 19:04:30

昵称在此一游,原来可以这样

phith0n

一个想当文人的黑客

随机分类

其他 文章:95 篇
浏览器安全 文章:36 篇
区块链 文章:2 篇
Android 文章:89 篇
Ruby安全 文章:2 篇

扫码关注公众号

WeChat Offical Account QRCode

最新评论

Yukong

🐮皮

H

HHHeey

好的,谢谢师傅的解答

Article_kelp

a类中的变量secret_class_var = "secret"是在merge

H

HHHeey

secret_var = 1 def test(): pass

H

hgsmonkey

tql!!!

目录