├── .github ├── FUNDING.yml └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── LICENSE ├── README.md ├── detection.py ├── functions.py ├── index.py ├── indicators.py ├── semgrep ├── assert-use.yaml ├── backticks-use.yaml ├── curl-ssl-verifypeer-off.yaml ├── deserialization.yaml ├── detected-generic-api-key.yaml ├── detected-generic-secret.yaml ├── detected-private-key.yaml ├── detected-username-and-password-in-uri.yaml ├── doctrine-dbal-dangerous-query.yaml ├── doctrine-orm-dangerous-query.yaml ├── eval-use.yaml ├── exec-use.yaml ├── extract-use.yaml ├── file-inclusion-oracle.yaml ├── file-inclusion.yaml ├── file-upload.yaml ├── ftp-use.yaml ├── laravel-api-route-sql-injection.yaml ├── laravel-blade-form-missing-csrf.yaml ├── laravel-dangerous-model-construction.yaml ├── laravel-sql-injection.yaml ├── laravel-unsafe-validator.yaml ├── ldap-bind-without-password.yaml ├── mb-ereg-replace-eval.yaml ├── mb-eregi-replace-eval.yaml ├── mcrypt-use.yaml ├── md5-loose-equality.yaml ├── md5-used-as-password.yaml ├── non-literal-header.yaml ├── openssl-cbc-static-iv.yaml ├── openssl-decrypt-validate.yaml ├── php-permissive-cors.yaml ├── php-ssrf.yaml ├── phpinfo-use.yaml ├── preg-replace-eval.yaml ├── source-leak.yaml ├── sqli-query-sink-1.yaml ├── sqli-query-sink-2.yaml ├── symfony-csrf-protection-disabled.yaml ├── symfony-non-literal-redirect.yaml ├── symfony-permissive-cors.yaml ├── tainted-callable.yaml ├── tainted-exec.yaml ├── tainted-filename.yaml ├── tainted-object-instantiation.yaml ├── tainted-session.yaml ├── tainted-sql-string.yaml ├── tainted-url-host.yaml ├── tainted-zip-extract.yaml ├── unlink-use.yaml ├── unserialize-use.yaml ├── weak-crypto.yaml └── xml-load-entity.yaml ├── utils └── export.sh └── vulns ├── assert-use.php ├── assert.php ├── backtick.php ├── backticks-use.php ├── configuration.php ├── cookies.php ├── curl-ssl-verifypeer-off.php ├── deserialization.php ├── doctrine-dbal-dangerous-query.php ├── doctrine-orm-dangerous-query.php ├── eval-use.php ├── exec-use.php ├── exec.php ├── extract.php ├── file-inclusion.php ├── filegetcontents.php ├── ftp-use.php ├── hash.php ├── include.php ├── info.php ├── laravel-api-route-sql-injection.php ├── laravel-blade-form-missing-csrf.blade.php ├── laravel-dangerous-model-construction.php ├── laravel-sql-injection.php ├── laravel-unsafe-validator.php ├── ldap-bind-without-password.php ├── ldap.php ├── mail.php ├── mb-ereg-replace-eval.php ├── mcrypt-use.php ├── md5-loose-equality.php ├── md5-used-as-password.php ├── non-literal-header.php ├── openssl-cbc-static-iv.php ├── openssl-decrypt-validate.php ├── pdo.php ├── pgsqli.php ├── php-permissive-cors.php ├── phpinfo-use.php ├── preg-replace-eval.php ├── preg_replace.php ├── require.php ├── sql-ip.php ├── sqli-req-concat.php ├── sqli.php ├── sqli2.php ├── ssrf.php ├── ssti.php ├── symfony-csrf-protection-disabled.php ├── symfony-non-literal-redirect.php ├── symfony-permissive-cors.php ├── tainted-filename.php ├── tainted-object-instantiation.php ├── tainted-sql-string.php ├── tainted-url-host.php ├── unlink-use.php ├── unserialize-use.php ├── unserialize.php ├── upload.php ├── weak-crypto.php ├── xpath.php ├── xss.php ├── xxe.php ├── xxe2.php ├── zip-extract-2.php └── zip-extract.php /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: swisskyrepo 4 | ko_fi: swissky # Replace with a single Ko-fi username 5 | custom: https://www.buymeacoffee.com/swissky 6 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | name: "CodeQL" 7 | 8 | on: 9 | push: 10 | branches: [master] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [master] 14 | schedule: 15 | - cron: '0 4 * * 3' 16 | 17 | jobs: 18 | analyze: 19 | name: Analyze 20 | runs-on: ubuntu-latest 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | # Override automatic language detection by changing the below list 26 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 27 | language: ['python'] 28 | # Learn more... 29 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 30 | 31 | steps: 32 | - name: Checkout repository 33 | uses: actions/checkout@v2 34 | with: 35 | # We must fetch at least the immediate parents so that if this is 36 | # a pull request then we can checkout the head. 37 | fetch-depth: 2 38 | 39 | # If this run was triggered by a pull request event, then checkout 40 | # the head of the pull request instead of the merge commit. 41 | - run: git checkout HEAD^2 42 | if: ${{ github.event_name == 'pull_request' }} 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v1 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v1 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v1 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | www 3 | Report 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | VulnyCode Public Source License 2 | 3 | The VulnyCode software (henceforth referred to simply as "VulnyCode") is dual-licensed - Copyright 2017 VulnyCode Team. 4 | 5 | Cases that include commercialization of VulnyCode require a commercial, non-free license. Otherwise, VulnyCode can be used without charge under the terms set out below. 6 | 7 | 1. Definitions 8 | 9 | 1.1 “License” means this document. 10 | 1.2 “Contributor” means each individual or legal entity that creates, contributes to the creation of, or owns VulnyCode. 11 | 1.3 “VulnyCode Team” means VulnyCode’s core developers, an updated list of whom can be found within the CREDITS file. 12 | 13 | 2. Commercialization 14 | 15 | A commercial use is one intended for commercial advantage or monetary compensation. 16 | 17 | Example cases of commercialization are: 18 | 19 | - Using VulnyCode to provide commercial managed/Software-as-a-Service services. 20 | - Distributing VulnyCode as a commercial product or as part of one. 21 | - Using VulnyCode as a value added service/product. 22 | 23 | Example cases which do not require a commercial license, and thus fall under the terms set out below, include (but are not limited to): 24 | 25 | - Penetration testers (or penetration testing organizations) using VulnyCode as part of their assessment toolkit. 26 | - Using VulnyCode to test your own systems. 27 | - Any non-commercial use of VulnyCode. 28 | 29 | If you need to purchase a commercial license or are unsure whether you need to purchase a commercial license contact us on twitter @pentest_swissky 30 | 31 | We may grant commercial licenses at no monetary cost at our own discretion if the commercial usage is deemed by the VulnyCode Team to significantly benefit VulnyCode. 32 | 33 | Free-use Terms and Conditions; 34 | 35 | 3. Redistribution 36 | 37 | Redistribution is permitted under the following conditions: 38 | 39 | - Unmodified License is provided with VulnyCode. 40 | - Unmodified Copyright notices are provided with VulnyCode. 41 | - Does not conflict with the commercialization clause. 42 | 43 | 4. Copying 44 | 45 | Copying is permitted so long as it does not conflict with the Redistribution clause. 46 | 47 | 5. Modification 48 | 49 | Modification is permitted so long as it does not conflict with the Redistribution clause. 50 | 51 | 6. Contributions 52 | 53 | Any Contributions assume the Contributor grants the VulnyCode Team the unlimited, non-exclusive right to reuse, modify and relicense the Contributor's content. 54 | 55 | 7. Support 56 | 57 | VulnyCode is provided under an AS-IS basis and without any support, updates or maintenance. Support, updates and maintenance may be given according to the sole discretion of the VulnyCode Team. 58 | 59 | 8. Disclaimer of Warranty 60 | 61 | VulnyCode is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the VulnyCode is free of defects, merchantable, fit for a particular purpose or non-infringing. 62 | 63 | 9. Limitation of Liability 64 | 65 | To the extent permitted under Law, VulnyCode is provided under an AS-IS basis. The VulnyCode Team shall never, and without any limit, be liable for any damage, cost, expense or any other payment incurred as a result of VulnyCode's actions, failure, bugs and/or any other interaction between VulnyCode and end-equipment, computers, other software or any 3rd party, end-equipment, computer or services. 66 | 67 | 10. Disclaimer 68 | 69 | Running VulnyCode against websites source code without prior mutual consent may be illegal in your country. The VulnyCode Team accept no liability and are not responsible for any misuse or damage caused by VulnyCode. 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VulnyCode - PHP Code Static Analysis [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=VulnyCode%20-%20PHP%20Code%20Static%20Analysis&url=https://github.com/swisskyrepo/Vulny-Code-Static-Analysis) - Deprecated 2 | 3 | ![1.0.0](https://img.shields.io/badge/Version-1.0.0%20Beta-RED) ![Python](https://img.shields.io/badge/Python-3.4+-GREEN) ![Platform](https://img.shields.io/badge/Platforms-Linux%20x64-yellowgreen) 4 | 5 | 6 | :warning: **Deprecated**, you should use semgrep rules instead of this script: `semgrep --config=./semgrep/ vulns/*.php` 7 | Most of the semgrep rules provided in this repository are from https://github.com/returntocorp/semgrep-rules 8 | 9 | 10 | Basic script to detect vulnerabilities into a PHP source code, it is using Regular Expression to find sinkholes. 11 | 12 | ```bash 13 | # HELP 14 | ╭─ 👻 swissky@crashlab: ~/Github/PHP_Code_Static_Analysis ‹master*› 15 | ╰─$ python3 index.py 16 | usage: index.py [-h] [--dir DIR] [--plain] 17 | 18 | optional arguments: 19 | -h, --help show this help message and exit 20 | --dir DIR Directory to analyse 21 | --plain No color in output 22 | 23 | # Example 24 | ╭─ 👻 swissky@crashlab: ~/Github/PHP_Code_Static_Analysis ‹master*› 25 | ╰─$ python3 index.py --dir vulns 26 | ------------------------------------------------------------ 27 | Analyzing 'vulns' source code 28 | ------------------------------------------------------------ 29 | Potential vulnerability found : File Inclusion 30 | Line 19 in vulns/include.php 31 | Code : include($_GET['patisserie']) 32 | ------------------------------------------------------------ 33 | Potential vulnerability found : Insecure E-mail 34 | Line 2 in vulns/mail.php 35 | Code : mail($dest, "subject", "message", "", "-f" . $_GET['from']) 36 | Declared at line 1 : $dest = $_GET['who']; 37 | ``` 38 | 39 | Currently detecting : 40 | - Arbitrary Cookie 41 | - Arbitrary File Deletion 42 | - Arbitrary Variable Overwrite 43 | - Cross Site Scripting 44 | - File Inclusion 45 | - File Inclusion / Path Traversal 46 | - File Upload 47 | - Header Injection 48 | - Information Leak 49 | - Insecure E-mail 50 | - Insecure Weak Random 51 | - LDAP Injection 52 | - PHP Object Injection 53 | - Remote Code Execution 54 | - Remote Command Execution 55 | - Server Side Request Forgery 56 | - Server Side Template Injection 57 | - SQL Injection 58 | - URL Redirection 59 | - Weak Cryptographic Hash 60 | - XML external entity 61 | - XPATH Injection 62 | - Hardcoded credentials 63 | - High Entropy string 64 | 65 | > if you want to export each vulnerabilities type into a folder use the "export.sh" 66 | 67 | Don't forget to read the [license](/LICENSE) ;) 68 | 69 | 70 | ## Alternatives 71 | 72 | * [RIPS - A static source code analyser for vulnerabilities in PHP scripts](https://blog.ripstech.com/2016/introducing-the-rips-analysis-engine/) 73 | * [Cobra - Source Code Security Audit](https://github.com/WhaleShark-Team/cobra) 74 | * [PHP parser written in Python using PLY](https://github.com/viraptor/phply) 75 | * [Psalm - A static analysis tool for finding errors in PHP applications](https://psalm.dev/docs/security_analysis/) -------------------------------------------------------------------------------- /detection.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | import os 4 | import re 5 | import math 6 | from indicators import * 7 | from functions import * 8 | 9 | result_count = 0 10 | result_files = 0 11 | 12 | # Compute a Shannon entropy for a string based on an iterator 13 | def shannon_entropy(data, iterator): 14 | """ 15 | Borrowed from http://blog.dkbza.org/2007/05/scanning-data-for-entropy-anomalies.html 16 | """ 17 | if not data: 18 | return 0 19 | entropy = 0 20 | for x in iterator: 21 | p_x = float(data.count(x))/len(data) 22 | if p_x > 0: 23 | entropy += - p_x*math.log(p_x, 2) 24 | return entropy 25 | 26 | 27 | # Analyse the source code of a single page 28 | def analysis(path, plain): 29 | global result_count 30 | global result_files 31 | result_files += 1 32 | with open(path, 'r', encoding='utf-8', errors='replace') as content_file: 33 | 34 | # Clean source for a better detection 35 | content = content_file.read() 36 | content = clean_source_and_format(content) 37 | 38 | # Hardcoded credentials (work as an exception, it's not function based) 39 | credz = ['pass', 'secret', 'token', 'pwd'] 40 | for credential in credz: 41 | content_pure = content.replace(' ', '') 42 | 43 | # detect all variables 44 | regex_var_detect = "\$[\w\s]+\s?=\s?[\"|'].*[\"|']|define\([\"|'].*[\"|']\)" 45 | regex = re.compile(regex_var_detect , re.I) 46 | matches = regex.findall(content_pure) 47 | 48 | # If we find a variable with a constant for a given indicator 49 | for vuln_content in matches: 50 | if credential in vuln_content.lower(): 51 | payload = ["", "Hardcoded Credential", []] 52 | add_vuln_var(payload, plain, path, vuln_content, content, regex_var_detect) 53 | 54 | 55 | # High Entropy String 56 | content_pure = content.replace(' ', '') 57 | regex_var_detect = ".*?=\s?[\"|'].*?[\"|'].*?" 58 | regex = re.compile(regex_var_detect , re.I) 59 | matches = regex.findall(content_pure) 60 | BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" 61 | HEX_CHARS = "1234567890abcdefABCDEF" 62 | 63 | for vuln_content in matches: 64 | payload = ["", "High Entropy String", []] 65 | if shannon_entropy(vuln_content, BASE64_CHARS) >= 4.1 or \ 66 | shannon_entropy(vuln_content, HEX_CHARS) >= 2.5: 67 | add_vuln_var(payload, plain, path, vuln_content, content, regex_var_detect) 68 | 69 | 70 | # Detection of RCE/SQLI/LFI/RFI/RFU/XSS/... 71 | for payload in payloads: 72 | regex = re.compile(payload[0] + regex_indicators) 73 | matches = regex.findall(content.replace(" ", "(PLACEHOLDER")) 74 | 75 | for vuln_content in matches: 76 | 77 | # Handle "require something" vs "require(something)" 78 | # Dirty trick to force a parenthesis before the function's argument 79 | vuln_content = list(vuln_content) 80 | for i in range(len(vuln_content)): 81 | vuln_content[i] = vuln_content[i].replace("(PLACEHOLDER", " ") 82 | vuln_content[i] = vuln_content[i].replace("PLACEHOLDER", "") 83 | 84 | occurence = 0 85 | 86 | # Security hole detected, is it protected ? 87 | if not check_protection(payload[2], vuln_content): 88 | declaration_text, line = "", "" 89 | 90 | # Managing multiple variable in a single line/function 91 | sentence = "".join(vuln_content) 92 | regex = re.compile(regex_indicators[2:-2]) 93 | for vulnerable_var in regex.findall(sentence): 94 | false_positive = False 95 | occurence += 1 96 | 97 | # No declaration for $_GET, $_POST ... 98 | if not check_exception(vulnerable_var[1]): 99 | # Look for the declaration of $something = xxxxx 100 | false_positive, declaration_text, line = check_declaration( 101 | content, 102 | vulnerable_var[1], 103 | path) 104 | 105 | # Set false positive if protection is in the variable's declaration 106 | is_protected = check_protection(payload[2], declaration_text) 107 | false_positive = is_protected if is_protected else false_positive 108 | 109 | # Display all the vuln 110 | line_vuln = find_line_vuln(payload, vuln_content, content) 111 | 112 | # Check for not $dest="constant"; $dest='cste'; $dest=XX; 113 | if "$_" not in vulnerable_var[1]: 114 | if "$" not in declaration_text.replace(vulnerable_var[1], ''): 115 | false_positive = True 116 | 117 | if not false_positive: 118 | result_count = result_count + 1 119 | display(path, payload, vuln_content, line_vuln, declaration_text, line, vulnerable_var[1], occurence, plain) 120 | 121 | 122 | # Run thru every files and subdirectories 123 | def recursive(dir, progress, plain): 124 | progress += 1 125 | progress_indicator = '⬛' 126 | if plain: 127 | progress_indicator = "█" 128 | try: 129 | for name in os.listdir(dir): 130 | 131 | print('\tAnalyzing : ' + progress_indicator * progress + '\r', end="\r"), 132 | 133 | # Targetting only PHP Files 134 | if os.path.isfile(os.path.join(dir, name)): 135 | if ".php" in os.path.join(dir, name): 136 | analysis(dir + "/" + name, plain) 137 | else: 138 | recursive(dir + "/" + name, progress, plain) 139 | 140 | except OSError as e: 141 | print("Error 404 - Not Found, maybe you need more right ?" + " " * 30) 142 | exit(-1) 143 | 144 | 145 | # Display basic informations about the scan 146 | def scanresults(): 147 | global result_count 148 | global result_files 149 | print("Found {} vulnerabilities in {} files".format(result_count, result_files)) 150 | 151 | 152 | 153 | def add_vuln_var(payload, plain, path, vuln_content, page_content, regex_var_detect, occurence=1): 154 | # Get the line of the vulnerability 155 | line_vuln = -1 156 | splitted_content = page_content.split('\n') 157 | for i in range(len(splitted_content)): 158 | regex = re.compile(regex_var_detect, re.I) 159 | matches = regex.findall(splitted_content[i]) 160 | if len(matches) > 0: 161 | line_vuln = i 162 | 163 | # display the result 164 | display( 165 | path, # path 166 | payload, # payload 167 | vuln_content, # vulnerability 168 | line_vuln, # line 169 | vuln_content, # declaration_text 170 | str(line_vuln), # declaration_line 171 | vuln_content, # colored 172 | occurence, # occurence 173 | plain # plain 174 | ) 175 | 176 | # increment the global vulnerability count 177 | global result_count 178 | result_count = result_count + 1 -------------------------------------------------------------------------------- /functions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | import os 4 | import re 5 | 6 | 7 | # Replace the nth occurrence of a string 8 | # Inspired from https://stackoverflow.com/questions/35091557/replace-nth-occurrence-of-substring-in-string 9 | def nth_replace(string, old, new, n): 10 | if string.count(old) >= n: 11 | left_join = old 12 | right_join = old 13 | groups = string.split(old) 14 | nth_split = [left_join.join(groups[:n]), right_join.join(groups[n:])] 15 | return new.join(nth_split) 16 | return string.replace(old, new) 17 | 18 | 19 | # Display the found vulnerability with basic information like the line 20 | def display(path, payload, vulnerability, line, declaration_text, declaration_line, colored, occurrence, plain): 21 | # Potential vulnerability found : SQL Injection 22 | header = "{}Potential vulnerability found : {}{}{}".format('' if plain else '\033[1m', '' if plain else '\033[92m', payload[1], '' if plain else '\033[0m') 23 | 24 | # Line 25 in test/sqli.php 25 | line = "n°{}{}{} in {}".format('' if plain else '\033[92m', line, '' if plain else '\033[0m', path) 26 | 27 | # Code : include($_GET['patisserie']) 28 | vuln = nth_replace("".join(vulnerability), colored, "{}".format('' if plain else '\033[92m') + colored + "{}".format('' if plain else '\033[0m'), occurrence) 29 | vuln = "{}({})".format(payload[0], vuln) 30 | 31 | # Final Display 32 | rows, columns = os.popen('stty size', 'r').read().split() 33 | print("-" * (int(columns) - 1)) 34 | print("Name \t{}".format(header)) 35 | print("-" * (int(columns) - 1)) 36 | print("{}Line {} {}".format('' if plain else '\033[1m', '' if plain else '\033[0m', line)) 37 | print("{}Code {} {}".format('' if plain else '\033[1m', '' if plain else '\033[0m', vuln)) 38 | 39 | # Declared at line 1 : $dest = $_GET['who']; 40 | if "$_" not in colored: 41 | declared = "Undeclared in the file" 42 | if declaration_text != "": 43 | declared = "Line n°{}{}{} : {}".format('' if plain else '\033[0;92m', declaration_line, '' if plain else '\033[0m', declaration_text) 44 | 45 | print("{}Declaration {} {}".format('' if plain else '\033[1m', '' if plain else '\033[0m', declared)) 46 | 47 | # Small delimiter 48 | print("") 49 | 50 | 51 | # Find the line where the vulnerability is located 52 | def find_line_vuln(payload, vulnerability, content): 53 | content = content.split('\n') 54 | for i in range(len(content)): 55 | if payload[0] + '(' + vulnerability[0] + vulnerability[1] + vulnerability[2] + ')' in content[i]: 56 | return str(i - 1) 57 | return "-1" 58 | 59 | 60 | # Find the line where the entry point is declared 61 | # TODO: should be an array of the declaration and modifications 62 | def find_line_declaration(declaration, content): 63 | content = content.split('\n') 64 | for i in range(len(content)): 65 | if declaration in content[i]: 66 | return str(i) 67 | return "-1" 68 | 69 | 70 | # Format the source code in order to improve the detection 71 | def clean_source_and_format(content): 72 | # Clean up - replace tab by space 73 | content = content.replace(" ", " ") 74 | 75 | # Quickfix to detect both echo("something") and echo "something" 76 | content = content.replace("echo ", "echo(") 77 | content = content.replace(";", ");") 78 | return content 79 | 80 | 81 | # Check the line to detect an eventual protection 82 | def check_protection(payload, match): 83 | for protection in payload: 84 | if protection in "".join(match): 85 | return True 86 | return False 87 | 88 | 89 | # Check exception - When it's a function($SOMETHING) Match declaration $SOMETHING = ... 90 | def check_exception(match): 91 | exceptions = ["_GET", "_REQUEST", "_POST", "_COOKIES", "_FILES"] 92 | for exception in exceptions: 93 | if exception in match: 94 | return True 95 | return False 96 | 97 | 98 | # Check declaration 99 | def check_declaration(content, vuln, path): 100 | # Follow and parse include, then add it's content 101 | regex_declaration = re.compile("(include.*?|require.*?)\\([\"\'](.*?)[\"\']\\)") 102 | includes = regex_declaration.findall(content) 103 | 104 | # Path is the path of the current scanned file, we can use it to compute the relative include 105 | for include in includes: 106 | relative_include = os.path.dirname(path) + "/" 107 | try: 108 | path_include = relative_include + include[1] 109 | with open(path_include, 'r') as f: 110 | content = f.read() + content 111 | except Exception as e: 112 | return False, "", "" 113 | 114 | # Extract declaration - for ($something as $somethingelse) 115 | vulnerability = vuln[1:].replace(')', '\\)').replace('(', '\\(') 116 | regex_declaration2 = re.compile("\\$(.*?)([\t ]*)as(?!=)([\t ]*)\\$" + vulnerability) 117 | declaration2 = regex_declaration2.findall(content) 118 | if len(declaration2) > 0: 119 | return check_declaration(content, "$" + declaration2[0][0], path) 120 | 121 | # Extract declaration - $something = $_GET['something'] 122 | regex_declaration = re.compile("\\$" + vulnerability + "([\t ]*)=(?!=)(.*)") 123 | declaration = regex_declaration.findall(content) 124 | if len(declaration) > 0: 125 | 126 | # Check constant then return True if constant because it's false positive 127 | declaration_text = "$" + vulnerability + declaration[0][0] + "=" + declaration[0][1] 128 | line_declaration = find_line_declaration(declaration_text, content) 129 | regex_constant = re.compile("\\$" + vuln[1:] + "([\t ]*)=[\t ]*?([\"\'(]*?[a-zA-Z0-9{}_\\(\\)@\\.,!: ]*?[\"\')]*?);") 130 | false_positive = regex_constant.match(declaration_text) 131 | 132 | if false_positive: 133 | return True, "", "" 134 | return False, declaration_text, line_declaration 135 | 136 | return False, "", "" 137 | -------------------------------------------------------------------------------- /index.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys 5 | import argparse 6 | from detection import * 7 | 8 | if __name__ == "__main__": 9 | 10 | parser = argparse.ArgumentParser() 11 | parser.add_argument('--dir', action='store', dest='dir', help="Directory to analyse") 12 | parser.add_argument('--plain', action='store_true', dest='plain', help="No color in output") 13 | results = parser.parse_args() 14 | 15 | if results.dir is not None: 16 | # default recursion is limited to 1000 17 | # since we browse files recursively, 18 | # we need to set an higher threshold 19 | sys.setrecursionlimit(1000000) 20 | 21 | print(""" (`-') <-. (`-')_ _(`-') (`-') _ 22 | _(OO ) .-> <-. \\( OO) ) .-> _ .-> ( (OO ).-> ( OO).-/ 23 | ,--.(_/,-.\\,--.(,--. ,--. ) ,--./ ,--/ ,--.' ,-.\\-,-----.(`-')----. \\ .'_ (,------. 24 | \\ \\ / (_/| | |(`-') | (`-')| \\ | | (`-')'.' / | .--./( OO).-. ''`'-..__) | .---' 25 | \\ / / | | |(OO ) | |OO )| . '| |)(OO \\ / /_) (`-')( _) | | || | ' |(| '--. 26 | _ \\ /_)| | | | \\(| '__ || |\\ | | / /) || |OO ) \\| |)| || | / : | .--' 27 | \\-'\\ / \\ '-'(_ .' | |'| | \\ | `-/ /` (_' '--'\\ ' '-' '| '-' / | `---. 28 | `-' `-----' `-----' `--' `--' `--' `-----' `-----' `------' `------' 29 | Copyright @pentest_swissky """) 30 | print("\n{}Analyzing '{}' source code{}".format('' if results.plain else '\033[1m', results.dir, '' if results.plain else '\033[0m')) 31 | 32 | if os.path.isfile(results.dir): 33 | analysis(results.dirm, results.plain) 34 | else: 35 | recursive(results.dir, 0, results.plain) 36 | scanresults() 37 | 38 | else: 39 | parser.print_help() 40 | -------------------------------------------------------------------------------- /indicators.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | # /!\ Detection Format (.*)function($vuln)(.*) matched by payload[0]+regex_indicators 5 | regex_indicators = '\\((.*?)(\\$_GET\\[.*?\\]|\\$_FILES\\[.*?\\]|\\$_POST\\[.*?\\]|\\$_REQUEST\\[.*?\\]|\\$_COOKIES\\[.*?\\]|\\$_SESSION\\[.*?\\]|\\$(?!this|e-)[a-zA-Z0-9_]*)(.*?)\\)' 6 | 7 | # Function_Name:String, Vulnerability_Name:String, Protection_Function:Array 8 | payloads = [ 9 | 10 | # Remote Command Execution 11 | ["eval", "Remote Command Execution", ["escapeshellarg", "escapeshellcmd"]], 12 | ["popen", "Remote Command Execution", ["escapeshellarg", "escapeshellcmd"]], 13 | ["popen_ex", "Remote Command Execution", ["escapeshellarg", "escapeshellcmd"]], 14 | ["system", "Remote Command Execution", ["escapeshellarg", "escapeshellcmd"]], 15 | ["passthru", "Remote Command Execution", ["escapeshellarg", "escapeshellcmd"]], 16 | ["exec", "Remote Command Execution", ["escapeshellarg", "escapeshellcmd"]], 17 | ["shell_exec", "Remote Command Execution", ["escapeshellarg", "escapeshellcmd"]], 18 | ["pcntl_exec", "Remote Command Execution", ["escapeshellarg", "escapeshellcmd"]], 19 | ["assert", "Remote Command Execution", ["escapeshellarg", "escapeshellcmd"]], 20 | ["proc_open", "Remote Command Execution", ["escapeshellarg", "escapeshellcmd"]], 21 | ["expect_popen", "Remote Command Execution", ["escapeshellarg", "escapeshellcmd"]], 22 | ["create_function", "Remote Command Execution", ["escapeshellarg", "escapeshellcmd"]], 23 | ["call_user_func", "Remote Code Execution", []], 24 | ["call_user_func_array", "Remote Code Execution", []], 25 | ["preg_replace", "Remote Command Execution", ["preg_quote"]], 26 | ["ereg_replace", "Remote Command Execution", ["preg_quote"]], 27 | ["eregi_replace", "Remote Command Execution", ["preg_quote"]], 28 | ["mb_ereg_replace", "Remote Command Execution", ["preg_quote"]], 29 | ["mb_eregi_replace", "Remote Command Execution", ["preg_quote"]], 30 | 31 | # File Inclusion / Path Traversal 32 | ["virtual", "File Inclusion", []], 33 | ["include", "File Inclusion", []], 34 | ["require", "File Inclusion", []], 35 | ["include_once", "File Inclusion", []], 36 | ["require_once", "File Inclusion", []], 37 | 38 | ["readfile", "File Inclusion / Path Traversal", []], 39 | ["file_get_contents", "File Inclusion / Path Traversal", []], 40 | ["file_put_contents", "File Inclusion / Path Traversal", []], 41 | ["show_source", "File Inclusion / Path Traversal", []], 42 | ["fopen", "File Inclusion / Path Traversal", []], 43 | ["file", "File Inclusion / Path Traversal", []], 44 | ["fpassthru", "File Inclusion / Path Traversal", []], 45 | ["gzopen", "File Inclusion / Path Traversal", []], 46 | ["gzfile", "File Inclusion / Path Traversal", []], 47 | ["gzpassthru", "File Inclusion / Path Traversal", []], 48 | ["readgzfile", "File Inclusion / Path Traversal", []], 49 | 50 | ["DirectoryIterator", "File Inclusion / Path Traversal", []], 51 | ["stream_get_contents", "File Inclusion / Path Traversal", []], 52 | ["copy", "File Inclusion / Path Traversal", []], 53 | 54 | # MySQL(i) SQL Injection 55 | ["mysql_query", "SQL Injection", ["mysql_real_escape_string"]], 56 | ["mysqli_multi_query", "SQL Injection", ["mysql_real_escape_string"]], 57 | ["mysqli_send_query", "SQL Injection", ["mysql_real_escape_string"]], 58 | ["mysqli_master_query", "SQL Injection", ["mysql_real_escape_string"]], 59 | ["mysqli_master_query", "SQL Injection", ["mysql_real_escape_string"]], 60 | ["mysql_unbuffered_query", "SQL Injection", ["mysql_real_escape_string"]], 61 | ["mysql_db_query", "SQL Injection", ["mysql_real_escape_string"]], 62 | ["mysqli::real_query", "SQL Injection", ["mysql_real_escape_string"]], 63 | ["mysqli_real_query", "SQL Injection", ["mysql_real_escape_string"]], 64 | ["mysqli::query", "SQL Injection", ["mysql_real_escape_string"]], 65 | ["mysqli_query", "SQL Injection", ["mysql_real_escape_string"]], 66 | 67 | # PostgreSQL Injection 68 | ["pg_query", "SQL Injection", ["pg_escape_string", "pg_pconnect", "pg_connect"]], 69 | ["pg_send_query", "SQL Injection", ["pg_escape_string", "pg_pconnect", "pg_connect"]], 70 | 71 | # SQLite SQL Injection 72 | ["sqlite_array_query", "SQL Injection", ["sqlite_escape_string"]], 73 | ["sqlite_exec", "SQL Injection", ["sqlite_escape_string"]], 74 | ["sqlite_query", "SQL Injection", ["sqlite_escape_string"]], 75 | ["sqlite_single_query", "SQL Injection", ["sqlite_escape_string"]], 76 | ["sqlite_unbuffered_query", "SQL Injection", ["sqlite_escape_string"]], 77 | 78 | # PDO SQL Injection 79 | ["->arrayQuery", "SQL Injection", ["->prepare"]], 80 | ["->query", "SQL Injection", ["->prepare"]], 81 | ["->queryExec", "SQL Injection", ["->prepare"]], 82 | ["->singleQuery", "SQL Injection", ["->prepare"]], 83 | ["->querySingle", "SQL Injection", ["->prepare"]], 84 | ["->exec", "SQL Injection", ["->prepare"]], 85 | ["->execute", "SQL Injection", ["->prepare"]], 86 | ["->unbufferedQuery", "SQL Injection", ["->prepare"]], 87 | ["->real_query", "SQL Injection", ["->prepare"]], 88 | ["->multi_query", "SQL Injection", ["->prepare"]], 89 | ["->send_query", "SQL Injection", ["->prepare"]], 90 | 91 | # Cubrid SQL Injection 92 | ["cubrid_unbuffered_query", "SQL Injection", ["cubrid_real_escape_string"]], 93 | ["cubrid_query", "SQL Injection", ["cubrid_real_escape_string"]], 94 | 95 | # MSSQL SQL Injection : Warning there is not any real_escape_string 96 | ["mssql_query", "SQL Injection", ["mssql_escape"]], 97 | 98 | # File Upload 99 | ["move_uploaded_file", "File Upload", []], 100 | 101 | # Cross Site Scripting 102 | ["echo", "Cross Site Scripting", ["htmlentities", "htmlspecialchars"]], 103 | ["print", "Cross Site Scripting", ["htmlentities", "htmlspecialchars"]], 104 | ["printf", "Cross Site Scripting", ["htmlentities", "htmlspecialchars"]], 105 | ["vprintf", "Cross Site Scripting", ["htmlentities", "htmlspecialchars"]], 106 | ["trigger_error", "Cross Site Scripting", ["htmlentities", "htmlspecialchars"]], 107 | ["user_error", "Cross Site Scripting", ["htmlentities", "htmlspecialchars"]], 108 | ["odbc_result_all", "Cross Site Scripting", ["htmlentities", "htmlspecialchars"]], 109 | ["ifx_htmltbl_result", "Cross Site Scripting", ["htmlentities", "htmlspecialchars"]], 110 | ["die", "Cross Site Scripting", ["htmlentities", "htmlspecialchars"]], 111 | ["exit", "Cross Site Scripting", ["htmlentities", "htmlspecialchars"]], 112 | ["var_dump", "Cross Site Scripting", ["htmlentities", "htmlspecialchars"]], 113 | 114 | # XPATH and LDAP 115 | ["xpath", "XPATH Injection", []], 116 | ["ldap_search", "LDAP Injection", ["Zend_Ldap", "ldap_escape"]], 117 | 118 | # Insecure E-Mail 119 | ["mail", "Insecure E-mail", []], 120 | 121 | # PHP Objet Injection 122 | ["unserialize", "PHP Object Injection", []], 123 | 124 | # Header Injection 125 | ["header", "Header Injection", []], 126 | ["HttpMessage::setHeaders", "Header Injection", []], 127 | ["HttpRequest::setHeaders", "Header Injection", []], 128 | 129 | # URL Redirection 130 | ["http_redirect", "URL Redirection", []], 131 | ["HttpMessage::setResponseCode", "URL Redirection", []], 132 | 133 | # Server Side Template Injection 134 | ["->render", "Server Side Template Injection", []], 135 | ["->assign", "Server Side Template Injection", []], 136 | 137 | # Weak Cryptographic Hash 138 | ["md5", "Weak Cryptographic Hash", []], 139 | ["sha1", "Weak Cryptographic Hash", []], 140 | 141 | # Insecure Weak Random 142 | ["mt_rand", "Insecure Weak Random", []], 143 | ["srand", "Insecure Weak Random", []], 144 | ["uniqid", "Insecure Weak Random", []], 145 | 146 | # Information Leak 147 | ["phpinfo", "Information Leak", []], 148 | ["debug_print_backtrace", "Information Leak", []], 149 | ["show_source", "Information Leak", []], 150 | ["highlight_file", "Information Leak", []], 151 | 152 | # Server Side Request Forgery 153 | ["curl_setopt", "Server Side Request Forgery", []], 154 | ["curl_exec", "Server Side Request Forgery", []], 155 | ["fsockopen", "Server Side Request Forgery", []], 156 | 157 | 158 | # XML External Entity 159 | ["SimpleXMLElement", "XML External Entity", []], 160 | ["xmlparse", "XML External Entity", []], 161 | ["loadXML", "XML External Entity", []], 162 | ["simplexml_load_string", "XML External Entity", []], 163 | 164 | # Others 165 | ["unlink", "Arbitrary File Deletion", []], 166 | ["extract", "Arbitrary Variable Overwrite", []], 167 | ["setcookie", "Arbitrary Cookie", []], 168 | ["chmod", "Arbitrary File Permission", []], 169 | ["mkdir", "Arbitrary Folder Creation", []], 170 | 171 | ] 172 | -------------------------------------------------------------------------------- /semgrep/assert-use.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: assert-use 3 | patterns: 4 | - pattern: assert($ASSERT, ...); 5 | # - pattern-not: assert(<... $ASSERT ...>, ...); - https://github.com/returntocorp/semgrep/issues/2035 6 | - pattern-not: assert("...", ...); 7 | message: >- 8 | Calling assert with user input is equivalent to eval'ing. 9 | metadata: 10 | references: 11 | - https://www.php.net/manual/en/function.assert 12 | - https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/AssertsSniff.php 13 | category: security 14 | technology: 15 | - php 16 | languages: [php] 17 | severity: ERROR 18 | -------------------------------------------------------------------------------- /semgrep/backticks-use.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: backticks-use 3 | pattern: "`...`;" 4 | message: >- 5 | Backticks use may lead to command injection vulnerabilities. 6 | metadata: 7 | references: 8 | - https://www.php.net/manual/en/language.operators.execution.php 9 | - https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/BackticksSniff.php 10 | category: security 11 | technology: 12 | - php 13 | languages: [php] 14 | severity: ERROR 15 | -------------------------------------------------------------------------------- /semgrep/curl-ssl-verifypeer-off.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: curl-ssl-verifypeer-off 3 | patterns: 4 | - pattern-either: 5 | - pattern: | 6 | $ARG = $IS_VERIFIED; 7 | ... 8 | curl_setopt(..., CURLOPT_SSL_VERIFYPEER, $ARG); 9 | - pattern: curl_setopt(..., CURLOPT_SSL_VERIFYPEER, $IS_VERIFIED) 10 | - metavariable-regex: 11 | metavariable: $IS_VERIFIED 12 | regex: 0|false|null 13 | message: >- 14 | SSL verification is disabled but should not be (currently CURLOPT_SSL_VERIFYPEER= 15 | $IS_VERIFIED) 16 | metadata: 17 | references: 18 | - https://www.saotn.org/dont-turn-off-curlopt_ssl_verifypeer-fix-php-configuration/ 19 | category: security 20 | technology: 21 | - php 22 | languages: [php] 23 | severity: ERROR 24 | -------------------------------------------------------------------------------- /semgrep/deserialization.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: extract-user-data 3 | mode: taint 4 | pattern-sources: 5 | - pattern-either: 6 | - pattern: $_GET[...] 7 | - pattern: $_FILES[...] 8 | - pattern: $_POST[...] 9 | - pattern: $_FILE[...] 10 | - pattern: $params[...] # Captures user-controlled `$params` 11 | - pattern: $request->getParam(...) # Captures user-controlled request parameters 12 | - pattern: $request->input(...) # Alternative for Laravel-style requests 13 | pattern-sinks: 14 | - pattern: extract(...) 15 | pattern-sanitizers: 16 | - pattern: extract($VAR, EXTR_SKIP,...) 17 | message: Do not call 'extract()' on user-controllable data. If you must, then you 18 | must also provide the EXTR_SKIP flag to prevent overwriting existing variables. 19 | languages: 20 | - php 21 | metadata: 22 | license: MIT 23 | category: security 24 | cwe: 'CWE-502: Deserialization of Untrusted Data' 25 | owasp: 26 | - A08:2021 - Software and Data Integrity Failures 27 | - A08:2017 - Insecure Deserialization 28 | technology: 29 | - php 30 | references: 31 | - https://www.php.net/manual/en/function.extract.php#refsect1-function.extract-notes 32 | severity: ERROR 33 | -------------------------------------------------------------------------------- /semgrep/detected-generic-api-key.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: detected-generic-api-key 3 | pattern-regex: |- 4 | [aA][pP][iI]_?[kK][eE][yY].*['|"]?[0-9a-zA-Z]{32,45}['|"]? 5 | languages: [regex] 6 | message: Generic API Key detected 7 | severity: ERROR 8 | metadata: 9 | source-rule-url: https://github.com/dxa4481/truffleHogRegexes/blob/master/truffleHogRegexes/regexes.json 10 | category: security 11 | technology: 12 | - secrets 13 | confidence: MEDIUM 14 | -------------------------------------------------------------------------------- /semgrep/detected-generic-secret.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: detected-generic-secret 3 | pattern-regex: |- 4 | [sS][eE][cC][rR][eE][tT][:= \t]*['|\"]?[0-9a-zA-Z]{32,45}['|\"]? 5 | languages: [regex] 6 | message: Generic Secret detected 7 | severity: ERROR 8 | metadata: 9 | source-rule-url: https://github.com/dxa4481/truffleHogRegexes/blob/master/truffleHogRegexes/regexes.json 10 | category: security 11 | technology: 12 | - secrets 13 | confidence: MEDIUM 14 | -------------------------------------------------------------------------------- /semgrep/detected-private-key.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: detected-private-key 3 | patterns: 4 | - pattern-either: 5 | - patterns: 6 | - pattern: 7 | -----BEGIN $TYPE PRIVATE KEY----- 8 | $KEY 9 | - metavariable-regex: 10 | metavariable: $TYPE 11 | regex: (?i)([dr]sa|ec|openssh|encrypted)? 12 | - patterns: 13 | - pattern: | 14 | -----BEGIN PRIVATE KEY----- 15 | $KEY 16 | - metavariable-analysis: 17 | metavariable: $KEY 18 | analyzer: entropy 19 | languages: [generic] 20 | message: Private Key detected. This is a sensitive credential and should not be hardcoded here. Instead, store this in a separate, private file. 21 | severity: ERROR 22 | metadata: 23 | source-rule-url: https://github.com/grab/secret-scanner/blob/master/scanner/signatures/pattern.go 24 | category: security 25 | technology: 26 | - secrets 27 | confidence: MEDIUM 28 | -------------------------------------------------------------------------------- /semgrep/detected-username-and-password-in-uri.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: detected-username-and-password-in-uri 3 | patterns: 4 | - pattern-regex: ([\w+]{1,24})(://)([^$<]{1})([^\s";]{1,}):(?![\x{2022}*]+?@)([^$<\{]{1})([^\s";]{1,})@[-a-zA-Z0-9@:%._\+~#=]{1,256}[a-zA-Z0-9()]{1,24}([^\s]+) 5 | languages: 6 | - regex 7 | message: Username and password in URI detected 8 | severity: ERROR 9 | metadata: 10 | source-rule-url: https://github.com/grab/secret-scanner/blob/master/scanner/signatures/pattern.go 11 | category: security 12 | technology: 13 | - secrets 14 | confidence: MEDIUM 15 | license: Commons Clause License Condition v1.0[LGPL-2.1-only] 16 | -------------------------------------------------------------------------------- /semgrep/doctrine-dbal-dangerous-query.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: doctrine-dbal-dangerous-query 3 | languages: 4 | - php 5 | message: 6 | Detected string concatenation with a non-literal variable in a Doctrine DBAL query method. This could lead to SQL 7 | injection if the variable is user-controlled and not properly sanitized. In order to prevent SQL injection, used parameterized 8 | queries or prepared statements instead. 9 | metadata: 10 | category: security 11 | cwe: "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')" 12 | license: Commons Clause License Condition v1.0[LGPL-2.1-only] 13 | owasp: "A1: Injection" 14 | references: 15 | - https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/security.html 16 | - https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html 17 | technology: 18 | - doctrine 19 | patterns: 20 | - pattern-either: 21 | - pattern: $CONNECTION->prepare($QUERY,...) 22 | - pattern: $CONNECTION->createQuery($QUERY,...) 23 | - pattern: $CONNECTION->executeQuery($QUERY,...) 24 | - pattern-either: 25 | - pattern-inside: | 26 | use Doctrine\DBAL\Connection; 27 | ... 28 | - pattern-inside: | 29 | $CONNECTION = $SMTH->getConnection(...); 30 | ... 31 | - pattern-not: $CONNECTION->prepare("...",...) 32 | - pattern-not: $CONNECTION->createQuery("...",...) 33 | - pattern-not: $CONNECTION->executeQuery("...",...) 34 | severity: WARNING 35 | -------------------------------------------------------------------------------- /semgrep/doctrine-orm-dangerous-query.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: doctrine-orm-dangerous-query 3 | languages: 4 | - php 5 | message: >- 6 | `$QUERY` Detected string concatenation with a non-literal variable in a Doctrine 7 | QueryBuilder method. This could lead to SQL injection if the variable is 8 | user-controlled and not properly sanitized. In order to prevent SQL 9 | injection, used parameterized queries or prepared statements instead. 10 | metadata: 11 | category: security 12 | cwe: "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')" 13 | license: Commons Clause License Condition v1.0[LGPL-2.1-only] 14 | owasp: "A1: Injection" 15 | references: 16 | - https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/query-builder.html#security-safely-preventing-sql-injection 17 | - https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html 18 | technology: 19 | - doctrine 20 | mode: taint 21 | pattern-sinks: 22 | - patterns: 23 | - pattern: $SINK 24 | - pattern-either: 25 | - pattern-inside: $QUERY->add(...,$SINK,...) 26 | - pattern-inside: $QUERY->select(...,$SINK,...) 27 | - pattern-inside: $QUERY->addSelect(...,$SINK,...) 28 | - pattern-inside: $QUERY->delete(...,$SINK,...) 29 | - pattern-inside: $QUERY->update(...,$SINK,...) 30 | - pattern-inside: $QUERY->insert(...,$SINK,...) 31 | - pattern-inside: $QUERY->from(...,$SINK,...) 32 | - pattern-inside: $QUERY->join(...,$SINK,...) 33 | - pattern-inside: $QUERY->innerJoin(...,$SINK,...) 34 | - pattern-inside: $QUERY->leftJoin(...,$SINK,...) 35 | - pattern-inside: $QUERY->rightJoin(...,$SINK,...) 36 | - pattern-inside: $QUERY->where(...,$SINK,...) 37 | - pattern-inside: $QUERY->andWhere(...,$SINK,...) 38 | - pattern-inside: $QUERY->orWhere(...,$SINK,...) 39 | - pattern-inside: $QUERY->groupBy(...,$SINK,...) 40 | - pattern-inside: $QUERY->addGroupBy(...,$SINK,...) 41 | - pattern-inside: $QUERY->having(...,$SINK,...) 42 | - pattern-inside: $QUERY->andHaving(...,$SINK,...) 43 | - pattern-inside: $QUERY->orHaving(...,$SINK,...) 44 | - pattern-inside: $QUERY->orderBy(...,$SINK,...) 45 | - pattern-inside: $QUERY->addOrderBy(...,$SINK,...) 46 | - pattern-inside: $QUERY->set($SINK,...) 47 | - pattern-inside: $QUERY->setValue($SINK,...) 48 | - pattern-either: 49 | - pattern-inside: | 50 | $Q = $X->createQueryBuilder(); 51 | ... 52 | - pattern-inside: | 53 | $Q = new QueryBuilder(...); 54 | ... 55 | pattern-sources: 56 | - patterns: 57 | - pattern-either: 58 | - pattern: sprintf(...) 59 | - pattern: | 60 | "...".$SMTH 61 | severity: WARNING 62 | -------------------------------------------------------------------------------- /semgrep/eval-use.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: eval-use 3 | patterns: 4 | - pattern: eval(...); 5 | - pattern-not: eval('...'); 6 | message: >- 7 | Evaluating non-constant commands. This can lead to command injection. 8 | metadata: 9 | cwe: 10 | - "CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')" 11 | references: 12 | - https://www.php.net/manual/en/function.eval 13 | - https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/NoEvalsSniff.php 14 | category: security 15 | technology: 16 | - php 17 | owasp: 18 | - A01:2017 - Injection 19 | - A03:2021 - Injection 20 | cwe2022-top25: true 21 | cwe2021-top25: true 22 | subcategory: 23 | - audit 24 | likelihood: LOW 25 | impact: HIGH 26 | confidence: LOW 27 | languages: [php] 28 | severity: ERROR -------------------------------------------------------------------------------- /semgrep/exec-use.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: exec-use 3 | patterns: 4 | - pattern: $FUNC(...); 5 | - pattern-not: $FUNC('...', ...); 6 | - metavariable-regex: 7 | metavariable: $FUNC 8 | regex: exec|passthru|proc_open|popen|shell_exec|system|pcntl_exec|expect_popen 9 | message: >- 10 | Executing non-constant commands. This can lead to command injection. 11 | metadata: 12 | cwe: 13 | - "CWE-94: Improper Control of Generation of Code ('Code Injection')" 14 | references: 15 | - https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/SystemExecFunctionsSniff.php 16 | category: security 17 | technology: 18 | - php 19 | owasp: 20 | - A03:2021 - Injection 21 | cwe2022-top25: true 22 | subcategory: 23 | - audit 24 | likelihood: LOW 25 | impact: HIGH 26 | confidence: LOW 27 | languages: [php] 28 | severity: ERROR 29 | -------------------------------------------------------------------------------- /semgrep/extract-use.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: extract-use 3 | patterns: 4 | - pattern: extract(...); 5 | message: >- 6 | Import variables into the current symbol table from an array 7 | metadata: 8 | references: 9 | - https://www.php.net/manual/en/function.extract.php 10 | category: security 11 | technology: 12 | - php 13 | languages: [php] 14 | severity: WARNING -------------------------------------------------------------------------------- /semgrep/file-inclusion-oracle.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: file-inclusion-oracle 3 | message: >- 4 | Detected error based oracle file inclusion. 5 | metadata: 6 | cwe: 7 | - "CWE-98: Improper Control of Filename for Include/Require Statement in PHP Program ('PHP Remote\ 8 | \ File Inclusion')" 9 | references: 10 | - https://www.ambionics.io/blog/lightyear-file-dump 11 | - https://www.synacktiv.com/en/publications/php-filter-chains-file-read-from-error-based-oracle 12 | - https://github.com/DownUnderCTF/Challenges_2022_Public/blob/main/web/minimal-php/solve/solution.py 13 | category: security 14 | technology: 15 | - php 16 | owasp: 17 | - A03:2021 - Injection 18 | subcategory: 19 | - audit 20 | likelihood: LOW 21 | impact: MEDIUM 22 | confidence: LOW 23 | languages: [php] 24 | severity: ERROR 25 | mode: taint 26 | pattern-sources: 27 | - patterns: 28 | - pattern-either: 29 | - pattern: $_GET 30 | - pattern: $_POST 31 | - pattern: $_COOKIE 32 | - pattern: $_REQUEST 33 | - pattern: $_SERVER 34 | - pattern: $_FILE[...] 35 | - pattern: $params[...] # Captures user-controlled `$params` 36 | - pattern: $request->getParam(...) # Captures user-controlled request parameters 37 | - pattern: $request->input(...) # Alternative for Laravel-style requests 38 | pattern-sanitizers: 39 | - patterns: 40 | - pattern-either: 41 | - pattern-inside: basename($PATH, ...) 42 | - pattern-inside: linkinfo($PATH, ...) 43 | - pattern-inside: readlink($PATH, ...) 44 | - pattern-inside: realpath($PATH, ...) 45 | - pattern-inside: include_safe(...) 46 | - pattern-inside: file_exists(...) 47 | - pattern-inside: is_file(...) 48 | pattern-sinks: 49 | - patterns: 50 | - pattern-inside: $FUNC(...); 51 | - pattern: $VAR 52 | - metavariable-regex: 53 | metavariable: $FUNC 54 | regex: \b(file_get_contents|readfile|getimagesize|md5_file|sha1_file|hash_file|file|parse_ini_file|copy|stream_get_contents)\b -------------------------------------------------------------------------------- /semgrep/file-inclusion.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: file-inclusion 3 | message: >- 4 | Detected non-constant file inclusion. This can lead to local file inclusion (LFI) or remote file inclusion 5 | (RFI) if user input reaches this statement. LFI and RFI could lead to sensitive files being obtained 6 | by attackers. Instead, explicitly specify what to include. If that is not a viable solution, validate 7 | user input thoroughly. 8 | metadata: 9 | cwe: 10 | - "CWE-98: Improper Control of Filename for Include/Require Statement in PHP Program ('PHP Remote\ 11 | \ File Inclusion')" 12 | references: 13 | - https://www.php.net/manual/en/function.include.php 14 | - https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/EasyRFISniff.php 15 | - https://en.wikipedia.org/wiki/File_inclusion_vulnerability#Types_of_Inclusion 16 | category: security 17 | technology: 18 | - php 19 | owasp: 20 | - A03:2021 - Injection 21 | subcategory: 22 | - audit 23 | likelihood: LOW 24 | impact: MEDIUM 25 | confidence: LOW 26 | languages: [php] 27 | severity: ERROR 28 | mode: taint 29 | pattern-sources: 30 | - patterns: 31 | - pattern-either: 32 | - pattern: $_GET 33 | - pattern: $_POST 34 | - pattern: $_COOKIE 35 | - pattern: $_REQUEST 36 | - pattern: $_SERVER 37 | - pattern: $_FILE[...] 38 | - pattern: $params[...] # Captures user-controlled `$params` 39 | - pattern: $request->getParam(...) # Captures user-controlled request parameters 40 | - pattern: $request->input(...) # Alternative for Laravel-style requests 41 | pattern-sanitizers: 42 | - patterns: 43 | - pattern-either: 44 | - pattern-inside: basename($PATH, ...) 45 | - pattern-inside: linkinfo($PATH, ...) 46 | - pattern-inside: readlink($PATH, ...) 47 | - pattern-inside: realpath($PATH, ...) 48 | - pattern-inside: include_safe(...) 49 | pattern-sinks: 50 | - patterns: 51 | - pattern-inside: $FUNC(...); 52 | - pattern: $VAR 53 | - metavariable-regex: 54 | metavariable: $FUNC 55 | regex: \b(include|include_once|require|require_once)\b -------------------------------------------------------------------------------- /semgrep/file-upload.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: file-upload-use 3 | patterns: 4 | - pattern: move_uploaded_file(...,...) 5 | message: >- 6 | Moves an uploaded file to a new location. This can lead to command injection. 7 | metadata: 8 | references: 9 | - https://www.php.net/manual/en/function.move-uploaded-file 10 | category: security 11 | technology: 12 | - php 13 | languages: [php] 14 | severity: ERROR -------------------------------------------------------------------------------- /semgrep/ftp-use.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: ftp-use 3 | patterns: 4 | - pattern: $FUNC(...); 5 | - metavariable-regex: 6 | metavariable: $FUNC 7 | regex: ftp_.+ 8 | message: >- 9 | FTP allows for unencrypted file transfers. Consider using an encrypted alternative. 10 | metadata: 11 | references: 12 | - https://www.php.net/manual/en/intro.ftp.php 13 | - https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/FringeFunctionsSniff.php 14 | category: security 15 | technology: 16 | - php 17 | languages: [php] 18 | severity: ERROR 19 | -------------------------------------------------------------------------------- /semgrep/laravel-api-route-sql-injection.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: laravel-api-route-sql-injection 3 | mode: taint 4 | pattern-sources: 5 | - patterns: 6 | - pattern: $ARG 7 | - pattern-inside: | 8 | Route::$METHOD($ROUTE_NAME, function(...,$ARG,...){...}) 9 | pattern-sanitizers: 10 | - patterns: 11 | - pattern: | 12 | DB::raw("...",[...]) 13 | pattern-sinks: 14 | - patterns: 15 | - pattern: | 16 | DB::raw(...) 17 | message: HTTP method [$METHOD] to Laravel route $ROUTE_NAME is vulnerable to SQL 18 | injection via string concatentation or unsafe interpolation. 19 | languages: 20 | - php 21 | severity: WARNING 22 | metadata: 23 | category: security 24 | cwe: 'CWE-89: Improper Neutralization of Special Elements used in an SQL Command 25 | (''SQL Injection'')' 26 | owasp: 27 | - A01:2017 - Injection 28 | - A03:2021 - Injection 29 | references: 30 | - https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Laravel_Cheat_Sheet.md 31 | technology: 32 | - php 33 | - laravel 34 | -------------------------------------------------------------------------------- /semgrep/laravel-blade-form-missing-csrf.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: laravel-blade-form-missing-csrf 3 | patterns: 4 | - pattern: | 5 |
...
6 | - pattern-not: | 7 |
8 | @csrf 9 | ... 10 |
11 | message: Found a Blade form POST definition without the `@csrf` decorator. State-changing 12 | operations using simple HTTP content types should include an antiforgery token. 13 | languages: 14 | - generic 15 | severity: ERROR 16 | paths: 17 | include: 18 | - '*.blade.php' 19 | metadata: 20 | technology: 21 | - php 22 | - laravel 23 | - blade 24 | category: security 25 | cwe: 'CWE-352: Cross-Site Request Forgery (CSRF)' 26 | references: 27 | - https://laravel.com/docs/9.x/blade#csrf-field 28 | -------------------------------------------------------------------------------- /semgrep/laravel-dangerous-model-construction.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: laravel-dangerous-model-construction 3 | patterns: 4 | - pattern: | 5 | $guarded = []; 6 | - pattern-inside: | 7 | class $CLASS extends Model { 8 | ... 9 | } 10 | message: Setting `$guarded` to an empty array allows mass assignment to every property 11 | in a Laravel model. This explicitly overrides Eloquent's safe-by-default mass 12 | assignment protections. 13 | languages: 14 | - php 15 | metadata: 16 | category: security 17 | technology: 18 | - php 19 | - laravel 20 | - eloquent 21 | references: 22 | - https://laravel.com/docs/9.x/eloquent#allowing-mass-assignment 23 | - https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Laravel_Cheat_Sheet.md 24 | cwe: 'CWE-915: Improperly Controlled Modification of Dynamically-Determined Object 25 | Attributes' 26 | severity: ERROR 27 | -------------------------------------------------------------------------------- /semgrep/laravel-sql-injection.yaml: -------------------------------------------------------------------------------- 1 | 2 | rules: 3 | - id: laravel-sql-injection 4 | metadata: 5 | owasp: 'A3: Injection' 6 | cwe: "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')" 7 | category: security 8 | technology: 9 | - laravel 10 | references: 11 | - https://laravel.com/docs/8.x/queries 12 | severity: WARNING 13 | message: >- 14 | Detected a SQL query based on user input. 15 | This could lead to SQL injection, which could potentially result in sensitive data being exfiltrated by attackers. 16 | Instead, use parameterized queries and prepared statements. 17 | languages: [php] 18 | mode: taint 19 | pattern-sources: 20 | - patterns: 21 | - pattern-either: 22 | - pattern: $_GET 23 | - pattern: $_POST 24 | - pattern: $_COOKIE 25 | - pattern: $_REQUEST 26 | - pattern: $_SERVER 27 | - pattern: $_FILE[...] 28 | pattern-sinks: 29 | - patterns: 30 | - pattern-either: 31 | - patterns: 32 | - pattern: $SQL 33 | - pattern-either: 34 | - pattern-inside: DB::table(...)->whereRaw($SQL, ...) 35 | - pattern-inside: DB::table(...)->orWhereRaw($SQL, ...) 36 | - pattern-inside: DB::table(...)->groupByRaw($SQL, ...) 37 | - pattern-inside: DB::table(...)->havingRaw($SQL, ...) 38 | - pattern-inside: DB::table(...)->orHavingRaw($SQL, ...) 39 | - pattern-inside: DB::table(...)->orderByRaw($SQL, ...) 40 | - patterns: 41 | - pattern: $EXPRESSION 42 | - pattern-either: 43 | - pattern-inside: DB::table(...)->selectRaw($EXPRESSION, ...) 44 | - pattern-inside: DB::table(...)->fromRaw($EXPRESSION, ...) 45 | - patterns: 46 | - pattern: $COLUMNS 47 | - pattern-either: 48 | - pattern-inside: DB::table(...)->whereNull($COLUMNS, ...) 49 | - pattern-inside: DB::table(...)->orWhereNull($COLUMN) 50 | - pattern-inside: DB::table(...)->whereNotNull($COLUMNS, ...) 51 | - pattern-inside: DB::table(...)->whereRowValues($COLUMNS, ...) 52 | - pattern-inside: DB::table(...)->orWhereRowValues($COLUMNS, ...) 53 | - pattern-inside: DB::table(...)->find($ID, $COLUMNS) 54 | - pattern-inside: DB::table(...)->paginate($PERPAGE, $COLUMNS, ...) 55 | - pattern-inside: DB::table(...)->simplePaginate($PERPAGE, $COLUMNS, ...) 56 | - pattern-inside: DB::table(...)->cursorPaginate($PERPAGE, $COLUMNS, ...) 57 | - pattern-inside: DB::table(...)->getCountForPagination($COLUMNS) 58 | - pattern-inside: DB::table(...)->aggregate($FUNCTION, $COLUMNS) 59 | - pattern-inside: DB::table(...)->numericAggregate($FUNCTION, $COLUMNS) 60 | - pattern-inside: DB::table(...)->insertUsing($COLUMNS, ...) 61 | - pattern-inside: DB::table(...)->select($COLUMNS) 62 | - pattern-inside: DB::table(...)->get($COLUMNS) 63 | - pattern-inside: DB::table(...)->count($COLUMNS) 64 | - patterns: 65 | - pattern: $COLUMN 66 | - pattern-either: 67 | - pattern-inside: DB::table(...)->whereIn($COLUMN, ...) 68 | - pattern-inside: DB::table(...)->orWhereIn($COLUMN, ...) 69 | - pattern-inside: DB::table(...)->whereNotIn($COLUMN, ...) 70 | - pattern-inside: DB::table(...)->orWhereNotIn($COLUMN, ...) 71 | - pattern-inside: DB::table(...)->whereIntegerInRaw($COLUMN, ...) 72 | - pattern-inside: DB::table(...)->orWhereIntegerInRaw($COLUMN, ...) 73 | - pattern-inside: DB::table(...)->whereIntegerNotInRaw($COLUMN, ...) 74 | - pattern-inside: DB::table(...)->orWhereIntegerNotInRaw($COLUMN, ...) 75 | - pattern-inside: DB::table(...)->whereBetweenColumns($COLUMN, ...) 76 | - pattern-inside: DB::table(...)->orWhereBetween($COLUMN, ...) 77 | - pattern-inside: DB::table(...)->orWhereBetweenColumns($COLUMN, ...) 78 | - pattern-inside: DB::table(...)->whereNotBetween($COLUMN, ...) 79 | - pattern-inside: DB::table(...)->whereNotBetweenColumns($COLUMN, ...) 80 | - pattern-inside: DB::table(...)->orWhereNotBetween($COLUMN, ...) 81 | - pattern-inside: DB::table(...)->orWhereNotBetweenColumns($COLUMN, ...) 82 | - pattern-inside: DB::table(...)->orWhereNotNull($COLUMN) 83 | - pattern-inside: DB::table(...)->whereDate($COLUMN, ...) 84 | - pattern-inside: DB::table(...)->orWhereDate($COLUMN, ...) 85 | - pattern-inside: DB::table(...)->whereTime($COLUMN, ...) 86 | - pattern-inside: DB::table(...)->orWhereTime($COLUMN, ...) 87 | - pattern-inside: DB::table(...)->whereDay($COLUMN, ...) 88 | - pattern-inside: DB::table(...)->orWhereDay($COLUMN, ...) 89 | - pattern-inside: DB::table(...)->whereMonth($COLUMN, ...) 90 | - pattern-inside: DB::table(...)->orWhereMonth($COLUMN, ...) 91 | - pattern-inside: DB::table(...)->whereYear($COLUMN, ...) 92 | - pattern-inside: DB::table(...)->orWhereYear($COLUMN, ...) 93 | - pattern-inside: DB::table(...)->whereJsonContains($COLUMN, ...) 94 | - pattern-inside: DB::table(...)->orWhereJsonContains($COLUMN, ...) 95 | - pattern-inside: DB::table(...)->whereJsonDoesntContain($COLUMN, ...) 96 | - pattern-inside: DB::table(...)->orWhereJsonDoesntContain($COLUMN, ...) 97 | - pattern-inside: DB::table(...)->whereJsonLength($COLUMN, ...) 98 | - pattern-inside: DB::table(...)->orWhereJsonLength($COLUMN, ...) 99 | - pattern-inside: DB::table(...)->having($COLUMN, ...) 100 | - pattern-inside: DB::table(...)->orHaving($COLUMN, ...) 101 | - pattern-inside: DB::table(...)->havingBetween($COLUMN, ...) 102 | - pattern-inside: DB::table(...)->orderBy($COLUMN, ...) 103 | - pattern-inside: DB::table(...)->orderByDesc($COLUMN) 104 | - pattern-inside: DB::table(...)->latest($COLUMN) 105 | - pattern-inside: DB::table(...)->oldest($COLUMN) 106 | - pattern-inside: DB::table(...)->forPageBeforeId($PERPAGE, $LASTID, $COLUMN) 107 | - pattern-inside: DB::table(...)->forPageAfterId($PERPAGE, $LASTID, $COLUMN) 108 | - pattern-inside: DB::table(...)->value($COLUMN) 109 | - pattern-inside: DB::table(...)->pluck($COLUMN, ...) 110 | - pattern-inside: DB::table(...)->implode($COLUMN, ...) 111 | - pattern-inside: DB::table(...)->min($COLUMN) 112 | - pattern-inside: DB::table(...)->max($COLUMN) 113 | - pattern-inside: DB::table(...)->sum($COLUMN) 114 | - pattern-inside: DB::table(...)->avg($COLUMN) 115 | - pattern-inside: DB::table(...)->average($COLUMN) 116 | - pattern-inside: DB::table(...)->increment($COLUMN, ...) 117 | - pattern-inside: DB::table(...)->decrement($COLUMN, ...) 118 | - pattern-inside: DB::table(...)->where($COLUMN, ...) 119 | - pattern-inside: DB::table(...)->orWhere($COLUMN, ...) 120 | - pattern-inside: DB::table(...)->addSelect($COLUMN) 121 | - patterns: 122 | - pattern: $QUERY 123 | - pattern-inside: DB::unprepared($QUERY) 124 | -------------------------------------------------------------------------------- /semgrep/laravel-unsafe-validator.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: laravel-unsafe-validator 3 | mode: taint 4 | pattern-sources: 5 | - patterns: 6 | - pattern: $R 7 | - pattern-inside: | 8 | public function $F(...,Request $R,...){...} 9 | pattern-sinks: 10 | - patterns: 11 | - pattern: | 12 | Rule::unique($...X)->ignore(...) 13 | message: Found a request argument passed to an `ignore()` definition in a Rule constraint. This 14 | can lead to SQL injection. 15 | languages: 16 | - php 17 | severity: ERROR 18 | metadata: 19 | category: security 20 | cwe: 'CWE-89: Improper Neutralization of Special Elements used in an SQL Command 21 | (''SQL Injection'')' 22 | owasp: 23 | - A03:2021 - Injection 24 | - A01:2017 - Injection 25 | technology: 26 | - php 27 | - laravel 28 | references: 29 | - https://laravel.com/docs/9.x/validation#rule-unique 30 | -------------------------------------------------------------------------------- /semgrep/ldap-bind-without-password.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: ldap-bind-without-password 3 | patterns: 4 | - pattern-either: 5 | - pattern: ldap_bind($LDAP, $DN, NULL) 6 | - pattern: ldap_bind($LDAP, $DN, '') 7 | - patterns: 8 | - pattern: ldap_bind(...) 9 | - pattern-not: ldap_bind($LDAP, $DN, $PASSWORD) 10 | message: >- 11 | Detected anonymous LDAP bind. 12 | This permits anonymous users to execute LDAP statements. 13 | Consider enforcing authentication for LDAP. 14 | metadata: 15 | references: 16 | - https://www.php.net/manual/ru/function.ldap-bind.php 17 | cwe: "CWE-287: Improper Authentication" 18 | owasp: "A2: Broken Authentication" 19 | category: security 20 | technology: 21 | - php 22 | languages: [php] 23 | severity: WARNING 24 | -------------------------------------------------------------------------------- /semgrep/mb-ereg-replace-eval.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: mb-ereg-replace-eval 3 | patterns: 4 | - pattern: mb_ereg_replace($PATTERN, $REPL, $STR, $OPTIONS); 5 | - pattern-not: mb_ereg_replace($PATTERN, $REPL, $STR, "..."); 6 | message: >- 7 | Calling mb_ereg_replace with user input in the options can lead to arbitrary 8 | code execution. The eval modifier (`e`) evaluates the replacement argument 9 | as code. 10 | metadata: 11 | references: 12 | - https://www.php.net/manual/en/function.mb-ereg-replace.php 13 | - https://www.php.net/manual/en/function.mb-regex-set-options.php 14 | category: security 15 | technology: 16 | - php 17 | languages: [php] 18 | severity: ERROR 19 | -------------------------------------------------------------------------------- /semgrep/mb-eregi-replace-eval.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: mb-eregi-replace-eval 3 | patterns: 4 | - pattern: mb_eregi_replace($PATTERN, $REPL, $STR, $OPTIONS); 5 | - pattern-not: mb_eregi_replace($PATTERN, $REPL, $STR, "..."); 6 | message: >- 7 | Calling mb_eregi_replace with user input in the options can lead to arbitrary 8 | code execution. The eval modifier (`e`) evaluates the replacement argument 9 | as code. 10 | metadata: 11 | references: 12 | - https://www.php.net/manual/en/function.mb-ereg-replace.php 13 | - https://www.php.net/manual/en/function.mb-regex-set-options.php 14 | category: security 15 | technology: 16 | - php 17 | languages: [php] 18 | severity: ERROR 19 | -------------------------------------------------------------------------------- /semgrep/mcrypt-use.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: mcrypt-use 3 | patterns: 4 | - pattern: $FUNC(...); 5 | - metavariable-regex: 6 | metavariable: $FUNC 7 | regex: (mcrypt_|mdecrypt_).+ 8 | message: >- 9 | Mcrypt functionality has been deprecated and/or removed in recent PHP 10 | versions. Consider using Sodium or OpenSSL. 11 | metadata: 12 | references: 13 | - https://www.php.net/manual/en/intro.mcrypt.php 14 | - https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/CryptoFunctionsSniff.php 15 | category: security 16 | technology: 17 | - php 18 | languages: [php] 19 | severity: ERROR 20 | -------------------------------------------------------------------------------- /semgrep/md5-loose-equality.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: md5-loose-equality 3 | patterns: 4 | - pattern-either: 5 | - pattern: $X == $FUNC(...) 6 | - pattern: $FUNC(...) == $X 7 | - pattern: $FUNC(...) == $FUNC(...) 8 | - metavariable-regex: 9 | metavariable: $FUNC 10 | regex: md5|md5_file 11 | message: >- 12 | Make sure comparisons involving md5 values are strict (use `===` not `==`) to 13 | avoid type juggling issues 14 | metadata: 15 | references: 16 | - https://www.php.net/manual/en/types.comparisons.php 17 | - https://www.whitehatsec.com/blog/magic-hashes/ 18 | category: security 19 | technology: 20 | - php 21 | languages: [php] 22 | severity: ERROR 23 | -------------------------------------------------------------------------------- /semgrep/md5-used-as-password.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: md5-used-as-password 3 | severity: WARNING 4 | message: >- 5 | It looks like MD5 is used as a password hash. MD5 is not considered a 6 | secure password hash because it can be cracked by an attacker in a short 7 | amount of time. Use a suitable password hashing function such as bcrypt. 8 | You can use `password_hash($PASSWORD, PASSWORD_BCRYPT, $OPTIONS);`. 9 | languages: [php] 10 | metadata: 11 | cwe: "CWE-327: Use of a Broken or Risky Cryptographic Algorithm" 12 | owasp: 13 | - A02:2017 - Broken Authentication 14 | - A02:2021 - Cryptographic Failures 15 | references: 16 | - https://tools.ietf.org/html/rfc6151 17 | - https://crypto.stackexchange.com/questions/44151/how-does-the-flame-malware-take-advantage-of-md5-collision 18 | - https://security.stackexchange.com/questions/211/how-to-securely-hash-passwords 19 | - https://github.com/returntocorp/semgrep-rules/issues/1609 20 | - https://www.php.net/password_hash 21 | category: security 22 | technology: 23 | - md5 24 | mode: taint 25 | pattern-sources: 26 | - patterns: 27 | - pattern-either: 28 | - pattern: md5(...) 29 | - pattern: hash('md5', ...) 30 | pattern-sinks: 31 | - patterns: 32 | - pattern: $FUNCTION(...) 33 | - metavariable-regex: 34 | metavariable: $FUNCTION 35 | regex: (?i)(.*password.*) 36 | -------------------------------------------------------------------------------- /semgrep/non-literal-header.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: non-literal-header 3 | patterns: 4 | - pattern: header(...) 5 | - pattern-not: header("...",...) 6 | message: >- 7 | Using user input when setting headers with `header()` is potentially dangerous. 8 | This could allow an attacker to inject a new line and add a new header into the 9 | response. 10 | This is called HTTP response splitting. 11 | To fix, do not allow whitespace inside `header()`: '[^\s]+'. 12 | metadata: 13 | references: 14 | - https://www.php.net/manual/ru/function.header.php 15 | - https://owasp.org/www-community/attacks/HTTP_Response_Splitting 16 | category: security 17 | technology: 18 | - php 19 | cwe: "CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Response Splitting')" 20 | languages: [php] 21 | severity: WARNING 22 | -------------------------------------------------------------------------------- /semgrep/openssl-cbc-static-iv.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: openssl-cbc-static-iv 3 | patterns: 4 | - pattern-either: 5 | - pattern: openssl_encrypt($D, $M, $K, $FLAGS, "...",...); 6 | - pattern: openssl_decrypt($D, $M, $K, $FLAGS, "...",...); 7 | - metavariable-comparison: 8 | metavariable: $M 9 | comparison: re.match(".*-CBC",$M) 10 | message: Static IV used with AES in CBC mode. Static IVs enable chosen-plaintext 11 | attacks against encrypted data. 12 | languages: 13 | - php 14 | severity: ERROR 15 | metadata: 16 | cwe: 'CWE-329: Generation of Predictable IV with CBC Mode' 17 | references: 18 | - https://csrc.nist.gov/publications/detail/sp/800-38a/final 19 | owasp: 20 | - A02:2021 - Cryptographic Failures 21 | - A03:2017 - Sensitive Data Exposure 22 | technology: 23 | - php 24 | - openssl 25 | category: security 26 | license: MIT 27 | -------------------------------------------------------------------------------- /semgrep/openssl-decrypt-validate.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: openssl-decrypt-validate 3 | patterns: 4 | - pattern: openssl_decrypt(...); 5 | - pattern-not-inside: | 6 | $DECRYPTED_STRING = openssl_decrypt(...); 7 | ... 8 | if($DECRYPTED_STRING === false){ 9 | ... 10 | } 11 | - pattern-not-inside: | 12 | $DECRYPTED_STRING = openssl_decrypt(...); 13 | ... 14 | if($DECRYPTED_STRING == false){ 15 | ... 16 | } 17 | - pattern-not-inside: | 18 | $DECRYPTED_STRING = openssl_decrypt(...); 19 | ... 20 | if(false === $DECRYPTED_STRING){ 21 | ... 22 | } 23 | - pattern-not-inside: | 24 | $DECRYPTED_STRING = openssl_decrypt(...); 25 | ... 26 | if(false == $DECRYPTED_STRING){ 27 | ... 28 | } 29 | - pattern-not-inside: | 30 | $DECRYPTED_STRING = openssl_decrypt(...); 31 | ... 32 | assertTrue(false !== $DECRYPTED_STRING,...); 33 | - pattern-not-inside: | 34 | $DECRYPTED_STRING = openssl_decrypt(...); 35 | ... 36 | assertTrue($DECRYPTED_STRING !== false,...); 37 | - pattern-not-inside: | 38 | $DECRYPTED_STRING = openssl_decrypt(...); 39 | ... 40 | $REFERENCE::assertTrue(false !== $DECRYPTED_STRING,...); 41 | - pattern-not-inside: | 42 | $DECRYPTED_STRING = openssl_decrypt(...); 43 | ... 44 | $REFERENCE::assertTrue($DECRYPTED_STRING !== false,...); 45 | - pattern-not-inside: | 46 | $DECRYPTED_STRING = openssl_decrypt(...); 47 | ... 48 | assert(false !== $DECRYPTED_STRING,...); 49 | - pattern-not-inside: | 50 | $DECRYPTED_STRING = openssl_decrypt(...); 51 | ... 52 | assert($DECRYPTED_STRING !== false,...); 53 | message: The function `openssl_decrypt` returns either a string of the decrypted 54 | data on success or `false` on failure. If the failure case is not handled, this 55 | could lead to undefined behavior in your application. Please handle the case where 56 | `openssl_decrypt` returns `false`. 57 | languages: 58 | - php 59 | severity: WARNING 60 | metadata: 61 | references: 62 | - https://www.php.net/manual/en/function.openssl-decrypt.php 63 | cwe: 'CWE-252: Unchecked Return Value' 64 | owasp: 65 | - A02:2021 - Cryptographic Failures 66 | technology: 67 | - php 68 | - openssl 69 | category: security 70 | -------------------------------------------------------------------------------- /semgrep/php-permissive-cors.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: php-permissive-cors 3 | patterns: 4 | - pattern: header($VALUE,...) 5 | - pattern-either: 6 | - pattern: header("...",...) 7 | - pattern-inside: | 8 | $VALUE = "..."; 9 | ... 10 | - metavariable-regex: 11 | metavariable: $VALUE 12 | regex: (\'|\")\s*(Access-Control-Allow-Origin|access-control-allow-origin)\s*:\s*(\*)\s*(\'|\") 13 | message: >- 14 | Access-Control-Allow-Origin response header is set to "*". 15 | This will disable CORS Same Origin Policy restrictions. 16 | metadata: 17 | references: 18 | - https://developer.mozilla.org/ru/docs/Web/HTTP/Headers/Access-Control-Allow-Origin 19 | owasp: "A6: Security Misconfiguration" 20 | cwe: "CWE-346: Origin Validation Error" 21 | category: security 22 | technology: 23 | - php 24 | languages: [php] 25 | severity: WARNING 26 | -------------------------------------------------------------------------------- /semgrep/php-ssrf.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: php-ssrf 3 | patterns: 4 | - pattern-either: 5 | - pattern: | 6 | $VAR=$DATA; 7 | ... 8 | $FUNCS(...,$VAR, ...); 9 | - pattern: $FUNCS(...,$DATA, ...); 10 | - metavariable-pattern: 11 | metavariable: $DATA 12 | patterns: 13 | - pattern-either: 14 | - pattern: $_GET 15 | - pattern: $_POST 16 | - pattern: $_COOKIE 17 | - pattern: $_REQUEST 18 | - pattern: $_FILE[...] 19 | - pattern: $params[...] # Captures user-controlled `$params` 20 | - pattern: $request->getParam(...) # Captures user-controlled request parameters 21 | - pattern: $request->input(...) # Alternative for Laravel-style requests 22 | - metavariable-pattern: 23 | metavariable: $FUNCS 24 | patterns: 25 | - pattern-either: 26 | - pattern: curl_setopt 27 | - pattern: fopen 28 | - pattern: file_get_contents 29 | - pattern: curl_init 30 | - pattern: readfile 31 | message: The web server receives a URL or similar request from an upstream 32 | component and retrieves the contents of this URL, but it does not 33 | sufficiently ensure that the request is being sent to the expected 34 | destination. Dangerous function $FUNCS with payload $DATA 35 | metadata: 36 | references: 37 | - https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html 38 | cwe: 39 | - "CWE-918: Server-Side Request Forgery (SSRF)" 40 | category: security 41 | technology: 42 | - php 43 | owasp: 44 | - A10:2021 - Server-Side Request Forgery (SSRF) 45 | cwe2022-top25: true 46 | subcategory: 47 | - audit 48 | likelihood: LOW 49 | impact: HIGH 50 | confidence: LOW 51 | languages: 52 | - php 53 | severity: ERROR 54 | -------------------------------------------------------------------------------- /semgrep/phpinfo-use.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: phpinfo-use 3 | pattern: phpinfo(...); 4 | message: >- 5 | The 'phpinfo' function may reveal sensitive information about your environment. 6 | metadata: 7 | references: 8 | - https://www.php.net/manual/en/function.phpinfo 9 | - https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/PhpinfosSniff.php 10 | category: security 11 | technology: 12 | - php 13 | languages: [php] 14 | severity: ERROR 15 | -------------------------------------------------------------------------------- /semgrep/preg-replace-eval.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: preg-replace-eval 3 | patterns: 4 | - pattern: preg_replace(...); 5 | - pattern-not: preg_replace("...", ...); 6 | message: >- 7 | Calling preg_replace with user input in the pattern can lead to arbitrary 8 | code execution. The eval modifier (`/e`) evaluates the replacement argument 9 | as code. 10 | metadata: 11 | references: 12 | - https://www.php.net/manual/en/function.preg-replace.php 13 | - https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php 14 | - https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/PregReplaceSniff.php 15 | category: security 16 | technology: 17 | - php 18 | languages: [php] 19 | severity: ERROR 20 | -------------------------------------------------------------------------------- /semgrep/source-leak.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: source-leak 3 | patterns: 4 | - pattern: $FUNC(...); 5 | - pattern-not: $FUNC("..."); 6 | - pattern-not: $FUNC(__DIR__ . "..."); 7 | - metavariable-regex: 8 | metavariable: $FUNC 9 | regex: \b(show_source|highlight_file)\b 10 | message: >- 11 | Detected non-constant source code display. This can lead to local file inclusion (LFI). LFI could lead to sensitive files being obtained by attackers. Instead, explicitly specify what to include. If that is not a viable solution, validate user input thoroughly. 12 | metadata: 13 | references: 14 | - https://www.php.net/manual/en/function.highlight-file 15 | - https://en.wikipedia.org/wiki/File_inclusion_vulnerability#Types_of_Inclusion 16 | category: security 17 | technology: 18 | - php 19 | languages: [php] 20 | severity: ERROR 21 | -------------------------------------------------------------------------------- /semgrep/sqli-query-sink-1.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: sql-query-sink-1 3 | patterns: 4 | - pattern-either: 5 | - pattern-regex: '"SELECT\s+[^"]*\$[a-zA-Z0-9_]+.*"' 6 | - pattern-regex: '"INSERT\s+[^"]*\$[a-zA-Z0-9_]+.*"' 7 | - pattern-regex: '"UPDATE\s+[^"]*\$[a-zA-Z0-9_]+.*"' 8 | - pattern-regex: '"DELETE\s+[^"]*\$[a-zA-Z0-9_]+.*"' 9 | message: >- 10 | SQL query constructed with a PHP variable 11 | metadata: 12 | references: 13 | - https://owasp.org/www-community/attacks/SQL_Injection 14 | category: security 15 | technology: 16 | - php 17 | languages: [php] 18 | severity: WARNING -------------------------------------------------------------------------------- /semgrep/sqli-query-sink-2.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: sql-query-sink-2 3 | patterns: 4 | - pattern-either: 5 | - pattern-regex: '\$sqlReq\s*\.=\s*.*\$[a-zA-Z0-9_].*;' 6 | - pattern-regex: '\$sql\s*\.=\s*.*\$[a-zA-Z0-9_].*;' 7 | message: >- 8 | SQL query concatenating a PHP variable 9 | metadata: 10 | references: 11 | - https://owasp.org/www-community/attacks/SQL_Injection 12 | category: security 13 | technology: 14 | - php 15 | languages: [php] 16 | severity: WARNING -------------------------------------------------------------------------------- /semgrep/symfony-csrf-protection-disabled.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: symfony-csrf-protection-disabled 3 | patterns: 4 | - pattern-either: 5 | - pattern: $X->createForm($TYPE, $TASK, [..., 'csrf_protection' => false, ...], ...) 6 | - pattern: $X->prependExtensionConfig('framework', [..., 'csrf_protection' => false, ...], ...) 7 | - pattern: $X->loadFromExtension('framework', [..., 'csrf_protection' => false, ...], ...) 8 | - pattern: $X->setDefaults([..., 'csrf_protection' => false, ...], ...) 9 | - patterns: 10 | - pattern-either: 11 | - pattern: $X->createForm($TYPE, $TASK, [..., 'csrf_protection' => $VAL, ...], ...) 12 | - pattern: $X->prependExtensionConfig('framework', [..., 'csrf_protection' => $VAL, ...], ...) 13 | - pattern: $X->loadFromExtension('framework', [..., 'csrf_protection' => $VAL, ...], ...) 14 | - pattern: $X->setDefaults([..., 'csrf_protection' => $VAL, ...], ...) 15 | - pattern-inside: | 16 | $VAL = false; 17 | ... 18 | message: >- 19 | CSRF is disabled for this configuration. This is a security risk. 20 | Make sure that it is safe or consider setting `csrf_protection` property to `true`. 21 | metadata: 22 | references: 23 | - https://symfony.com/doc/current/security/csrf.html 24 | cwe: "CWE-352: Cross-Site Request Forgery (CSRF)" 25 | owasp: "A6: Security Misconfiguration" 26 | category: security 27 | technology: 28 | - symfony 29 | languages: [php] 30 | severity: WARNING 31 | -------------------------------------------------------------------------------- /semgrep/symfony-non-literal-redirect.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: symfony-non-literal-redirect 3 | patterns: 4 | - pattern: $this->redirect(...) 5 | - pattern-not: $this->redirect("...") 6 | - pattern-not: $this->redirect() 7 | message: >- 8 | The `redirect()` method does not check its destination in any way. If you redirect to a URL provided by end-users, your 9 | application may be open to the unvalidated redirects security vulnerability. 10 | Consider using literal values or an allowlist to validate URLs. 11 | languages: [php] 12 | metadata: 13 | references: 14 | - https://symfony.com/doc/current/controller.html#redirecting 15 | - https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html 16 | owasp: "A1: Injection" 17 | cwe: "CWE-601: URL Redirection to Untrusted Site ('Open Redirect')" 18 | category: security 19 | technology: 20 | - symfony 21 | severity: WARNING 22 | -------------------------------------------------------------------------------- /semgrep/symfony-permissive-cors.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: symfony-permissive-cors 3 | patterns: 4 | - pattern-inside: | 5 | use Symfony\Component\HttpFoundation\Response; 6 | ... 7 | - pattern-either: 8 | - patterns: 9 | - pattern-either: 10 | - pattern: | 11 | new Symfony\Component\HttpFoundation\Response($X, $Y, $HEADERS, ...) 12 | - pattern: new Response($X, $Y, $HEADERS, ...) 13 | - pattern-either: 14 | - pattern: new $R($X, $Y, [$KEY => $VALUE], ...) 15 | - pattern-inside: | 16 | $HEADERS = [$KEY => $VALUE]; 17 | ... 18 | - patterns: 19 | - pattern: $RES->headers->set($KEY, $VALUE) 20 | - metavariable-regex: 21 | metavariable: $KEY 22 | regex: (\'|\")\s*(Access-Control-Allow-Origin|access-control-allow-origin)\s*(\'|\") 23 | - metavariable-regex: 24 | metavariable: $VALUE 25 | regex: (\'|\")\s*(\*)\s*(\'|\") 26 | message: >- 27 | Access-Control-Allow-Origin response header is set to "*". 28 | This will disable CORS Same Origin Policy restrictions. 29 | metadata: 30 | references: 31 | - https://developer.mozilla.org/ru/docs/Web/HTTP/Headers/Access-Control-Allow-Origin 32 | owasp: "A6: Security Misconfiguration" 33 | cwe: "CWE-346: Origin Validation Error" 34 | category: security 35 | technology: 36 | - symfony 37 | languages: [php] 38 | severity: WARNING 39 | -------------------------------------------------------------------------------- /semgrep/tainted-callable.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: tainted-callable 3 | severity: WARNING 4 | message: >- 5 | Callable based on user input risks remote code execution. 6 | metadata: 7 | technology: 8 | - php 9 | category: security 10 | cwe: 11 | - "CWE-94: Improper Control of Generation of Code ('Code Injection')" 12 | owasp: 13 | - A03:2021 - Injection 14 | references: 15 | - https://www.php.net/manual/en/language.types.callable.php 16 | subcategory: 17 | - vuln 18 | impact: HIGH 19 | likelihood: MEDIUM 20 | confidence: MEDIUM 21 | languages: [php] 22 | mode: taint 23 | pattern-sources: 24 | - patterns: 25 | - pattern-either: 26 | - pattern: $_GET 27 | - pattern: $_POST 28 | - pattern: $_COOKIE 29 | - pattern: $_REQUEST 30 | - pattern: $_FILE[...] 31 | - pattern: file_get_contents('php://input') 32 | - pattern: $params[...] # Captures user-controlled `$params` 33 | - pattern: $request->getParam(...) # Captures user-controlled request parameters 34 | - pattern: $request->input(...) # Alternative for Laravel-style requests 35 | pattern-sinks: 36 | - patterns: 37 | - pattern: $CALLABLE 38 | - pattern-either: 39 | - pattern-inside: $ARRAYITERATOR->uasort($CALLABLE) 40 | - pattern-inside: $ARRAYITERATOR->uksort($CALLABLE) 41 | - pattern-inside: $EVENTHTTP->setCallback($CALLABLE, ...) 42 | - pattern-inside: $EVENTHTTPCONNECTION->setCloseCallback($CALLABLE, ...) 43 | - pattern-inside: $EVLOOP->fork($CALLABLE, ...) 44 | - pattern-inside: $EVLOOP->idle($CALLABLE, ...) 45 | - pattern-inside: $EVLOOP->prepare($CALLABLE, ...) 46 | - pattern-inside: $EVWATCHER->setCallback($CALLABLE) 47 | - pattern-inside: $GEARMANCLIENT->setClientCallback($CALLABLE) 48 | - pattern-inside: $GEARMANCLIENT->setCompleteCallback($CALLABLE) 49 | - pattern-inside: $GEARMANCLIENT->setCreatedCallback($CALLABLE) 50 | - pattern-inside: $GEARMANCLIENT->setDataCallback($CALLABLE) 51 | - pattern-inside: $GEARMANCLIENT->setExceptionCallback($CALLABLE) 52 | - pattern-inside: $GEARMANCLIENT->setFailCallback($CALLABLE) 53 | - pattern-inside: $GEARMANCLIENT->setStatusCallback($CALLABLE) 54 | - pattern-inside: $GEARMANCLIENT->setWarningCallback($CALLABLE) 55 | - pattern-inside: $GEARMANCLIENT->setWorkloadCallback($CALLABLE) 56 | - pattern-inside: $IMAGICK->setProgressMonitor($CALLABLE) 57 | - pattern-inside: $OAUTHPROVIDER->consumerHandler($CALLABLE) 58 | - pattern-inside: $OAUTHPROVIDER->tokenHandler($CALLABLE) 59 | - pattern-inside: $PDO->sqliteCreateCollation($NAME, $CALLABLE) 60 | - pattern-inside: $PDOSTATEMENT->fetchAll(PDO::FETCH_FUNC, $CALLABLE) 61 | - pattern-inside: $SQLITE3->createCollation($NAME, $CALLABLE) 62 | - pattern-inside: $SQLITE3->setAuthorizer($CALLABLE) 63 | - pattern-inside: $ZIPARCHIVE->registerCancelCallback($CALLABLE) 64 | - pattern-inside: $ZIPARCHIVE->registerProgressCallback($RATE, $CALLABLE) 65 | - pattern-inside: $ZMQDEVICE->setIdleCallback($CALLABLE, ...) 66 | - pattern-inside: $ZMQDEVICE->setTimerCallback($CALLABLE, ...) 67 | - pattern-inside: apcu_entry($KEY, $CALLABLE, ...) 68 | - pattern-inside: array_filter($ARRAY, $CALLABLE, ...) 69 | - pattern-inside: array_map($CALLABLE, ...) 70 | - pattern-inside: array_reduce($ARRAY, $CALLABLE, ...) 71 | - pattern-inside: array_walk_recursive($ARRAY, $CALLABLE, ...) 72 | - pattern-inside: array_walk($ARRAY, $CALLABLE, ...) 73 | - pattern-inside: call_user_func_array($CALLABLE, ...) 74 | - pattern-inside: call_user_func($CALLABLE, ...) 75 | - pattern-inside: Closure::fromCallable($CALLABLE) 76 | - pattern-inside: createCollation($NAME, $CALLABLE) 77 | - pattern-inside: eio_grp($CALLABLE, ...) 78 | - pattern-inside: eio_nop($PRI, $CALLABLE, ...) 79 | - pattern-inside: eio_sync($PRI, $CALLABLE, ...) 80 | - pattern-inside: EvPrepare::createStopped($CALLABLE, ...) 81 | - pattern-inside: fann_set_callback($ANN, $CALLABLE) 82 | - pattern-inside: fdf_enum_values($FDF_DOCUMENT, $CALLABLE, ...) 83 | - pattern-inside: forward_static_call_array($CALLABLE, ...) 84 | - pattern-inside: forward_static_call($CALLABLE, ...) 85 | - pattern-inside: header_register_callback($CALLABLE) 86 | - pattern-inside: ibase_set_event_handler($CALLABLE, ...) 87 | - pattern-inside: IntlChar::enumCharTypes($CALLABLE) 88 | - pattern-inside: iterator_apply($ITERATOR, $CALLABLE) 89 | - pattern-inside: ldap_set_rebind_proc($LDAP, $CALLABLE) 90 | - pattern-inside: libxml_set_external_entity_loader($CALLABLE, ...) 91 | - pattern-inside: new CallbackFilterIterator($ITERATOR, $CALLABLE) 92 | - pattern-inside: new EvCheck($CALLABLE, ...) 93 | - pattern-inside: new EventHttpRequest($CALLABLE, ...) 94 | - pattern-inside: new EvFork($CALLABLE, ...) 95 | - pattern-inside: new EvIdle($CALLABLE, ...) 96 | - pattern-inside: new Fiber($CALLABLE) 97 | - pattern-inside: new Memcached($PERSISTENT_ID, $CALLABLE, ...) 98 | - pattern-inside: new RecursiveCallbackFilterIterator($ITERATOR, $CALLABLE) 99 | - pattern-inside: new Zookeeper($HOST, $CALLABLE, ...) 100 | - pattern-inside: ob_start($CALLABLE, ...) 101 | - pattern-inside: oci_register_taf_callback($CONNECTION, $CALLABLE) 102 | - pattern-inside: readline_callback_handler_install($PROMPT, $CALLABLE) 103 | - pattern-inside: readline_completion_function($CALLABLE) 104 | - pattern-inside: register_shutdown_function($CALLABLE, ...) 105 | - pattern-inside: register_tick_function($CALLABLE, ...) 106 | - pattern-inside: rnp_ffi_set_pass_provider($FFI, $CALLABLE) 107 | - pattern-inside: sapi_windows_set_ctrl_handler($CALLABLE, ...) 108 | - pattern-inside: set_error_handler($CALLABLE, ...) 109 | - pattern-inside: set_exception_handler($CALLABLE) 110 | - pattern-inside: setAuthorizer($CALLABLE) 111 | - pattern-inside: spl_autoload_register($CALLABLE, ...) 112 | - pattern-inside: uasort($ARRAY, $CALLABLE) 113 | - pattern-inside: uksort($ARRAY, $CALLABLE) 114 | - pattern-inside: usort($ARRAY, $CALLABLE) 115 | - pattern-inside: xml_set_character_data_handler($PARSER, $CALLABLE) 116 | - pattern-inside: xml_set_default_handler($PARSER, $CALLABLE) 117 | - pattern-inside: xml_set_element_handler($PARSER, $CALLABLE, $CALLABLE) 118 | - pattern-inside: xml_set_notation_decl_handler($PARSER, $CALLABLE) 119 | - pattern-inside: Yar_Concurrent_Client::loop($CALLABLE, ...) 120 | -------------------------------------------------------------------------------- /semgrep/tainted-exec.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: tainted-exec 3 | languages: 4 | - php 5 | severity: WARNING 6 | message: >- 7 | User input is passed to a function that executes a shell command. This can lead to remote code execution. 8 | metadata: 9 | cwe: 10 | - "CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')" 11 | category: security 12 | technology: 13 | - php 14 | owasp: 15 | - A03:2021 - Injection 16 | references: 17 | - https://owasp.org/Top10/A03_2021-Injection 18 | subcategory: 19 | - vuln 20 | impact: HIGH 21 | likelihood: MEDIUM 22 | confidence: MEDIUM 23 | mode: taint 24 | pattern-sources: 25 | - patterns: 26 | - pattern-either: 27 | - pattern: $_GET 28 | - pattern: $_POST 29 | - pattern: $_COOKIE 30 | - pattern: $_REQUEST 31 | - pattern: $_FILE[...] 32 | - pattern: file_get_contents('php://input') 33 | - pattern: $params[...] # Captures user-controlled `$params` 34 | - pattern: $request->getParam(...) # Captures user-controlled request parameters 35 | - pattern: $request->input(...) # Alternative for Laravel-style requests 36 | pattern-sanitizers: 37 | - patterns: 38 | - pattern-either: 39 | - pattern: escapeshellcmd(...) 40 | - pattern: escapeshellarg(...) 41 | pattern-sinks: 42 | - patterns: 43 | - pattern-either: 44 | - pattern: exec(...) 45 | - pattern: system(...) 46 | - pattern: passthru(...) 47 | - patterns: 48 | - pattern: proc_open(...) 49 | - pattern-not: proc_open([...], ...) 50 | - pattern: popen(...) 51 | - pattern: expect_popen(...) 52 | - pattern: shell_exec(...) 53 | - pattern: | 54 | `...` 55 | 56 | -------------------------------------------------------------------------------- /semgrep/tainted-filename.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: tainted-filename 3 | severity: WARNING 4 | message: >- 5 | File name based on user input risks server-side request forgery. 6 | metadata: 7 | technology: 8 | - php 9 | category: security 10 | cwe: 11 | - 'CWE-918: Server-Side Request Forgery (SSRF)' 12 | owasp: 13 | - A10:2021 - Server-Side Request Forgery (SSRF) 14 | references: 15 | - https://owasp.org/Top10/A10_2021-Server-Side_Request_Forgery_%28SSRF%29 16 | cwe2022-top25: true 17 | cwe2021-top25: true 18 | subcategory: 19 | - vuln 20 | impact: MEDIUM 21 | likelihood: MEDIUM 22 | confidence: MEDIUM 23 | languages: [php] 24 | mode: taint 25 | pattern-sources: 26 | - patterns: 27 | - pattern-either: 28 | - pattern: $_GET 29 | - pattern: $_POST 30 | - pattern: $_COOKIE 31 | - pattern: $_REQUEST 32 | - pattern: $_SERVER 33 | - pattern: $params[...] # Captures user-controlled `$params` 34 | - pattern: $request->getParam(...) # Captures user-controlled request parameters 35 | - pattern: $request->input(...) # Alternative for Laravel-style requests 36 | pattern-sanitizers: 37 | - patterns: 38 | - pattern-either: 39 | - pattern-inside: basename($PATH, ...) 40 | - pattern-inside: linkinfo($PATH, ...) 41 | - pattern-inside: readlink($PATH, ...) 42 | - pattern-inside: realpath($PATH, ...) 43 | pattern-sinks: 44 | - patterns: 45 | - pattern-either: 46 | - pattern-inside: opcache_compile_file($FILENAME, ...) 47 | - pattern-inside: opcache_invalidate($FILENAME, ...) 48 | - pattern-inside: opcache_is_script_cached($FILENAME, ...) 49 | - pattern-inside: runkit7_import($FILENAME, ...) 50 | - pattern-inside: readline_read_history($FILENAME, ...) 51 | - pattern-inside: readline_write_history($FILENAME, ...) 52 | - pattern-inside: rar_open($FILENAME, ...) 53 | - pattern-inside: zip_open($FILENAME, ...) 54 | - pattern-inside: gzfile($FILENAME, ...) 55 | - pattern-inside: gzopen($FILENAME, ...) 56 | - pattern-inside: readgzfile($FILENAME, ...) 57 | - pattern-inside: hash_file($ALGO, $FILENAME, ...) 58 | - pattern-inside: hash_update_file($CONTEXT, $FILENAME, ...) 59 | - pattern-inside: pg_trace($FILENAME, ...) 60 | - pattern-inside: dio_open($FILENAME, ...) 61 | - pattern-inside: finfo_file($FINFO, $FILENAME, ...) 62 | - pattern-inside: mime_content_type($FILENAME, ...) 63 | - pattern-inside: chgrp($FILENAME, ...) 64 | - pattern-inside: chmod($FILENAME, ...) 65 | - pattern-inside: chown($FILENAME, ...) 66 | - pattern-inside: clearstatcache($CLEAR_REALPATH_CACHE, $FILENAME, ...) 67 | - pattern-inside: file_exists($FILENAME, ...) 68 | - pattern-inside: file_get_contents($FILENAME, ...) 69 | - pattern-inside: file_put_contents($FILENAME, ...) 70 | - pattern-inside: file($FILENAME, ...) 71 | - pattern-inside: fileatime($FILENAME, ...) 72 | - pattern-inside: filectime($FILENAME, ...) 73 | - pattern-inside: filegroup($FILENAME, ...) 74 | - pattern-inside: fileinode($FILENAME, ...) 75 | - pattern-inside: filemtime($FILENAME, ...) 76 | - pattern-inside: fileowner($FILENAME, ...) 77 | - pattern-inside: fileperms($FILENAME, ...) 78 | - pattern-inside: filesize($FILENAME, ...) 79 | - pattern-inside: filetype($FILENAME, ...) 80 | - pattern-inside: fnmatch($PATTERN, $FILENAME, ...) 81 | - pattern-inside: fopen($FILENAME, ...) 82 | - pattern-inside: is_dir($FILENAME, ...) 83 | - pattern-inside: is_executable($FILENAME, ...) 84 | - pattern-inside: is_file($FILENAME, ...) 85 | - pattern-inside: is_link($FILENAME, ...) 86 | - pattern-inside: is_readable($FILENAME, ...) 87 | - pattern-inside: is_uploaded_file($FILENAME, ...) 88 | - pattern-inside: is_writable($FILENAME, ...) 89 | - pattern-inside: lchgrp($FILENAME, ...) 90 | - pattern-inside: lchown($FILENAME, ...) 91 | - pattern-inside: lstat($FILENAME, ...) 92 | - pattern-inside: parse_ini_file($FILENAME, ...) 93 | - pattern-inside: readfile($FILENAME, ...) 94 | - pattern-inside: stat($FILENAME, ...) 95 | - pattern-inside: touch($FILENAME, ...) 96 | - pattern-inside: unlink($FILENAME, ...) 97 | - pattern-inside: xattr_get($FILENAME, ...) 98 | - pattern-inside: xattr_list($FILENAME, ...) 99 | - pattern-inside: xattr_remove($FILENAME, ...) 100 | - pattern-inside: xattr_set($FILENAME, ...) 101 | - pattern-inside: xattr_supported($FILENAME, ...) 102 | - pattern-inside: enchant_broker_request_pwl_dict($BROKER, $FILENAME, ...) 103 | - pattern-inside: pspell_config_personal($CONFIG, $FILENAME, ...) 104 | - pattern-inside: pspell_config_repl($CONFIG, $FILENAME, ...) 105 | - pattern-inside: pspell_new_personal($FILENAME, ...) 106 | - pattern-inside: exif_imagetype($FILENAME, ...) 107 | - pattern-inside: getimagesize($FILENAME, ...) 108 | - pattern-inside: image2wbmp($IMAGE, $FILENAME, ...) 109 | - pattern-inside: imagecreatefromavif($FILENAME, ...) 110 | - pattern-inside: imagecreatefrombmp($FILENAME, ...) 111 | - pattern-inside: imagecreatefromgd2($FILENAME, ...) 112 | - pattern-inside: imagecreatefromgd2part($FILENAME, ...) 113 | - pattern-inside: imagecreatefromgd($FILENAME, ...) 114 | - pattern-inside: imagecreatefromgif($FILENAME, ...) 115 | - pattern-inside: imagecreatefromjpeg($FILENAME, ...) 116 | - pattern-inside: imagecreatefrompng($FILENAME, ...) 117 | - pattern-inside: imagecreatefromtga($FILENAME, ...) 118 | - pattern-inside: imagecreatefromwbmp($FILENAME, ...) 119 | - pattern-inside: imagecreatefromwebp($FILENAME, ...) 120 | - pattern-inside: imagecreatefromxbm($FILENAME, ...) 121 | - pattern-inside: imagecreatefromxpm($FILENAME, ...) 122 | - pattern-inside: imageloadfont($FILENAME, ...) 123 | - pattern-inside: imagexbm($IMAGE, $FILENAME, ...) 124 | - pattern-inside: iptcembed($IPTC_DATA, $FILENAME, ...) 125 | - pattern-inside: mailparse_msg_extract_part_file($MIMEMAIL, $FILENAME, ...) 126 | - pattern-inside: mailparse_msg_extract_whole_part_file($MIMEMAIL, $FILENAME, ...) 127 | - pattern-inside: mailparse_msg_parse_file($FILENAME, ...) 128 | - pattern-inside: fdf_add_template($FDF_DOCUMENT, $NEWPAGE, $FILENAME, ...) 129 | - pattern-inside: fdf_get_ap($FDF_DOCUMENT, $FIELD, $FACE, $FILENAME, ...) 130 | - pattern-inside: fdf_open($FILENAME, ...) 131 | - pattern-inside: fdf_save($FDF_DOCUMENT, $FILENAME, ...) 132 | - pattern-inside: fdf_set_ap($FDF_DOCUMENT, $FIELD_NAME, $FACE, $FILENAME, ...) 133 | - pattern-inside: ps_add_launchlink($PSDOC, $LLX, $LLY, $URX, $URY, $FILENAME, ...) 134 | - pattern-inside: ps_add_pdflink($PSDOC, $LLX, $LLY, $URX, $URY, $FILENAME, ...) 135 | - pattern-inside: ps_open_file($PSDOC, $FILENAME, ...) 136 | - pattern-inside: ps_open_image_file($PSDOC, $TYPE, $FILENAME, ...) 137 | - pattern-inside: posix_access($FILENAME, ...) 138 | - pattern-inside: posix_mkfifo($FILENAME, ...) 139 | - pattern-inside: posix_mknod($FILENAME, ...) 140 | - pattern-inside: ftok($FILENAME, ...) 141 | - pattern-inside: fann_cascadetrain_on_file($ANN, $FILENAME, ...) 142 | - pattern-inside: fann_read_train_from_file($FILENAME, ...) 143 | - pattern-inside: fann_train_on_file($ANN, $FILENAME, ...) 144 | - pattern-inside: highlight_file($FILENAME, ...) 145 | - pattern-inside: php_strip_whitespace($FILENAME, ...) 146 | - pattern-inside: stream_resolve_include_path($FILENAME, ...) 147 | - pattern-inside: swoole_async_read($FILENAME, ...) 148 | - pattern-inside: swoole_async_readfile($FILENAME, ...) 149 | - pattern-inside: swoole_async_write($FILENAME, ...) 150 | - pattern-inside: swoole_async_writefile($FILENAME, ...) 151 | - pattern-inside: swoole_load_module($FILENAME, ...) 152 | - pattern-inside: tidy_parse_file($FILENAME, ...) 153 | - pattern-inside: tidy_repair_file($FILENAME, ...) 154 | - pattern-inside: get_meta_tags($FILENAME, ...) 155 | - pattern-inside: yaml_emit_file($FILENAME, ...) 156 | - pattern-inside: yaml_parse_file($FILENAME, ...) 157 | - pattern-inside: curl_file_create($FILENAME, ...) 158 | - pattern-inside: ftp_chmod($FTP, $PERMISSIONS, $FILENAME, ...) 159 | - pattern-inside: ftp_delete($FTP, $FILENAME, ...) 160 | - pattern-inside: ftp_mdtm($FTP, $FILENAME, ...) 161 | - pattern-inside: ftp_size($FTP, $FILENAME, ...) 162 | - pattern-inside: rrd_create($FILENAME, ...) 163 | - pattern-inside: rrd_fetch($FILENAME, ...) 164 | - pattern-inside: rrd_graph($FILENAME, ...) 165 | - pattern-inside: rrd_info($FILENAME, ...) 166 | - pattern-inside: rrd_last($FILENAME, ...) 167 | - pattern-inside: rrd_lastupdate($FILENAME, ...) 168 | - pattern-inside: rrd_tune($FILENAME, ...) 169 | - pattern-inside: rrd_update($FILENAME, ...) 170 | - pattern-inside: snmp_read_mib($FILENAME, ...) 171 | - pattern-inside: ssh2_sftp_chmod($SFTP, $FILENAME, ...) 172 | - pattern-inside: ssh2_sftp_realpath($SFTP, $FILENAME, ...) 173 | - pattern-inside: ssh2_sftp_unlink($SFTP, $FILENAME, ...) 174 | - pattern-inside: apache_lookup_uri($FILENAME, ...) 175 | - pattern-inside: md5_file($FILENAME, ...) 176 | - pattern-inside: sha1_file($FILENAME, ...) 177 | - pattern-inside: simplexml_load_file($FILENAME, ...) 178 | - pattern: $FILENAME 179 | -------------------------------------------------------------------------------- /semgrep/tainted-object-instantiation.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: tainted-object-instantiation 3 | languages: 4 | - php 5 | severity: WARNING 6 | message: <- 7 | A new object is created where the class name is based on user input. This 8 | could lead to remote code execution, as it allows to instantiate any class in 9 | the application. 10 | metadata: 11 | cwe: "CWE-470: Use of Externally-Controlled Input to Select Classes or Code ('Unsafe Reflection')" 12 | category: security 13 | technology: 14 | - php 15 | mode: taint 16 | pattern-sources: 17 | - patterns: 18 | - pattern-either: 19 | - pattern: $_GET 20 | - pattern: $_POST 21 | - pattern: $_COOKIE 22 | - pattern: $_REQUEST 23 | - pattern: $_SERVER 24 | - pattern: $_FILE[...] 25 | pattern-sinks: 26 | - patterns: 27 | - pattern-either: 28 | - pattern-inside: new $SINK(...) 29 | - pattern: $SINK 30 | -------------------------------------------------------------------------------- /semgrep/tainted-session.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: tainted-session 3 | severity: WARNING 4 | message: >- 5 | Session key based on user input risks session poisoning. 6 | The user can determine the key used for the session, and thus 7 | write any session variable. Session variables are typically trusted 8 | to be set only by the application, and manipulating the session can 9 | result in access control issues. 10 | metadata: 11 | technology: 12 | - php 13 | category: security 14 | cwe: 15 | - 'CWE-284: Improper Access Control' 16 | owasp: 17 | - A01:2021 - Broken Access Control 18 | references: 19 | - https://en.wikipedia.org/wiki/Session_poisoning 20 | cwe2022-top25: true 21 | cwe2021-top25: true 22 | subcategory: 23 | - vuln 24 | impact: MEDIUM 25 | likelihood: MEDIUM 26 | confidence: MEDIUM 27 | languages: [php] 28 | mode: taint 29 | pattern-sources: 30 | - patterns: 31 | - pattern-either: 32 | - pattern: $_GET 33 | - pattern: $_POST 34 | - pattern: $_COOKIE 35 | - pattern: $_REQUEST 36 | pattern-sanitizers: 37 | - patterns: 38 | - pattern-either: 39 | - pattern: $A . $B 40 | - pattern: bin2hex(...) 41 | - pattern: crc32(...) 42 | - pattern: crypt(...) 43 | - pattern: filter_input(...) 44 | - pattern: filter_var(...) 45 | - pattern: hash(...) 46 | - pattern: md5(...) 47 | - pattern: preg_filter(...) 48 | - pattern: preg_grep(...) 49 | - pattern: preg_match_all(...) 50 | - pattern: sha1(...) 51 | - pattern: sprintf(...) 52 | - pattern: str_contains(...) 53 | - pattern: str_ends_with(...) 54 | - pattern: str_starts_with(...) 55 | - pattern: strcasecmp(...) 56 | - pattern: strchr(...) 57 | - pattern: stripos(...) 58 | - pattern: stristr(...) 59 | - pattern: strnatcasecmp(...) 60 | - pattern: strnatcmp(...) 61 | - pattern: strncmp(...) 62 | - pattern: strpbrk(...) 63 | - pattern: strpos(...) 64 | - pattern: strripos(...) 65 | - pattern: strrpos(...) 66 | - pattern: strspn(...) 67 | - pattern: strstr(...) 68 | - pattern: strtok(...) 69 | - pattern: substr_compare(...) 70 | - pattern: substr_count(...) 71 | - pattern: vsprintf(...) 72 | pattern-sinks: 73 | - patterns: 74 | - pattern-inside: $_SESSION[$KEY] = $VAL; 75 | - pattern: $KEY 76 | -------------------------------------------------------------------------------- /semgrep/tainted-sql-string.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: tainted-sql-string 3 | languages: 4 | - php 5 | severity: ERROR 6 | message: User data flows into this manually-constructed SQL string. User data can 7 | be safely inserted into SQL strings using prepared statements or an object-relational 8 | mapper (ORM). Manually-constructed SQL strings is a possible indicator of SQL 9 | injection, which could let an attacker steal or manipulate data from the database. 10 | Instead, use prepared statements (`$mysqli->prepare("INSERT INTO test(id, label) 11 | VALUES (?, ?)");`) or a safe library. 12 | metadata: 13 | cwe: 'CWE-89: Improper Neutralization of Special Elements used in an SQL Command 14 | (''SQL Injection'')' 15 | owasp: 16 | - A10:2021 17 | - A01:2017 18 | references: 19 | - https://owasp.org/www-community/attacks/SQL_Injection 20 | category: security 21 | technology: 22 | - php 23 | mode: taint 24 | pattern-sanitizers: 25 | - pattern-either: 26 | - pattern: mysqli_real_escape_string(...) 27 | - pattern: real_escape_string(...) 28 | - pattern: $MYSQLI->real_escape_string(...) 29 | pattern-sources: 30 | - patterns: 31 | - pattern-either: 32 | - pattern: $_GET 33 | - pattern: $_POST 34 | - pattern: $_COOKIE 35 | - pattern: $_REQUEST 36 | - pattern: $_FILE[...] 37 | pattern-sinks: 38 | - pattern-either: 39 | - patterns: 40 | - pattern: | 41 | sprintf($SQLSTR, ...) 42 | - metavariable-regex: 43 | metavariable: $SQLSTR 44 | regex: .*\b(?i)(select|delete|insert|create|update|alter|drop)\b.* 45 | - patterns: 46 | - pattern: | 47 | "...{$EXPR}..." 48 | - pattern-regex: | 49 | .*\b(?i)(select|delete|insert|create|update|alter|drop)\b.* 50 | - patterns: 51 | - pattern: | 52 | "...$EXPR..." 53 | - pattern-regex: | 54 | .*\b(?i)(select|delete|insert|create|update|alter|drop)\b.* 55 | - patterns: 56 | - pattern: | 57 | "...".$EXPR 58 | - pattern-regex: | 59 | .*\b(?i)(select|delete|insert|create|update|alter|drop)\b.* 60 | -------------------------------------------------------------------------------- /semgrep/tainted-url-host.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: tainted-url-host 3 | languages: 4 | - php 5 | severity: WARNING 6 | message: >- 7 | User data flows into the host portion of this manually-constructed URL. This could allow an attacker to send data 8 | to their own server, potentially exposing sensitive data such as cookies or authorization information sent with this request. 9 | They could also probe internal servers or other resources that the server runnig this code can access. (This is called 10 | server-side request forgery, or SSRF.) Do not allow arbitrary hosts. Instead, create an allowlist for approved hosts hardcode 11 | the correct host. 12 | metadata: 13 | cwe: "CWE-918: Server-Side Request Forgery (SSRF)" 14 | owasp: 15 | - A10:2021 16 | - A01:2017 17 | references: 18 | - https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html 19 | category: security 20 | technology: 21 | - php 22 | license: Commons Clause License Condition v1.0[LGPL-2.1-only] 23 | mode: taint 24 | pattern-sources: 25 | - patterns: 26 | - pattern-either: 27 | - pattern: $_GET 28 | - pattern: $_POST 29 | - pattern: $_COOKIE 30 | - pattern: $_REQUEST 31 | - pattern: $_FILE[...] 32 | pattern-sinks: 33 | - pattern-either: 34 | - patterns: 35 | - pattern: | 36 | sprintf($URLSTR, ...) 37 | - metavariable-pattern: 38 | metavariable: $URLSTR 39 | language: generic 40 | pattern: $SCHEME://%s 41 | - patterns: 42 | - pattern: | 43 | "...{$EXPR}..." 44 | - pattern-regex: | 45 | .*://\{.* 46 | - patterns: 47 | - pattern: | 48 | "...$EXPR..." 49 | - pattern-regex: | 50 | .*://\$.* 51 | - patterns: 52 | - pattern: | 53 | "...".$EXPR 54 | - pattern-regex: | 55 | .*://["'].* 56 | -------------------------------------------------------------------------------- /semgrep/tainted-zip-extract.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: tainted-zip-extract 3 | severity: WARNING 4 | message: >- 5 | ZIP archive extracting to user controlled directory 6 | metadata: 7 | technology: 8 | - php 9 | category: security 10 | cwe: 11 | - "CWE-23: Relative Path Traversal" 12 | references: 13 | - https://www.php.net/manual/en/ziparchive.extractto.php 14 | subcategory: 15 | - vuln 16 | impact: HIGH 17 | likelihood: MEDIUM 18 | confidence: MEDIUM 19 | languages: [php] 20 | mode: taint 21 | pattern-sources: 22 | - patterns: 23 | - pattern-either: 24 | - pattern: $_GET 25 | - pattern: $_POST 26 | - pattern: $_COOKIE 27 | - pattern: $_REQUEST 28 | - pattern: $_FILE[...] 29 | - pattern: file_get_contents('php://input') 30 | - pattern: $params[...] # Captures user-controlled `$params` 31 | - pattern: $request->getParam(...) # Captures user-controlled request parameters 32 | - pattern: $request->input(...) # Alternative for Laravel-style requests 33 | pattern-sinks: 34 | - patterns: 35 | - pattern: $VAR 36 | - pattern-either: 37 | - pattern-inside: $ZIPARCHIVE->extractTo($VAR) -------------------------------------------------------------------------------- /semgrep/unlink-use.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: unlink-use 3 | patterns: 4 | - pattern: unlink(...) 5 | - pattern-not: unlink("...",...) 6 | message: >- 7 | Using user input when deleting files with `unlink()` is potentially dangerous. 8 | A malicious actor could use this to modify 9 | or access files they have no right to. 10 | metadata: 11 | references: 12 | - https://www.php.net/manual/en/function.unlink 13 | - https://owasp.org/www-project-top-ten/2017/A5_2017-Broken_Access_Control.html 14 | category: security 15 | technology: 16 | - php 17 | owasp: "A5: Broken Access Control" 18 | cwe: "CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')" 19 | languages: [php] 20 | severity: WARNING 21 | -------------------------------------------------------------------------------- /semgrep/unserialize-use.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: unserialize-use 3 | patterns: 4 | - pattern: unserialize(...) 5 | - pattern-not: unserialize("...",...) 6 | message: >- 7 | Calling `unserialize()` with user input in the pattern can lead to arbitrary code 8 | execution. 9 | Consider using JSON or structured data approaches (e.g. Google Protocol Buffers). 10 | metadata: 11 | references: 12 | - https://www.php.net/manual/ru/function.unserialize.php 13 | - https://owasp.org/www-project-top-ten/2017/A8_2017-Insecure_Deserialization.html 14 | category: security 15 | technology: 16 | - php 17 | owasp: "A8: Insecure Deserialization" 18 | cwe: "CWE-502: Deserialization of Untrusted Data" 19 | languages: [php] 20 | severity: WARNING 21 | -------------------------------------------------------------------------------- /semgrep/weak-crypto.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: weak-crypto 3 | patterns: 4 | - pattern: $FUNC(...); 5 | - metavariable-regex: 6 | metavariable: $FUNC 7 | regex: crypt|md5|md5_file|sha1|sha1_file|str_rot13 8 | message: >- 9 | Detected usage of weak crypto function. Consider using stronger alternatives. 10 | metadata: 11 | references: 12 | - https://www.php.net/manual/en/book.sodium.php 13 | - https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/CryptoFunctionsSniff.php 14 | category: security 15 | technology: 16 | - php 17 | languages: [php] 18 | severity: ERROR 19 | -------------------------------------------------------------------------------- /semgrep/xml-load-entity.yaml: -------------------------------------------------------------------------------- 1 | rules: 2 | - id: xml-load-entity 3 | mode: taint 4 | pattern-sources: 5 | - pattern-either: 6 | - pattern: $_GET[...] 7 | - pattern: $_FILES[...] 8 | - pattern: $_POST[...] 9 | - pattern: $_FILE[...] 10 | - pattern: $params[...] # Captures user-controlled `$params` 11 | - pattern: $request->getParam(...) # Captures user-controlled request parameters 12 | - pattern: $request->input(...) # Alternative for Laravel-style requests 13 | pattern-sinks: 14 | - pattern: simplexml_load_string(...,LIBXML_DTDLOAD) 15 | - pattern: simplexml_load_string(...,LIBXML_NOENT) 16 | - pattern: simplexml_load_string(...,LIBXML_DTDATTR) 17 | - pattern: simplexml_load_string(...,LIBXML_DTDVALID) 18 | pattern-sanitizers: 19 | - pattern: simplexml_load_string($VAR, 'SimpleXMLElement', LIBXML_NO_XXE) 20 | - pattern: simplexml_load_string($VAR) 21 | message: Do not call 'simplexml_load_string()' on user-controllable data with the flags LIBXML_NOENT, LIBXML_DTDATTR LIBXML_DTDLOAD, LIBXML_DTDVALID. 22 | languages: 23 | - php 24 | metadata: 25 | category: security 26 | cwe: 27 | - 'CWE-611: Improper Restriction of XML External Entity Reference' 28 | - 'CWE-776: Improper Restriction of Recursive Entity References in DTDs' 29 | technology: 30 | - php 31 | references: 32 | - https://www.php.net/manual/en/function.simplexml-load-string.php 33 | - https://www.php.net/manual/en/libxml.constants.php 34 | - https://www.acceis.fr/kirby-3-9-6-xml-external-entity-xxe-vulnerability-cve-2023-38490/ 35 | subcategory: 36 | - vuln 37 | likelihood: MEDIUM 38 | impact: MEDIUM 39 | confidence: MEDIUM 40 | severity: ERROR -------------------------------------------------------------------------------- /utils/export.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "Generating report" 4 | mkdir Report 2> /dev/null 5 | python index.py --dir $1 --plain > Report/exported.txt 6 | cat Report/exported.txt | grep "Remote Co" -A4 > Report/RemoteCodeExecution.txt 7 | cat Report/exported.txt | grep "File Inclusion" -A4 > Report/File_Inclusion.txt 8 | cat Report/exported.txt | grep "SQL Injection" -A4 > Report/SQL_Injection.txt 9 | cat Report/exported.txt | grep "File Upload" -A4 > Report/File_Upload.txt 10 | cat Report/exported.txt | grep "Cross Site Scripting" -A4 > Report/Cross_Site_Scripting.txt 11 | cat Report/exported.txt | grep "XPATH Injection" -A4 > Report/XPATH_Injection.txt 12 | cat Report/exported.txt | grep "LDAP Injection" -A4 > Report/LDAP_Injection.txt 13 | cat Report/exported.txt | grep "Insecure E-mail" -A4 > Report/Insecure_E-mail.txt 14 | cat Report/exported.txt | grep "PHP Object Injection" -A4 > Report/PHP_Object_Injection.txt 15 | cat Report/exported.txt | grep "Header Injection" -A4 > Report/Header_Injection.txt 16 | cat Report/exported.txt | grep "URL Redirection" -A4 > Report/URL_Redirection.txt 17 | cat Report/exported.txt | grep "Hardcoded Credential" -A4 > Report/Hardcoded_Credential.txt 18 | 19 | 20 | echo "Found :" 21 | ls -ail Report 22 | -------------------------------------------------------------------------------- /vulns/assert-use.php: -------------------------------------------------------------------------------- 1 | 1'); 8 | 9 | // todook: assert-use 10 | assert($user_input > 1); 11 | -------------------------------------------------------------------------------- /vulns/assert.php: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /vulns/backtick.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vulns/backticks-use.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vulns/cookies.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vulns/curl-ssl-verifypeer-off.php: -------------------------------------------------------------------------------- 1 | "blue", 9 | "size" => "medium", 10 | "shape" => "sphere"); 11 | // ok: extract-user-data 12 | extract($var_array, EXTR_PREFIX_SAME, "wddx"); 13 | 14 | $bad = $_GET['some_param']; 15 | // ruleid:extract-user-data 16 | extract($bad, EXTR_PREFIX_SAME, "wddx"); 17 | echo "$color, $size, $shape, $wddx_size\n"; 18 | 19 | $bad2 = $_FILES["/some/bad/path"]; 20 | // ruleid:extract-user-data 21 | extract($bad2, EXTR_PREFIX_SAME, "wddx"); 22 | 23 | // ok: extract-user-data 24 | $ok = $_FILES["/some/bad/path"]; 25 | extract($ok, EXTR_SKIP, "wddx"); 26 | ?> 27 | -------------------------------------------------------------------------------- /vulns/doctrine-dbal-dangerous-query.php: -------------------------------------------------------------------------------- 1 | getEntityManager()->getConnection(); 8 | 9 | $sql = "SELECT * FROM product p WHERE p.price > " . $_GET['cur_price']. " ORDER BY p.price ASC"; 10 | // ruleid: doctrine-dbal-dangerous-query 11 | $stmt = $conn->prepare($sql); 12 | $stmt->execute(['price' => $price]); 13 | 14 | return $stmt->fetchAllAssociative(); 15 | } 16 | 17 | public function test2(): array 18 | { 19 | $conn = $this->getEntityManager()->getConnection(); 20 | 21 | // ruleid: doctrine-dbal-dangerous-query 22 | $query = $conn->createQuery("SELECT u FROM User u WHERE u.username = '" . $_GET['username'] . "'"); 23 | $data = $query->getResult(); 24 | return $data; 25 | } 26 | 27 | public function okTest1(int $price): array 28 | { 29 | $conn = $this->getEntityManager()->getConnection(); 30 | $sql = "SELECT * FROM users WHERE username = ?"; 31 | // ok: doctrine-dbal-dangerous-query 32 | $stmt = $conn->prepare($sql); 33 | $stmt->bindValue(1, $_GET['username']); 34 | $resultSet = $stmt->executeQuery(); 35 | return $resultSet; 36 | } 37 | 38 | public function okTest2(int $price): array 39 | { 40 | $conn = $this->foobar(); 41 | $sql = "SELECT * FROM users WHERE username = ?"; 42 | // ok: doctrine-dbal-dangerous-query 43 | $stmt = $conn->prepare($sql); 44 | $stmt->bindValue(1, $_GET['username']); 45 | $resultSet = $stmt->executeQuery(); 46 | return $resultSet; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /vulns/doctrine-orm-dangerous-query.php: -------------------------------------------------------------------------------- 1 | createQueryBuilder(); 6 | 7 | $queryBuilder 8 | ->select('id', 'name') 9 | ->from('users') 10 | // ruleid: doctrine-orm-dangerous-query 11 | ->where('email = '.$input) 12 | ; 13 | } 14 | 15 | function test2($email, $input) 16 | { 17 | $queryBuilder = new QueryBuilder($this->connection); 18 | 19 | $queryBuilder 20 | ->select('id', 'name') 21 | ->from('users') 22 | ->where('email = ?') 23 | ->setParameter(0, $email) 24 | // ruleid: doctrine-orm-dangerous-query 25 | ->andWhere(sprintf('user = %s', $input)) 26 | ; 27 | } 28 | 29 | function okTest1($input) 30 | { 31 | $queryBuilder = $conn->createQueryBuilder(); 32 | 33 | $queryBuilder 34 | ->select('id', 'name') 35 | ->from('users') 36 | // ok: doctrine-orm-dangerous-query 37 | ->where('email = ?') 38 | ->setParameter(0, $input) 39 | ; 40 | } 41 | -------------------------------------------------------------------------------- /vulns/eval-use.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vulns/extract.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vulns/file-inclusion.php: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /vulns/include.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 12 | 13 | -------------------------------------------------------------------------------- /vulns/info.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vulns/laravel-api-route-sql-injection.php: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /vulns/laravel-blade-form-missing-csrf.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | {{ config('app.name', 'Laravel') }} 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 66 | 67 |
68 | @yield('content') 69 |
70 |
71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /vulns/laravel-dangerous-model-construction.php: -------------------------------------------------------------------------------- 1 | where($tainted, 'John')->first(); 14 | // ruleid: laravel-sql-injection 15 | $titles = DB::table('users')->pluck($tainted); 16 | // ruleid: laravel-sql-injection 17 | DB::table('users')->orderBy($tainted); 18 | // ruleid: laravel-sql-injection 19 | $price = DB::table('orders')->max($tainted); 20 | // ruleid: laravel-sql-injection 21 | $query = DB::table('users')->select($tainted); 22 | 23 | // ok: laravel-sql-injection 24 | $user = DB::table('users')->where('name', $tainted)->first(); 25 | 26 | // https://laravel.com/docs/8.x/queries 27 | // Raw statements will be injected into the query as strings, so you should be extremely careful to avoid creating SQL injection vulnerabilities. 28 | // ruleid: laravel-sql-injection 29 | $users = DB::table('users')->select(DB::raw($tainted)); 30 | // ruleid: laravel-sql-injection 31 | $orders = DB::table('orders')->selectRaw($tainted); 32 | // ruleid: laravel-sql-injection 33 | $orders = DB::table('orders')->whereRaw($tainted); 34 | 35 | // ok: laravel-sql-injection 36 | $orders = DB::table('orders')->selectRaw('price * ? as price_with_tax', [$tainted]); 37 | 38 | -------------------------------------------------------------------------------- /vulns/laravel-unsafe-validator.php: -------------------------------------------------------------------------------- 1 | middleware("auth"); 16 | } 17 | 18 | function index(){ 19 | if(Auth::user()->accesslevel == env("ACCTNG_HEAD")){ 20 | $accounts = \App\ChartOfAccount::orderBy("accounting_name")->get(); 21 | return view("accounting.chart_of_accounts.index", compact("accounts")); 22 | } 23 | } 24 | 25 | function new_account(Request $request){ 26 | if(Auth::user()->accesslevel == env("ACCTNG_HEAD")){ 27 | $validate = Validator::make($request->all(),[ 28 | // ok: laravel-unsafe-validator 29 | "accounting_code" => "required|unique:chart_of_accounts", 30 | // ok: laravel-unsafe-validator 31 | "accounting_name" => "required|unique:chart_of_accounts", 32 | // ok: laravel-unsafe-validator 33 | "some_property" => [ Rule::unique("some_column_name")->ignore(Auth::user()->id, "pk_column_name"), "required" ] 34 | ]); 35 | 36 | if($validate->fails()){ 37 | return redirect()->back()->withErrors($validate); 38 | } 39 | 40 | $newaccount = new \App\ChartOfAccount; 41 | $newaccount->accounting_code = $request->accounting_code; 42 | $newaccount->accounting_name = $request->accounting_name; 43 | $newaccount->category = $request->category; 44 | $newaccount->save(); 45 | 46 | return redirect()->back()->withSuccess("Successfully created!"); 47 | } 48 | } 49 | 50 | function print_lists(){ 51 | if(Auth::user()->accesslevel == env("ACCTNG_HEAD")){ 52 | $accounts = \App\ChartOfAccount::orderBy("accounting_name")->get(); 53 | $pdf = PDF::loadView('accounting.chart_of_accounts.print_lists',compact('accounts')); 54 | $pdf->setPaper('letter','portrait'); 55 | return $pdf->stream("chart_of_accounts.pdf"); 56 | } 57 | } 58 | 59 | function delete_account($id){ 60 | if(Auth::user()->accesslevel == env("ACCTNG_HEAD")){ 61 | $account = \App\ChartOfAccount::find($id); 62 | 63 | $exists = \App\Accounting::where(function($query) use($account){ 64 | $query->where("accounting_code", $account->accounting_code) 65 | ->orWhere("accounting_name", $account->accounting_name); 66 | })->get(); 67 | 68 | if($exists->isEmpty()){ 69 | $account->delete(); 70 | 71 | return redirect()->back()->withSuccess("Account already deleted!"); 72 | }else{ 73 | 74 | return redirect()->back()->withErrors("The account you are trying to delete already have a record."); 75 | } 76 | 77 | } 78 | } 79 | 80 | function update_account($id){ 81 | if(Auth::user()->accesslevel == env("ACCTNG_HEAD")){ 82 | $account = \App\ChartOfAccount::find($id); 83 | 84 | $exists = \App\Accounting::where(function($query) use($account){ 85 | $query->where("accounting_code", $account->accounting_code) 86 | ->orWhere("accounting_name", $account->accounting_name); 87 | })->get(); 88 | 89 | if($exists->isEmpty()){ 90 | return view("accounting.chart_of_accounts.update_form", compact("id","account")); 91 | }else{ 92 | return redirect()->back()->withErrors("The account you are trying to update already have a record."); 93 | } 94 | 95 | } 96 | } 97 | 98 | function update_account_post(Request $request){ 99 | $validate = Validator::make($request->all(),[ 100 | // ruleid: laravel-unsafe-validator 101 | "accounting_code" => [ Rule::unique("chart_of_accounts")->ignore($request->chart_id,"id"), "required" ], 102 | // ruleid: laravel-unsafe-validator 103 | "accounting_name" => [ Rule::unique("chart_of_accounts")->ignore($request->chart_id,"id"), "required" ], 104 | ]); 105 | 106 | if($validate->fails()){ 107 | return redirect(url("/accounting/chart_of_accounts"))->withErrors($validate); 108 | } 109 | 110 | $newaccount = \App\ChartOfAccount::find($request->chart_id); 111 | $newaccount->accounting_code = $request->accounting_code; 112 | $newaccount->accounting_name = $request->accounting_name; 113 | $newaccount->category = $request->category; 114 | $newaccount->save(); 115 | 116 | return redirect(url("/accounting/chart_of_accounts"))->withSuccess("Successfully updated!"); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /vulns/ldap-bind-without-password.php: -------------------------------------------------------------------------------- 1 | There are " . $info["count"] . " entries for that search:

"; 12 | 13 | for ($i=0; $i<$info["count"]; $i++) 14 | { 15 | echo "common name: " . $info[$i]["cn"][0] . "
"; 16 | echo "telephone: " . $info[$i]["telephoneNumber"][0] . "
"; 17 | echo "email: " . $info[$i]["mail"][0] . "


"; 18 | } 19 | 20 | ldap_close($ds); 21 | 22 | } 23 | else 24 | { 25 | echo "

connection error

"; 26 | } 27 | ?> 28 | -------------------------------------------------------------------------------- /vulns/mail.php: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /vulns/mb-ereg-replace-eval.php: -------------------------------------------------------------------------------- 1 | setPassword($pass); 7 | } 8 | 9 | function test2($value) { 10 | $pass = hash('md5', $value); 11 | // ruleid: md5-used-as-password 12 | $user->setPassword($pass); 13 | } 14 | 15 | function okTest1($value) { 16 | // ok: md5-used-as-password 17 | $pass = hash('sha256', $value); 18 | $user->setPassword($pass); 19 | } 20 | -------------------------------------------------------------------------------- /vulns/non-literal-header.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Coffee Database 6 | 7 | 8 | 9 | 10 |
11 | 12 |

Coffee Database

13 | setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); 18 | $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // ERRMODE_WARNING | ERRMODE_EXCEPTION | ERRMODE_SILENT 19 | 20 | $stmt = $pdo->query("SELECT * FROM users WHERE username ='".$_POST['username']."' and password='".$_POST['password']."'"); 21 | if($result = $stmt->fetchAll()){ 22 | echo "

