记第一次awd训练

前言

此前从未接触awd,在师傅的建议下,一定要先了解流量监控,文件监控,ssh连接时间比较紧,也就搜了一些相关资料
知识
脚本
大佬的实战
修补思路

AWD简述

每个队伍都拥有一个相同的初始环境 ( 我们称其为 GameBox ),该环境通常运行着一些特定的服务或应用程序,而这些服务通常包含一些安全漏洞。参赛队伍需要挖掘利用对方队伍服务中的安全漏洞,获取 Flag 以获得积分; 同时,参赛队伍也需要修补自身服务漏洞进行防御,以防被其他队伍攻击和获取 Flag。

awd的流量监控

在找不到洞的时候,一个好的流量监控脚本可以帮助自己抄作业,再通过流量补洞
一般aws都是php网站

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$ip = $_SERVER["REMOTE_ADDR"]; //记录访问者的ip
$filename = $_SERVER['PHP_SELF']; //访问者要访问的文件名
$parameter = $_SERVER["QUERY_STRING"]; //访问者要请求的参数
$method = $_SERVER['REQUEST_METHOD']; //请求方法
$uri = $_SERVER['REQUEST_URI']; //请求URI
$time = date('Y-m-d H:i:s',time()); //访问时间
$post = file_get_contents("php://input",'r'); //接收POST数据
$others = '...其他你想得到的信息...';
$logadd = 'Visit Time:'.$time.' '.'Visit IP:'.$ip."\r\n".'RequestURI:'.$uri.' '.$parameter.'RequestMethod:'.$method."\r\n";
// log记录
$fh = fopen("/tmp/log.txt", "a+");
fwrite($fh, $logadd);
fwrite($fh, print_r($_COOKIE, true)."\r\n");
fwrite($fh, $post."\r\n");
fwrite($fh, $others."\r\n");
fclose($fh);
?>

可以把这个脚本部署在入口处,比如

1
2
3
4
5
6
PHPCMS V9 \phpcms\base.php
PHPWIND8.7 \data\sql_config.php
DEDECMS5.7 \data\common.inc.php
DiscuzX2 \config\config_global.php
Wordpress \wp-config.php
Metinfo \include\head.php
1
2
3
sed -i "1s|<?php|<?php\nrequire_once('waf.php');|" /var/www/html/index.php
需要log.txt写入权限
chmod 666 /tmp/log.txt

几个常见框架的必要处
然后也介绍了一个比较好用的命令

1
2
sudo find /var/www/html/ -type f -path "*.php" | xargs sed -i "s/<?php /<?php\nrequire_once('\/var\/www\/html\/waf.php');\n/g"
#意思就是查找需要加waf的目录下所有php文件,在头部添加一句,用require_once函数引入/tmp/waf.php文件。

awd的文件监控

这里直接拉来一个脚本

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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# -*- coding: utf-8 -*-
#use: python file_check.py ./

import os
import hashlib
import shutil
import ntpath
import time

CWD = os.getcwd()
FILE_MD5_DICT = {} # 文件MD5字典
ORIGIN_FILE_LIST = []

# 特殊文件路径字符串
Special_path_str = 'drops_JWI96TY7ZKNMQPDRUOSG0FLH41A3C5EXVB82'
bakstring = 'bak_EAR1IBM0JT9HZ75WU4Y3Q8KLPCX26NDFOGVS'
logstring = 'log_WMY4RVTLAJFB28960SC3KZX7EUP1IHOQN5GD'
webshellstring = 'webshell_WMY4RVTLAJFB28960SC3KZX7EUP1IHOQN5GD'
difffile = 'diff_UMTGPJO17F82K35Z0LEDA6QB9WH4IYRXVSCN'

Special_string = 'diaossama' # 免死金牌
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
except Exception, e:
print u'[!] getmd5_error : ' + getUnicode(filepath)
print getUnicode(e)
try:
ORIGIN_FILE_LIST.remove(filepath)
FILE_MD5_DICT.pop(filepath, None)
except KeyError, e:
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=[]):
# if len(os.listdir(Special_path['bak'])) == 0:
for filepath in filelist:
if Special_path_str not in filepath:
shutil.copy2(filepath, Special_path['bak'])

