Kali中AWD靶机环境搭建
- 1、kali安装docker
- 2、克隆项目(400多M,下载会有点久)
- 3、进入项目
- 4、下载镜像
- 5、改镜像名
- 6、比赛环境搭建
- 6.1 启动靶机
- 6.2 连接裁判机,启动check脚本
- 6.3 关闭环境命令
- 7、 靶机访问方式
- 7.1 web界面访问
- 7.2 ssh访问
- 7.3.提交flag方法
- 7.4.记分牌:查看实时分数情况
- 7.5.查看攻击情况
- 8、 靶机问题修复汇总
- 8.1 check.py问题
- 8.2 flag刷新时间修改
- 8.3 修改score.txt和result.txt权限为777
- 8.4 计分板换一个好看的背景
- 8.5 无限提交flag的bug
- 9、搭建靶机参考资料
1、kali安装docker
详见:https://blog.csdn.net/aodechudawei/article/details/122450720?spm=1001.2014.3001.5506
2、克隆项目(400多M,下载会有点久)
sudo git clone https://github.com/zhl2008/awd-platform.git
3、进入项目
sudo cd awd-platform/
4、下载镜像
sudo docker pull zhl2008/web_14.04
5、改镜像名
sudo docker tag zhl2008/web_14.04 web_14.04
6、比赛环境搭建
以root权限进入/awd-platform目录下,以yunnan_simple镜像为例
6.1 启动靶机
python2 batch.py web_yunnan_simple 3
python2 start.py ./ 3
6.2 连接裁判机,启动check脚本
docker attach check_server
敲一下回车键
python2 check.py
6.3 关闭环境命令
python2 stop_clean.py
7、 靶机访问方式
在虚拟机中执行ip a获取虚拟机ip,这里是192.168.40.129:
7.1 web界面访问
Team1:<虚拟机ip>:8801
Team2:<虚拟机ip>:8802
Team3:<虚拟机ip>:8803
……
7.2 ssh访问
ssh用户密码可见文件awd-platform/pass.txt
Team1:<虚拟机ip>:2201
Team2:<虚拟机ip>:2202
Team3:<虚拟机ip>:2203
……
7.3.提交flag方法
http://<虚拟机ip>:8080/flag_file.php?token=teamX&flag=xxxx
(teamX中的X为自己队伍号,flag为其他队伍的flag)
7.4.记分牌:查看实时分数情况
默认配置下是:
http://<虚拟机ip>:8080/score.txt
参照8.4中配置后是:
http://<虚拟机ip>:8080
7.5.查看攻击情况
http://<虚拟机ip>:8080/result.txt
8、 靶机问题修复汇总
按照默认配置搭建的靶机是有问题的,需要执行以下操作来修复:
8.1 check.py问题
参照:https://blog.csdn.net/weixin_34211761/article/details/92983952
修改awd-platform/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)
8.2 flag刷新时间修改
check时间和flag刷新时间,从2分钟改为5分钟:
/awd-platform/check_server/gen_flag.py 的time_span 变量设置为5*60
/awd-platform/flag_server/config.php 的 min_time_span变量设置为300
/awd-platform/flag.py 变量time_span设置为5*60
8.3 修改score.txt和result.txt权限为777
否则会因为权限问题无法写入文件,从而导致积分无变化
更新后效果:
8.4 计分板换一个好看的背景
资源下载地址如下:
https://pan.baidu.com/s/18KlIeluaTtm-kT3KuXHseQ 密码:cvdn
将计分板文件拷贝至awd-platform下的flag_server文件夹下,执行以下命令解压:
unzip awd计分板.zip
目录结构如下:
还需将index.php文件中的resul变量中的IP地址更改为本机IP
修改后结果如下:
界面效果如下:
8.5 无限提交flag的bug
网上找到的是修改时间来阻止无限提交
修改方法参见:https://www.cnblogs.com/Triangle-security/p/11332223.html
但感觉不太优雅,最好可以启动靶机的时候同时启动对应脚本,不用人来控制脚本启动时间
另外脚本只是针对某一时刻的,还是有些勉强
感觉逻辑也不太对,应该是一支队伍同一个flag只能提交一次,直到出现新的flag才可以继续提交,这样其实也是变相控制五分钟提交一次
基于以上的逻辑,试探性的修改了一下awd-platform/flag_server/flag_file.php代码,初步试验是可行的,这里简单分享一下:
思路其实很简单,就是如果flag提交正确,那么就将对应的队伍和flag值记录到一个文件中,当下一次再提交时,会与文件中的队伍名和flag值做比对,如果已存在对应的记录则报错不加分,否则打印success同时再记录信息到对应文件中,最终的flag_file.php代码如下:
<?php
require 'config.php';
#require 'pass.php';
$now_time = time();
$flag_file = 'xxxxxxxx_flag';
function check_time($attack_uid,$victim_uid){
global $time_file;
global $min_time_span;
global $now_time;
global $team_number;
$old_times = explode('|' , file_get_contents($time_file));
$id = $attack_uid * $team_number + $victim_uid;
if ($now_time - $old_times[$id] < $min_time_span){
die("error: submit too quick ". ($min_time_span + $old_times[$id] - $now_time). " seconds left");
}else{
return True;
}
}
function update_time($attack_uid,$victim_uid){
global $time_file;
global $now_time;
global $team_number;
$old_times = explode('|' , file_get_contents($time_file));
$id = $attack_uid * $team_number + $victim_uid;
$old_times[$id] = $now_time;
$now_times = $old_times;
file_put_contents($time_file,implode('|' , $now_times));
}
function match_flag($flag,$flag_file){
$flags = explode("\n",file_get_contents($flag_file));
foreach ($flags as $real_flag) {
$tmp = explode(":",$real_flag);
$host = $tmp[0];
$real_flag = $tmp[1];
if($flag==$real_flag){
return $host;
}
}
return '';
}
function check_flag($attack_id,$flag){
$flags = explode("\n",file_get_contents('submit_flag.txt'));
foreach ($flags as $sub_flag) {
$tmp = explode(":",$sub_flag);
$attacker = $tmp[0];
$real_flag = $tmp[1];
$submit_status = $tmp[2];
if($flag==$real_flag && $attack_id == $attacker){
return '';
}
}
return $flag;
}
if(isset($_REQUEST['token']) && isset($_REQUEST['flag'])){
$token = $_REQUEST['token'];
$flag = $_REQUEST['flag'];
//$ip = isset($_REQUEST['test_ip'])?$_REQUEST['test_ip']:$_SERVER['REMOTE_ADDR'];
if(!array_key_exists($token , $token_list)){
die('error: no such token');
}
$ip = match_flag($flag,$flag_file);
if(!$ip){
die('error: no such flag');
}
$attack_id = $token_list[$token];
$victim_id = $ip_list[$ip];
if($attack_id === $victim_id){
die('error: do not attack yourself');
}
$flag_validity = check_flag($attack_id,$flag);
if(!$flag_validity){
die('error: The flag has already been submitted');
}
file_put_contents('submit_flag.txt',$attack_id . ':' . $flag . "\n", FILE_APPEND);
for($i=0;$i<$team_number;$i++){
$scores[$i] = 0;
}
$scores[$attack_id] = 2;
$scores[$victim_id] = -2;
check_time($attack_id,$victim_id);
$score = implode('|',$scores);
file_put_contents('result.txt',$user_list[$attack_id] . ' => ' . $user_list[$victim_id]."\n", FILE_APPEND);
$cmd = 'curl "127.0.0.1/score.php?key='.$key.'&write=1&score='.$score.'"';
system($cmd);
update_time($attack_id,$victim_id);
}else {
die("error: empty token or empty target");
}
主要的修改为增加了check_flag()函数和以下的判断代码:
$flag_validity = check_flag($attack_id,$flag);
if(!$flag_validity){
die('error: The flag has already been submitted');
}
file_put_contents('submit_flag.txt',$attack_id . ':' . $flag . "\n", FILE_APPEND);
除替换awd-platform/flag_server/flag_file.php外还需要在awd-platform/flag_server/目录下执行以下操作:
touch submit_flag.txt
chmod 777 submit_flag.txt
最终的效果如下:
team1第一次提交team3的flag,可以成功提交:
第二次提交则报错,且分数不会增加:
team2第一次提交team3的flag,可以成功提交:
第二次提交则报错,且分数不会增加:
9、搭建靶机参考资料
kali安装docker(亲测有效)
AWD平台搭建
搭建CTF-AWD训练平台
线下AWD平台搭建以及一些相关问题解决
一个awd训练平台
云服务器AWD平台搭建