zoukankan      html  css  js  c++  java
  • 云服务器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

    现在的速度就很快了:

    花三十秒的时间下载完毕。

    cd awd-platform/

    目录中有AWD线下环境手册文档,但是在搭建的时候还是会有很多不完善的地方,综合网上的多篇博客共同搭建并优化。

    AWD环境中的机器按照功能分为几种类型:

    • Check_Server:

      服务检查服务器,用于判定选手维护的服务是否可用,如果不可用,则会扣除相应的分数,不开启任何端口,需要与flag服务器通信

      简单来说这台机器的作用就是检查靶机宕机没有

    • Flag_Server:

      选手提交flag的服务器,并存储选手的分数,开启80端口

      简单来说这台机器就是获取到flag后的提交对象,用于加分

    • Web_Server:

      选手连接的服务器,选手需要对其进行维护,并尝试攻击其他队伍的机器,通常开启80端口,22端口,并将端口映射到主机。

      这个就是我们每个队伍所要操作的机器。

    比赛逻辑拓补:

    云服务器首先安装docker,有很多师傅写过安装docker的文章,跳过这一步。

    接着下载镜像

    docker pull zhl2008/web_14.04

    接着按照参考文章里面的:

    所以我们将镜像的名字修改:

    docker tag zhl2008/web_14.04 web_14.04

    接着我们按照文档里面来进行操作:

    后面的数字是靶机的数量,也就是参赛队伍的数量,我们先复制所有队伍的比赛文件夹和启动比赛(这里启动的是2个参赛队):

    python batch.py web_yunnan_simple 2
    python start.py ./ 2

    这里使用的靶机是 web_yunnan_simple ,至此,靶机就已经可以访问了,因为是在一个服务器上运行了多个docker,靶机的端口映射规则为:

    1. team1 ---- 8801

    2. team3 ---- 8802

    3. team3 ---- 8803

    4. ....以此类推

    如图:

    各个靶机的ssh密码在目录文件夹下的pass.txt文件中,如图

    其ssh端口映射规则为:

    1. team1 ---- 2201

    2. team2 ---- 2202

    3. team3 ---- 2203

    4. ....以此类推

    但是我们还没有启动 check 脚本,而项目中原来的check脚本是不能用的,我们需要进行一些修改,这个规则要根据自己的环镜自己编写,总体思路就是判断页面是否存在,存在就加一分,不存在就减一分

    网上有修改过后的 check 脚本,同时可以看到 flag-server 和 check-server 所映射的端口

    使用大佬们的check.py脚本

    #!/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服务

    docker attach check_server/

    python check.py

    使用的腾讯云服务器,这一步的时候出错了

    连接超时,查看 check.py 源代码

    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() 函数报错,查看报错行:

    res = http('get',flag_server,8080,'/score.php?key=%s'%key,'',headers)

    调用了自写页面请求函数 http

    而 flag_server 为全局变量:

    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

    为:

    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

     

    使用

    python stop_clean.py

    命令清理环境重新启动服务,查看是否正常启动

    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类中,对于不同的环境,我们需要编写不同的类方法来进行检测服务是否宕机

    这里面只写了index_check函数,有python功底的朋友对于不同的CMS可以进行每个页面的check。

     

    该AWD平台另一个问题是可以无限交flag,即一个flag可以无限刷分,详情和修改方法参考:

    https://www.cnblogs.com/Triangle-security/p/11332223.html#

    个人感觉修改方法不是很优雅hhh,因为需要自己提前去运行该脚本,这段时间有空想想其他的解决办法,脚本如下:

    #!/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

    https://mp.weixin.qq.com/s?__biz=MzU1MzE3Njg2Mw==&mid=2247486325&idx=1&sn=96c04f3609a04260eabdd187fc7c38b1&chksm=fbf79105cc8018131579ad228dbf22a33bbdf0c8c71d3b8c090583b42ea21d80de53fc1efa70&scene=27&key=593393174013ce6d958e86eb764289b105cb7cea44d471bd3f9fe1a2ed76f546343dacb9b40a352e642e425b55c2a4d9698146a114ecd9680ed3262c8f96f6a206f0c78d6818ce0028c9bc75830936f0&ascene=7&uin=NTQ5ODg5NzY1&devicetype=Windows+10&version=6206061c&lang=zh_CN&pass_ticket=s3n8uD0SG7m1vojw%2F%2BN7uxdrTxvWnumzuUe%2BTLY12QY9yFKjU7n%2FNruWi9PS1sJO&winzoom=1

  • 相关阅读:
    LeetCode 252. Meeting Rooms
    LeetCode 161. One Edit Distance
    LeetCode 156. Binary Tree Upside Down
    LeetCode 173. Binary Search Tree Iterator
    LeetCode 285. Inorder Successor in BST
    LeetCode 305. Number of Islands II
    LeetCode 272. Closest Binary Search Tree Value II
    LeetCode 270. Closest Binary Search Tree Value
    LeetCode 329. Longest Increasing Path in a Matrix
    LintCode Subtree
  • 原文地址:https://www.cnblogs.com/Cl0ud/p/13662932.html
Copyright © 2011-2022 走看看