if __name__ == '__main__':
print u'---------start------------'
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) # TODO 备份文件可能会产生重名BUG
print u'[*] pre work end!'
while True:
file_list = getfilelist(CWD)
# 移除新上传文件
diff_file_list = list(set(file_list) ^ set(ORIGIN_FILE_LIST))
if len(diff_file_list) != 0:
# import pdb;pdb.set_trace()
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 find : ' + getUnicode(filepath)
shutil.move(filepath, os.path.join(Special_path['webshell'], ntpath.basename(filepath) + '.txt'))
except Exception as e:
print u'[!] move webshell error, "%s" maybe is webshell.'%getUnicode(filepath)
try:
f = open(os.path.join(Special_path['log'], 'log.txt'), 'a')
f.write('newfile: ' + getUnicode(filepath) + ' : ' + str(time.ctime()) + '\n')
f.close()
except Exception as e:
print u'[-] log error : file move error: ' + 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'[*] file had be change : ' + getUnicode(filekey)
shutil.move(filekey, os.path.join(Special_path['difffile'], ntpath.basename(filekey) + '.txt'))
shutil.move(os.path.join(Special_path['bak'], ntpath.basename(filekey)), filekey)
except Exception as e:
print u'[!] move webshell error, "%s" maybe is webshell.'%getUnicode(filekey)
try:
f = open(os.path.join(Special_path['log'], 'log.txt'), 'a')
f.write('diff_file: ' + getUnicode(filekey) + ' : ' + getUnicode(time.ctime()) + '\n')
f.close()
except Exception as e:
print u'[-] log error : done_diff: ' + getUnicode(filekey)
pass
time.sleep(2)
# print '[*] ' + getUnicode(time.ctime())

监控文件变化,无免死金牌,无法上传文件(实际没防住,不知道为什么)

awd的ssh连接

1
ssh -i ~/.ssh/id_rsa username@server_ip -p 22

如果没给id_rsa就没有权限连接

实战

前言是师傅介绍的必须知道的东西,至于具体如何加固,这是一个庞大问题,实战来理解

加固

加固分为很多,比如防范弱口令,改密码;也可以是全局find你的flag等等
找到一个WAF脚本waf

1
2
3
4
ssh登录服务器
备份源码
进去改弱口令,数据库等等密码
可以直接部署该脚本,获取ip并设置黑名单;另外设置文件监控py脚本,防止文件上传(暂定)

攻击

改密码&备份

ssh登录之后立即改密码
passwd
立即备份网站到/tmp
tar -cvf web.tar /var/www/html
mv web.tar /tmp
再下载到本地
scp -r username@servername:remote_dir/ /tmp/local_dir #从服务器下载整个目录到本地
scp -r /tmp/local_dir username@servername:remote_dir #从本地上传整个目录到服务器
复原
tar -xvf web.tar -c /var/www/html

备份所有数据库
mysqldump –all -databases > all.sql
导入数据库
mysql –u username –p password database < from.sql

尤其是WEB应用的后台密码修改

passwd username #ssh口令修改
set password for mycms@localhost = password(‘18ciweufhi28746’); #MySQL密码修改
find /var/www//html -path ‘config’ #查找配置文件中的密码凭证

监控文件&监控流量&WAF

文件监控脚本在上面,流量监控
文件监控再加一个python3的脚本
https://github.com/RuoJi6/awd_ruoji_waf/blob/main/%E6%96%87%E4%BB%B6%E7%9B%91%E6%8E%A7/python3wj.py
对于流量监控脚本或者phpwaf脚本,放入入口即可
比如sed -i "1s|<?php|<?php\nrequire_once('/tmp/waf.php');|" /var/www/html/index.php

实际战斗

全程被入到死()
加固时间发现scp传不了文件,赶快去安装了xftp去进行备份源码,再去紧急进行了流量监控,但是脚本好像根本没效果,种种之下都超出了加固时间,再用D盾扫,扫出一堆马,尝试删除发现权限不够,然后去部署文件监控py脚本,但是没什么效果,然后就被人删库了(),重启之后,迅速重新部署全部,不过再没过多久,比赛结束了,至于为什么还能是第五,我也不知道
全程很忙,但好像啥也没做

结语

第一次awd,感觉很迷茫,还是得练啊哎