云服务器AWD平台搭建
开学后实验室来了几个新同学,在线上CTF方面大家一直在持续学习,但AWD模式的CTF我们练习并不多,所以准备搭建一个AWD平台用于实验室成员的线下赛攻防练习。
最开始的是防灾科技大学的线下AWD靶场:
https://github.com/glzjin/20190511_awd_docker
但是靶场没有计分板和组队显示等功能,又找了一下:
https://github.com/zhl2008/awd-platform
腾讯云服务器没有FQ,从github上面拉取下来有495MB,本来想从本地电脑上下载后上传到云服务器上使用 unzip 命令进行解压,但 unzip 的速度也很慢,重新寻找解决办法:
https://zhuanlan.zhihu.com/p/112697807
如果只是为了clone加速,完成到第四步就可以了:
我的码云拉取地址在:
https://gitee.com/Cl0udG0d/awd-platform
接着在云服务器上面使用 git clone
现在的速度就很快了:
花三十秒的时间下载完毕。
1 | cd awd-platform/ |
目录中有AWD线下环境手册文档,但是在搭建的时候还是会有很多不完善的地方,综合网上的多篇博客共同搭建并优化。
AWD环境中的机器按照功能分为几种类型:
-
Check_Server:
服务检查服务器,用于判定选手维护的服务是否可用,如果不可用,则会扣除相应的分数,不开启任何端口,需要与flag服务器通信
简单来说这台机器的作用就是检查靶机宕机没有
-
Flag_Server:
选手提交flag的服务器,并存储选手的分数,开启80端口
简单来说这台机器就是获取到flag后的提交对象,用于加分
-
Web_Server:
选手连接的服务器,选手需要对其进行维护,并尝试攻击其他队伍的机器,通常开启80端口,22端口,并将端口映射到主机。
这个就是我们每个队伍所要操作的机器。
比赛逻辑拓补:
云服务器首先安装docker,有很多师傅写过安装docker的文章,跳过这一步。
接着下载镜像
1 | docker pull zhl2008 /web_14 .04 |
接着按照参考文章里面的:
所以我们将镜像的名字修改:
1 | docker tag zhl2008 /web_14 .04 web_14.04 |
接着我们按照文档里面来进行操作:
后面的数字是靶机的数量,也就是参赛队伍的数量,我们先复制所有队伍的比赛文件夹和启动比赛(这里启动的是2个参赛队):
1 2 | python batch.py web_yunnan_simple 2 python start.py ./ 2 |
这里使用的靶机是 web_yunnan_simple ,至此,靶机就已经可以访问了,因为是在一个服务器上运行了多个docker,靶机的端口映射规则为:
team1 ---- 8801
team3 ---- 8802
team3 ---- 8803
....以此类推
如图:
各个靶机的ssh密码在目录文件夹下的pass.txt文件中,如图
其ssh端口映射规则为:
team1 ---- 2201
team2 ---- 2202
team3 ---- 2203
....以此类推
但是我们还没有启动 check 脚本,而项目中原来的check脚本是不能用的,我们需要进行一些修改,这个规则要根据自己的环镜自己编写,总体思路就是判断页面是否存在,存在就加一分,不存在就减一分
网上有修改过后的 check 脚本,同时可以看到 flag-server 和 check-server 所映射的端口
使用大佬们的check.py脚本
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | #!/usr/bin/env python # -*- coding:utf8 -*- ''' ''' import hashlib import base64 sleep_time = 300 debug = True headers = { "User-Agent" : "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36" } import time import httplib import urllib2 import ssl my_time = 'AAAA' __doc__ = 'http(method,host,port,url,data,headers)' flag_server = '172.17.0.1' key = '744def038f39652db118a68ab34895dc' hosts = open ( 'host.lists' , 'r' ).readlines() user_id = [host.split( ':' )[ 0 ] for host in hosts] hosts = [host.split( ':' )[ 1 ] for host in hosts] port = 80 def http(method,host,port,url,data,headers): con = httplib.HTTPConnection(host,port,timeout = 2 ) if method = = 'post' or method = = 'POST' : headers[ 'Content-Length' ] = len (data) headers[ 'Content-Type' ] = 'application/x-www-form-urlencoded' con.request( "POST" ,url,data,headers = headers) else : headers[ 'Content-Length' ] = 0 con.request( "GET" ,url,headers = headers) res = con.getresponse() if res.getheader( 'set-cookie' ): #headers['Cookie'] = res.getheader('set-cookie') pass if res.getheader( 'Location' ): print "Your 302 direct is: " + res.getheader( 'Location' ) a = res.read() con.close() return a def https(method,host,port,url,data,headers): url = 'https://' + host + ":" + str (port) + url req = urllib2.Request(url,data,headers) response = urllib2.urlopen(req) return response.read() def get_score(): res = http( 'get' ,flag_server, 8080 , '/score.php?key=%s' % key,'',headers) print res user_scores = res.split( '|' ) print "******************************************************************" res = '' print res print "******************************************************************" return user_scores def write_score(scores): scores = '|' .join(scores) res = http( 'get' ,flag_server, 8080 , '/score.php?key=%s&write=1&score=%s' % (key,scores),'',headers) if res = = "success" : return True else : print res raise ValueError class check(): def index_check( self ): res = http( 'get' ,host,port, '/index.php?file=%s' % str (my_time),'',headers) if 'perspi' in res: return True if debug: print "[fail!] index_fail" return False def server_check(): try : a = check() if not a.index_check(): return False return True except Exception,e: print e return False game_round = 0 while True : scores = get_score() scores = [] print "--------------------------- round %d -------------------------------" % game_round for host in hosts: print "---------------------------------------------------------------" host = host[: - 1 ] if server_check(): print "Host: " + host + " seems ok" scores.append( "0" ) else : print "Host: " + host + " seems down" scores.append( "-10" ) game_round + = 1 write_score(scores) time.sleep(sleep_time) |
按照文档启动check服务
1 | docker attach check_server/ |
1 | python check.py |
使用的腾讯云服务器,这一步的时候出错了
连接超时,查看 check.py 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | game_round = 0 while True : scores = get_score() scores = [] print "--------------------------- round %d -------------------------------" % game_round for host in hosts: print "---------------------------------------------------------------" host = host[: - 1 ] if server_check(): print "Host: " + host + " seems ok" scores.append( "0" ) else : print "Host: " + host + " seems down" scores.append( "-10" ) game_round + = 1 write_score(scores) time.sleep(sleep_time) |
运行的是这一段
while循环调用,一段时间延迟后进行服务可用性的检查,延迟时间由sleep_time决定
get_score() 函数报错,查看报错行:
1 | res = http( 'get' ,flag_server, 8080 , '/score.php?key=%s' % key,'',headers) |
调用了自写页面请求函数 http
而 flag_server 为全局变量:
1 2 3 4 5 6 7 8 | my_time = 'AAAA' __doc__ = 'http(method,host,port,url,data,headers)' flag_server = '172.17.0.1' key = '744def038f39652db118a68ab34895dc' hosts = open ( 'host.lists' , 'r' ).readlines() user_id = [host.split( ':' )[ 0 ] for host in hosts] hosts = [host.split( ':' )[ 1 ] for host in hosts] port = 80 |
为:
1 | flag_server = '172.17.0.1' |
其靶机IP在host.lists文件中,ssh链接,查看其中一台靶机的IP
可以看到云服务器上靶机的内网IP实际上为 172.18.0.2,所以才会报错超时。
修改 flag_server
修改host.lists文件
重新启动并进入容器:
可以看到现在 check已经正常了,但是host.lists文件是自动生成的,为了避免每次都修改,我们需要修改其自动化生成的脚本
简单寻找了一下,初始化文件在start.py里面
如图,host.lists文件写入的IP根据我们的情况修改为 172.18.0
使用
1 | python stop_clean.py |
命令清理环境重新启动服务,查看是否正常启动
1 2 3 4 5 | python batch.py web_yunnan_simple 3 // 复制3个web_yunnan_simple的靶机,数值可改 python start.py ./ 3 // 启动三个docker靶机和check服务器、flag_server服务器。数值可改 docker attach check_server // 链接裁判机,检查是否正常 python check.py |
现在check裁判机就正常了
此外需要注意的是:
检测页面是否存活是在check.py中的 check类中,对于不同的环境,我们需要编写不同的类方法来进行检测服务是否宕机
该AWD平台另一个问题是可以无限交flag,即一个flag可以无限刷分,详情和修改方法参考:
https://www.cnblogs.com/Triangle-security/p/11332223.html#
个人感觉修改方法不是很优雅hhh,因为需要自己提前去运行该脚本,这段时间有空想想其他的解决办法,脚本如下:
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | #!/usr/bin/env python #coding:UTF-8 import time import os print int (time.time()) Unix_time = int (time.time()) print time.ctime(Unix_time) while True : time_his = [] time_list = [ "00" , "05" , "10" , "15" , "20" , "25" , "30" ] for i in time_list: dt = "2019-04-28 10:" + str (i) + ":00" time_his.append(dt) a = time_his[ 0 ] b = time_his[ 1 ] c = time_his[ 2 ] d = time_his[ 3 ] e = time_his[ 4 ] f = time_his[ 5 ] g = time_his[ 6 ] time_stamp = [a,b,c,d,e,f,g] for k in time_stamp: h = open ( "time.txt" , 'w+' ) timeArray = time.strptime(k, "%Y-%m-%d %H:%M:%S" ) timestamp = time.mktime(timeArray) print ( int (timestamp)) data = ( int (timestamp)) separated = '|' zero = '0' print >>h,(zero),(separated),(data),(separated),(zero),(separated),(data),(separated),(zero),(separated),(zero),(separated),(data),(separated),(zero),(separated),(zero), # 0|data|0|data|0|0|data|0|0 h.close() time.sleep( 300 ) |
另外,计分板在 IP:8080/score.txt中,界面不是很好看
使用夜莫离大佬的界面修改之
https://pan.baidu.com/s/18KlIeluaTtm-kT3KuXHseQ
密码:cvdn
修改过程为:
计分板文件拷贝至awd-platform下的flag_server文件夹下。要注意将文件score.txt与result.txt文件权限调至777,这样才能刷新出分值。
另外部分博客说的是修改 scorecard.php文件,下载上面的百度网盘文件后,发现其文件内容为:
应该是夜莫离后面又将scorecard.php改为了index.php,所以我们修改index.php中的IP地址
想要查看各队得分情况直接访问 IP:8080即可
可以看到因为只有三个队伍,所以这里只有前三个队伍有分数,为0,其余三个队伍是没有分数的,不知道如果开启了超过六个队伍,分数板会变成什么样子。
至此AWD平台安装完成。
该AWD平台题目环境较多,虽然安装的时候问题比较多,但都是能够克服的,尽管有无限刷分的bug,但是瑕不掩瑜,应该是开源AWD平台中最好的一个(很多没有bug的平台,题目环境又太少了)。
自己也想写一个AWD平台hhh,希望能够自带十道以上题目环境,一键部署,同时少量bug不影响正常使用,支持NPC队伍,以及有代码功底的使用者,能够自己快速添加CMS题目环境进来,扩展题目种类。这样就能够方便很多因为各种原因不能进入线下的学校来进行AWD的练习了。
做技术的hack心态加上开放共进的态度是成长和越过高山幽谷的秘籍
以上
参考链接:
https://www.cnblogs.com/Triangle-security/p/11332223.html#
https://www.heibai.org/post/1468.html
https://blog.csdn.net/huanghelouzi/article/details/90204325
__EOF__

本文链接:https://www.cnblogs.com/Cl0ud/p/13662932.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!