Welcome ".$result[0]['username']."
Your password is ".$result[0]['password']."

"; 23 | echo ''; 24 | } 25 | else{ 26 | echo "Unknown user or password"; 27 | goto login_input; 28 | } 29 | 30 | } 31 | catch(Exception $e) { 32 | echo "Impossible d'accéder à la base de données SQLite : ".$e->getMessage(); 33 | echo '
'; 34 | } 35 | } 36 | else{ 37 | login_input: 38 | ?> 39 | 40 | 41 | 42 | 45 | 46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /vulns/pgsqli.php: -------------------------------------------------------------------------------- 1 | \n"; 18 | } 19 | 20 | ?> 21 | -------------------------------------------------------------------------------- /vulns/php-permissive-cors.php: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /vulns/require.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vulns/sql-ip.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vulns/sqli-req-concat.php: -------------------------------------------------------------------------------- 1 | 0) { 11 | $sql.= " AND planning_periode.projet_id IN ('" . implode("','", $_SESSION['filtreGroupeProjet']) . "')"; 12 | } 13 | 14 | ... 15 | 16 | //echo $sql;die; 17 | $periodes->db_loadSQL($sql); 18 | $nbLignesTotal = $periodes->getCount(); 19 | 20 | ... -------------------------------------------------------------------------------- /vulns/sqli.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Security Challs : Android Compare 6 | 7 | 8 |
9 |

