1. 程式人生 > 實用技巧 >雲伺服器AWD平臺搭建

雲伺服器AWD平臺搭建

開學後實驗室來了幾個新同學,在線上CTF方面大家一直在持續學習,但AWD模式的CTF我們練習並不多,所以準備搭建一個AWD平臺用於實驗室成員的線下賽攻防練習。

最開始的是防災科技大學的線下AWD靶場:

https://github.com/glzjin/20190511_awd_docker

但是靶場沒有計分板和組隊顯示等功能,又找了一下:

https://github.com/zhl2008/awd-platform

騰訊雲伺服器沒有翻牆,從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