Android Compare

10 |
11 |
12 | "; 25 | echo "phone"; 26 | echo "

".$phone['name']."".nl2br($phone['specifications']); 27 | echo "
ACHETER

"; 28 | echo ""; 29 | } 30 | 31 | } 32 | else{ 33 | //Recuperation des 3 derniers telephones 34 | echo "

Sélectionner un téléphone pour accéder à ses caractéristiques

"; 35 | echo "
"; 36 | $news = mysql_query("SELECT name,image,id FROM ".$DB_CHALL_TWO." ORDER BY id DESC LIMIT 0,3") or die(mysql_error()); 37 | while($phone = mysql_fetch_array($news)){ 38 | echo "".$phone['name']."phone"; 39 | } 40 | echo "
"; 41 | } 42 | ?> 43 |
44 | 45 | 49 | 50 | -------------------------------------------------------------------------------- /vulns/sqli2.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Security Challs : Graduate CMS 6 | 7 | 8 |

Graduate CMS

9 |
10 | 0){ 19 | $data = mysql_fetch_assoc($sql); 20 | echo "Welcome ".$data['username']."
"; 21 | if($data['username'] == 'Administrator'){ 22 | echo "

Good job, you're logged as Administrator

"; 23 | } 24 | else{ 25 | echo "

Congratulation, you're graduated !

"; 26 | } 27 | echo "Log Out"; 28 | } 29 | else{ 30 | echo "Error
"; 31 | echo "Unknown username or password

"; 32 | echo "Retry"; 33 | } 34 | } 35 | else{ 36 | ?> 37 |
38 |
39 |
40 | 41 |
42 | 45 |
46 | 47 | 51 | 52 | -------------------------------------------------------------------------------- /vulns/ssrf.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vulns/ssti.php: -------------------------------------------------------------------------------- 1 | render($_GET['custom_email'], array("first_name" => $user.first_name) ); 4 | 5 | 6 | // from XVWA 7 | if (isset($_GET['submit'])) { 8 | $name=$_GET['name']; 9 | // include and register Twig auto-loader 10 | include 'vendor/twig/twig/lib/Twig/Autoloader.php'; 11 | Twig_Autoloader::register(); 12 | try { 13 | // specify where to look for templates 14 | $loader = new Twig_Loader_String(); 15 | 16 | // initialize Twig environment 17 | $twig = new Twig_Environment($loader); 18 | // set template variables 19 | // render template 20 | $result= $twig->render($name); 21 | 22 | 23 | 24 | $smarty=new vtigerCRM_Smarty; 25 | $smarty->assign("APP",$app_strings); 26 | $record=$_REQUEST['record']; 27 | $smarty->assign("record",$record); 28 | $mode=$_REQUEST["mode"]; 29 | 30 | ?> -------------------------------------------------------------------------------- /vulns/symfony-csrf-protection-disabled.php: -------------------------------------------------------------------------------- 1 | setDefaults([ 18 | 'data_class' => Type::class, 19 | 'csrf_protection' => false 20 | ]); 21 | 22 | // ruleid: symfony-csrf-protection-disabled 23 | $resolver->setDefaults(array( 24 | 'csrf_protection' => false 25 | )); 26 | 27 | 28 | $csrf = false; 29 | // ruleid: symfony-csrf-protection-disabled 30 | $resolver->setDefaults([ 31 | 'csrf_protection' => $csrf 32 | ]); 33 | 34 | // ok: symfony-csrf-protection-disabled 35 | $resolver->setDefaults([ 36 | 'csrf_protection' => true 37 | ]); 38 | 39 | // ok: symfony-csrf-protection-disabled 40 | $resolver->setDefaults([ 41 | 'data_class' => Type::class, 42 | ]); 43 | 44 | // ok: symfony-csrf-protection-disabled 45 | $resolver->setDefaults($options); 46 | } 47 | } 48 | 49 | class TestExtension extends Extension implements PrependExtensionInterface 50 | { 51 | public function prepend(ContainerBuilder $container) 52 | { 53 | 54 | // ruleid: symfony-csrf-protection-disabled 55 | $container->prependExtensionConfig('framework', ['csrf_protection' => false,]); 56 | 57 | // ruleid: symfony-csrf-protection-disabled 58 | $container->prependExtensionConfig('framework', ['something_else' => true, 'csrf_protection' => false,]); 59 | 60 | $csrfOption = false; 61 | // ruleid: symfony-csrf-protection-disabled 62 | $container->prependExtensionConfig('framework', ['csrf_protection' => $csrfOption,]); 63 | 64 | // ruleid: symfony-csrf-protection-disabled 65 | $container->loadFromExtension('framework', ['csrf_protection' => false,]); 66 | 67 | // ok: symfony-csrf-protection-disabled 68 | $container->loadFromExtension('framework', ['csrf_protection' => null,]); 69 | 70 | // ok: symfony-csrf-protection-disabled 71 | $container->prependExtensionConfig('framework', ['csrf_protection' => true,]); 72 | 73 | // ok: symfony-csrf-protection-disabled 74 | $container->prependExtensionConfig('framework', ['csrf_protection' => null,]); 75 | 76 | // ok: symfony-csrf-protection-disabled 77 | $container->prependExtensionConfig('something_else', ['csrf_protection' => false,]); 78 | } 79 | } 80 | 81 | class MyController1 extends AbstractController 82 | { 83 | public function action() 84 | { 85 | // ruleid: symfony-csrf-protection-disabled 86 | $this->createForm(TaskType::class, $task, [ 87 | 'other_option' => false, 88 | 'csrf_protection' => false, 89 | ]); 90 | 91 | // ruleid: symfony-csrf-protection-disabled 92 | $this->createForm(TaskType::class, $task, array( 93 | 'csrf_protection' => false, 94 | )); 95 | 96 | $csrf = false; 97 | // ruleid: symfony-csrf-protection-disabled 98 | $this->createForm(TaskType::class, $task, array( 99 | 'csrf_protection' => $csrf, 100 | )); 101 | 102 | // ok: symfony-csrf-protection-disabled 103 | $this->createForm(TaskType::class, $task, ['csrf_protection' => true]); 104 | 105 | // ok: symfony-csrf-protection-disabled 106 | $this->createForm(TaskType::class, $task, ['other_option' => false]); 107 | 108 | $this->redirectToRoute('/'); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /vulns/symfony-non-literal-redirect.php: -------------------------------------------------------------------------------- 1 | get('foobar'); 9 | // ruleid: symfony-non-literal-redirect 10 | return $this->redirect($foobar); 11 | } 12 | 13 | public function test2(): RedirectResponse 14 | { 15 | $addr = $request->query->get('page', 1); 16 | // ruleid: symfony-non-literal-redirect 17 | return $this->redirect('https://'. $addr); 18 | } 19 | 20 | public function okTest1(): RedirectResponse 21 | { 22 | $foobar = $session->get('foobar'); 23 | // ok: symfony-non-literal-redirect 24 | return $this->redirectToRoute($foobar); 25 | } 26 | 27 | public function okTest2(): RedirectResponse 28 | { 29 | // ok: symfony-non-literal-redirect 30 | return $this->redirect('http://symfony.com/doc'); 31 | } 32 | 33 | public function okTest3(): RedirectResponse 34 | { 35 | // ok: symfony-non-literal-redirect 36 | return $this->redirect(); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /vulns/symfony-permissive-cors.php: -------------------------------------------------------------------------------- 1 | '*']); 8 | 9 | // ruleid: symfony-permissive-cors 10 | $response = new Response('content', Response::HTTP_OK, Array('Access-Control-Allow-Origin' => '*')); 11 | 12 | // todoruleid: symfony-permissive-cors 13 | $response = new response('content', Response::HTTP_OK, Array('Access-Control-Allow-Origin' => '*')); 14 | 15 | // ruleid: symfony-permissive-cors 16 | $response = new FooResponse('content', Response::HTTP_OK, ['Access-Control-Allow-Origin' => '*']); 17 | 18 | 19 | $headers = ['Access-Control-Allow-Origin' => '*']; 20 | // ruleid: symfony-permissive-cors 21 | $response = new Response('content', Response::HTTP_OK, $headers); 22 | 23 | 24 | // ruleid: symfony-permissive-cors 25 | $response->headers->set(' access-control-allow-origin ', ' * '); 26 | 27 | 28 | 29 | $safe = ['foo' => 'bar']; 30 | // ok: symfony-permissive-cors 31 | $response = new Response('content', Response::HTTP_OK, $safe); 32 | 33 | // ok: symfony-permissive-cors 34 | $response = new Response('content', Response::HTTP_OK, ['Access-Control-Allow-Origin' => 'https://www.example.com']); 35 | 36 | // ok: symfony-permissive-cors 37 | $response = new Response('content', Response::HTTP_OK, ['Other-Property' => '*']); 38 | 39 | // ok: symfony-permissive-cors 40 | $response = new Foo('content', Response::HTTP_OK, ['Access-Control-Allow-Origin' => '*']); 41 | 42 | // ok: symfony-permissive-cors 43 | $response->headers->set('Access-Control-Allow-Origin', 'foo'); 44 | 45 | // ok: symfony-permissive-cors 46 | $response->headers->set('Other-Property', '*'); 47 | -------------------------------------------------------------------------------- /vulns/tainted-filename.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vulns/unserialize-use.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Much Series Very Analyse 7 | 8 | 9 | 10 |

Much Series Very Analyse

11 |
12 | 13 | English | Francais


14 | 15 | lang = !empty($lang) ? $lang : 'en.php'; 29 | } 30 | public function __destruct() { 31 | include($this->lang); 32 | echo " 33 | 34 |
35 |

© 2016 WowDoge Security . All Rights Reserved

36 | 37 | "; 38 | } 39 | } 40 | 41 | if (isset($_GET['lang']) && !empty($_GET['lang'])) { 42 | $allowed = ['fr.php', 'en.php']; 43 | if (in_array($_GET['lang'], $allowed)) { 44 | $lang = new Lang($_GET['lang']); 45 | setcookie("lang", serialize($lang)); 46 | } 47 | else 48 | $lang = new Lang('en.php'); 49 | } 50 | else if (isset($_COOKIE['lang']) && !empty($_COOKIE['lang'])) { 51 | $lang = unserialize($_COOKIE['lang']); 52 | } 53 | else { 54 | $lang = new Lang('en.php'); 55 | } 56 | ?> 57 | -------------------------------------------------------------------------------- /vulns/upload.php: -------------------------------------------------------------------------------- 1 | Your image was not uploaded.'; 12 | } 13 | else { 14 | // Yes! 15 | $html .= "
{$target_path} succesfully uploaded!
"; 16 | } 17 | } 18 | ?> -------------------------------------------------------------------------------- /vulns/weak-crypto.php: -------------------------------------------------------------------------------- 1 | Matching employees with name 'Laura Pollard'
"; 5 | $employees = $xml->xpath('/employees/employee[name="'.$_GET['name'].'"]'); 6 | 7 | foreach($employees as $employee) { 8 | echo "Found {$employee->name}
"; 9 | } 10 | 11 | echo "
"; 12 | 13 | echo "Matching employees younger than 54
"; 14 | $employees = $xml->xpath('/employees/employee[age<54]'); 15 | 16 | foreach($employees as $employee) { 17 | echo "Found {$employee->id}
"; 18 | } 19 | 20 | echo "
"; 21 | 22 | echo "Matching employees as old or older than 48
"; 23 | $age = $_POST['age']; 24 | $employees = $xml->xpath('//employee[age>='.$age.']'); 25 | 26 | foreach($employees as $employee) { 27 | echo "Found {$employee->age}
"; 28 | } 29 | 30 | echo "
"; 31 | 32 | ?> 33 | 34 | 35 | load('coffee.xml'); 41 | $xpath = new DOMXPath($doc); 42 | $query = "/Coffees/Coffee[@ID='".$_POST['search']."']"; 43 | #$result = isset($xpath->query($query)) ? $xpath->query($query) : ''; 44 | $result = $xpath->query($query); 45 | } 46 | 47 | ?> -------------------------------------------------------------------------------- /vulns/xss.php: -------------------------------------------------------------------------------- 1 | 2 | The mail ".$mail." has been registered in our database.

"); 6 | } 7 | else{ 8 | echo "

The mail ".$_GET['mail']." has been registered in our database.

"; 9 | } 10 | ?> 11 | 12 | -------------------------------------------------------------------------------- /vulns/xxe.php: -------------------------------------------------------------------------------- 1 | loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); 6 | $creds = simplexml_import_dom($dom); 7 | $user = $creds->user; 8 | $pass = $creds->pass; 9 | echo "You have logged in as user $user"; 10 | ?> -------------------------------------------------------------------------------- /vulns/xxe2.php: -------------------------------------------------------------------------------- 1 | ' . $_GET['name']; 6 | $parsed = simplexml_load_string( $xml, 'SimpleXMLElement', LIBXML_NOENT ); 7 | $e = @simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOENT); 8 | $a = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NO_XXE); 9 | $b = @simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_DTDVALID); 10 | $c = @simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_DTDATTR); 11 | if ( !$parsed ) { 12 | foreach( libxml_get_errors() as $error ) 13 | echo $error->message . "\n"; 14 | } else { 15 | echo 'Hello ' . $parsed . "\n"; 16 | } 17 | } 18 | ?> -------------------------------------------------------------------------------- /vulns/zip-extract-2.php: -------------------------------------------------------------------------------- 1 | open($upload_dir.$filename) === true) 6 | { 7 | $zip->extractTo($dst_dir); 8 | $zip->close(); 9 | } 10 | 11 | ?> -------------------------------------------------------------------------------- /vulns/zip-extract.php: -------------------------------------------------------------------------------- 1 | checkDroit('parameters_all')) { 7 | $_SESSION['erreur'] = 'droitsInsuffisants'; 8 | header('Location: index.php'); 9 | exit; 10 | } 11 | 12 | $type=$_POST['type']; 13 | $type_restauration=$_POST['type_restauration']; 14 | $type_fichier_import_seul=$_POST['type_fichier_import']; 15 | $upload_dir = SAVE_DIR; // upload directory 16 | // Si on fait un upload de fichiers 17 | if ($type=='upload') 18 | { 19 | // Pour tous les fichiers, on tente de les uploader 20 | for($i=0; $igetConfigVars('upload_fichier_erreur_ecriture_repertoire')); 33 | echo $msg; 34 | exit; 35 | }else 36 | { 37 | // Si le fichier existe, on l'efface 38 | if (file_exists($upload_dir.$filename)) 39 | { 40 | @unlink($upload_dir.$filename); 41 | } 42 | // V�rification de la taille du fichier 43 | if ($fileSize > MAX_SIZE_UPLOAD) 44 | { 45 | $msg=preg_replace('/filename/',$filename,$smarty->getConfigVars('upload_fichier_erreur_taille')); 46 | echo $msg; 47 | exit; 48 | } 49 | 50 | // Chargement du fichier 51 | if(!(move_uploaded_file($tmp_dir,$upload_dir.$filename))) 52 | { 53 | $msg=preg_replace('/filename/',$filename,$smarty->getConfigVars('upload_fichier_erreur_chargement')); 54 | echo $msg; 55 | exit; 56 | }else 57 | { 58 | // V�rification du bon chargement du fichier 59 | if (!file_exists($upload_dir.$filename)) 60 | { 61 | $msg=preg_replace('/filename/',$filename,$smarty->getConfigVars('upload_fichier_erreur_chargement')); 62 | echo $msg; 63 | exit; 64 | }else 65 | { 66 | @mkdir($dest_dir); 67 | $info = pathinfo($upload_dir.$filename); 68 | 69 | // Test si c'est une archive on l'extrait 70 | if ($type_restauration=="sauvegarde" && $info["extension"] == "zip") 71 | { 72 | // Extraction de l'archive 73 | $zip = new ZipArchive(); 74 | if($zip->open($upload_dir.$filename) === true) 75 | { 76 | $zip->extractTo($dest_dir); 77 | $zip->close(); 78 | } else { 79 | @unlink($upload_dir.$filename); 80 | $msg=preg_replace('/filename/',$filename,$smarty->getConfigVars('erreur_extraction_sauvegarde')); 81 | echo $msg; 82 | exit; 83 | exit; 84 | } 85 | 86 | ... 87 | 88 | } 89 | 90 | ... 91 | 92 | } 93 | } 94 | } 95 | } 96 | } 97 | ?> --------------------------------------------------------------------------------