Semgrep rules to replace this script
parent
561726732e
commit
e6fcd0d3ca
15
README.md
15
README.md
|
@ -1,7 +1,12 @@
|
|||
# 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)
|
||||
# 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
|
||||
|
||||
![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)
|
||||
|
||||
|
||||
:warning: **Deprecated**, you should use semgrep rules instead of this script: `semgrep --config=./semgrep/ vulns/*.php`
|
||||
Most of the semgrep rules provided in this repository are from https://github.com/returntocorp/semgrep-rules
|
||||
|
||||
|
||||
Basic script to detect vulnerabilities into a PHP source code, it is using Regular Expression to find sinkholes.
|
||||
|
||||
```bash
|
||||
|
@ -17,16 +22,16 @@ optional arguments:
|
|||
|
||||
# Example
|
||||
╭─ 👻 swissky@crashlab: ~/Github/PHP_Code_Static_Analysis ‹master*›
|
||||
╰─$ python3 index.py --dir test
|
||||
╰─$ python3 index.py --dir vulns
|
||||
------------------------------------------------------------
|
||||
Analyzing 'test' source code
|
||||
Analyzing 'vulns' source code
|
||||
------------------------------------------------------------
|
||||
Potential vulnerability found : File Inclusion
|
||||
Line 19 in test/include.php
|
||||
Line 19 in vulns/include.php
|
||||
Code : include($_GET['patisserie'])
|
||||
------------------------------------------------------------
|
||||
Potential vulnerability found : Insecure E-mail
|
||||
Line 2 in test/mail.php
|
||||
Line 2 in vulns/mail.php
|
||||
Code : mail($dest, "subject", "message", "", "-f" . $_GET['from'])
|
||||
Declared at line 1 : $dest = $_GET['who'];
|
||||
```
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
rules:
|
||||
- id: assert-use
|
||||
patterns:
|
||||
- pattern: assert($ASSERT, ...);
|
||||
# - pattern-not: assert(<... $ASSERT ...>, ...); - https://github.com/returntocorp/semgrep/issues/2035
|
||||
- pattern-not: assert("...", ...);
|
||||
message: >-
|
||||
Calling assert with user input is equivalent to eval'ing.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/function.assert
|
||||
- https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/AssertsSniff.php
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,14 @@
|
|||
rules:
|
||||
- id: backticks-use
|
||||
pattern: "`...`;"
|
||||
message: >-
|
||||
Backticks use may lead to command injection vulnerabilities.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/language.operators.execution.php
|
||||
- https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/BackticksSniff.php
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,23 @@
|
|||
rules:
|
||||
- id: curl-ssl-verifypeer-off
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
$ARG = $IS_VERIFIED;
|
||||
...
|
||||
curl_setopt(..., CURLOPT_SSL_VERIFYPEER, $ARG);
|
||||
- pattern: curl_setopt(..., CURLOPT_SSL_VERIFYPEER, $IS_VERIFIED)
|
||||
- metavariable-regex:
|
||||
metavariable: $IS_VERIFIED
|
||||
regex: 0|false|null
|
||||
message: >-
|
||||
SSL verification is disabled but should not be (currently CURLOPT_SSL_VERIFYPEER=
|
||||
$IS_VERIFIED)
|
||||
metadata:
|
||||
references:
|
||||
- https://www.saotn.org/dont-turn-off-curlopt_ssl_verifypeer-fix-php-configuration/
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,28 @@
|
|||
rules:
|
||||
- id: extract-user-data
|
||||
mode: taint
|
||||
pattern-sources:
|
||||
- pattern-either:
|
||||
- pattern: $_GET[...]
|
||||
- pattern: $_FILES[...]
|
||||
- pattern: $_POST[...]
|
||||
pattern-sinks:
|
||||
- pattern: extract(...)
|
||||
pattern-sanitizers:
|
||||
- pattern: extract($VAR, EXTR_SKIP,...)
|
||||
message: Do not call 'extract()' on user-controllable data. If you must, then you
|
||||
must also provide the EXTR_SKIP flag to prevent overwriting existing variables.
|
||||
languages:
|
||||
- php
|
||||
metadata:
|
||||
license: MIT
|
||||
category: security
|
||||
cwe: 'CWE-502: Deserialization of Untrusted Data'
|
||||
owasp:
|
||||
- A08:2021 - Software and Data Integrity Failures
|
||||
- A08:2017 - Insecure Deserialization
|
||||
technology:
|
||||
- php
|
||||
references:
|
||||
- https://www.php.net/manual/en/function.extract.php#refsect1-function.extract-notes
|
||||
severity: ERROR
|
|
@ -0,0 +1,13 @@
|
|||
rules:
|
||||
- id: detected-generic-api-key
|
||||
pattern-regex: |-
|
||||
[aA][pP][iI]_?[kK][eE][yY].*['|"]?[0-9a-zA-Z]{32,45}['|"]?
|
||||
languages: [regex]
|
||||
message: Generic API Key detected
|
||||
severity: ERROR
|
||||
metadata:
|
||||
source-rule-url: https://github.com/dxa4481/truffleHogRegexes/blob/master/truffleHogRegexes/regexes.json
|
||||
category: security
|
||||
technology:
|
||||
- secrets
|
||||
confidence: MEDIUM
|
|
@ -0,0 +1,13 @@
|
|||
rules:
|
||||
- id: detected-generic-secret
|
||||
pattern-regex: |-
|
||||
[sS][eE][cC][rR][eE][tT][:= \t]*['|\"]?[0-9a-zA-Z]{32,45}['|\"]?
|
||||
languages: [regex]
|
||||
message: Generic Secret detected
|
||||
severity: ERROR
|
||||
metadata:
|
||||
source-rule-url: https://github.com/dxa4481/truffleHogRegexes/blob/master/truffleHogRegexes/regexes.json
|
||||
category: security
|
||||
technology:
|
||||
- secrets
|
||||
confidence: MEDIUM
|
|
@ -0,0 +1,27 @@
|
|||
rules:
|
||||
- id: detected-private-key
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- patterns:
|
||||
- pattern:
|
||||
-----BEGIN $TYPE PRIVATE KEY-----
|
||||
$KEY
|
||||
- metavariable-regex:
|
||||
metavariable: $TYPE
|
||||
regex: (?i)([dr]sa|ec|openssh|encrypted)?
|
||||
- patterns:
|
||||
- pattern: |
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
$KEY
|
||||
- metavariable-analysis:
|
||||
metavariable: $KEY
|
||||
analyzer: entropy
|
||||
languages: [generic]
|
||||
message: Private Key detected. This is a sensitive credential and should not be hardcoded here. Instead, store this in a separate, private file.
|
||||
severity: ERROR
|
||||
metadata:
|
||||
source-rule-url: https://github.com/grab/secret-scanner/blob/master/scanner/signatures/pattern.go
|
||||
category: security
|
||||
technology:
|
||||
- secrets
|
||||
confidence: MEDIUM
|
|
@ -0,0 +1,15 @@
|
|||
rules:
|
||||
- id: detected-username-and-password-in-uri
|
||||
patterns:
|
||||
- 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]+)
|
||||
languages:
|
||||
- regex
|
||||
message: Username and password in URI detected
|
||||
severity: ERROR
|
||||
metadata:
|
||||
source-rule-url: https://github.com/grab/secret-scanner/blob/master/scanner/signatures/pattern.go
|
||||
category: security
|
||||
technology:
|
||||
- secrets
|
||||
confidence: MEDIUM
|
||||
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
|
|
@ -0,0 +1,34 @@
|
|||
rules:
|
||||
- id: doctrine-dbal-dangerous-query
|
||||
languages:
|
||||
- php
|
||||
message:
|
||||
Detected string concatenation with a non-literal variable in a Doctrine DBAL query method. This could lead to SQL
|
||||
injection if the variable is user-controlled and not properly sanitized. In order to prevent SQL injection, used parameterized
|
||||
queries or prepared statements instead.
|
||||
metadata:
|
||||
category: security
|
||||
cwe: "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')"
|
||||
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
|
||||
owasp: "A1: Injection"
|
||||
references:
|
||||
- https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/security.html
|
||||
- https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
|
||||
technology:
|
||||
- doctrine
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: $CONNECTION->prepare($QUERY,...)
|
||||
- pattern: $CONNECTION->createQuery($QUERY,...)
|
||||
- pattern: $CONNECTION->executeQuery($QUERY,...)
|
||||
- pattern-either:
|
||||
- pattern-inside: |
|
||||
use Doctrine\DBAL\Connection;
|
||||
...
|
||||
- pattern-inside: |
|
||||
$CONNECTION = $SMTH->getConnection(...);
|
||||
...
|
||||
- pattern-not: $CONNECTION->prepare("...",...)
|
||||
- pattern-not: $CONNECTION->createQuery("...",...)
|
||||
- pattern-not: $CONNECTION->executeQuery("...",...)
|
||||
severity: WARNING
|
|
@ -0,0 +1,61 @@
|
|||
rules:
|
||||
- id: doctrine-orm-dangerous-query
|
||||
languages:
|
||||
- php
|
||||
message: >-
|
||||
`$QUERY` Detected string concatenation with a non-literal variable in a Doctrine
|
||||
QueryBuilder method. This could lead to SQL injection if the variable is
|
||||
user-controlled and not properly sanitized. In order to prevent SQL
|
||||
injection, used parameterized queries or prepared statements instead.
|
||||
metadata:
|
||||
category: security
|
||||
cwe: "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')"
|
||||
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
|
||||
owasp: "A1: Injection"
|
||||
references:
|
||||
- https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/query-builder.html#security-safely-preventing-sql-injection
|
||||
- https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
|
||||
technology:
|
||||
- doctrine
|
||||
mode: taint
|
||||
pattern-sinks:
|
||||
- patterns:
|
||||
- pattern: $SINK
|
||||
- pattern-either:
|
||||
- pattern-inside: $QUERY->add(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->select(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->addSelect(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->delete(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->update(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->insert(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->from(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->join(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->innerJoin(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->leftJoin(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->rightJoin(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->where(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->andWhere(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->orWhere(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->groupBy(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->addGroupBy(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->having(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->andHaving(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->orHaving(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->orderBy(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->addOrderBy(...,$SINK,...)
|
||||
- pattern-inside: $QUERY->set($SINK,...)
|
||||
- pattern-inside: $QUERY->setValue($SINK,...)
|
||||
- pattern-either:
|
||||
- pattern-inside: |
|
||||
$Q = $X->createQueryBuilder();
|
||||
...
|
||||
- pattern-inside: |
|
||||
$Q = new QueryBuilder(...);
|
||||
...
|
||||
pattern-sources:
|
||||
- patterns:
|
||||
- pattern-either:
|
||||
- pattern: sprintf(...)
|
||||
- pattern: |
|
||||
"...".$SMTH
|
||||
severity: WARNING
|
|
@ -0,0 +1,16 @@
|
|||
rules:
|
||||
- id: eval-use
|
||||
patterns:
|
||||
- pattern: eval(...);
|
||||
- pattern-not: eval('...');
|
||||
message: >-
|
||||
Evaluating non-constant commands. This can lead to command injection.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/function.eval
|
||||
- https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/NoEvalsSniff.php
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,18 @@
|
|||
rules:
|
||||
- id: exec-use
|
||||
patterns:
|
||||
- pattern: $FUNC(...);
|
||||
- pattern-not: $FUNC('...', ...);
|
||||
- metavariable-regex:
|
||||
metavariable: $FUNC
|
||||
regex: exec|passthru|proc_open|popen|shell_exec|system|pcntl_exec|expect_popen
|
||||
message: >-
|
||||
Executing non-constant commands. This can lead to command injection.
|
||||
metadata:
|
||||
references:
|
||||
- https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/SystemExecFunctionsSniff.php
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,21 @@
|
|||
rules:
|
||||
- id: file-inclusion
|
||||
patterns:
|
||||
- pattern: $FUNC(...);
|
||||
- pattern-not: $FUNC("...");
|
||||
- pattern-not: $FUNC(__DIR__ . "...");
|
||||
- metavariable-regex:
|
||||
metavariable: $FUNC
|
||||
regex: \b(include|include_once|require|require_once|virtual)\b
|
||||
message: >-
|
||||
Detected non-constant file inclusion. This can lead to local file inclusion (LFI) or remote file inclusion (RFI) if user input reaches this statement. LFI and RFI 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.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/function.include.php
|
||||
- https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/EasyRFISniff.php
|
||||
- https://en.wikipedia.org/wiki/File_inclusion_vulnerability#Types_of_Inclusion
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,14 @@
|
|||
rules:
|
||||
- id: file-upload-use
|
||||
patterns:
|
||||
- pattern: move_uploaded_file(...,...)
|
||||
message: >-
|
||||
Moves an uploaded file to a new location. This can lead to command injection.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/function.move-uploaded-file
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,18 @@
|
|||
rules:
|
||||
- id: ftp-use
|
||||
patterns:
|
||||
- pattern: $FUNC(...);
|
||||
- metavariable-regex:
|
||||
metavariable: $FUNC
|
||||
regex: ftp_.+
|
||||
message: >-
|
||||
FTP allows for unencrypted file transfers. Consider using an encrypted alternative.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/intro.ftp.php
|
||||
- https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/FringeFunctionsSniff.php
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,33 @@
|
|||
rules:
|
||||
- id: laravel-api-route-sql-injection
|
||||
mode: taint
|
||||
pattern-sources:
|
||||
- patterns:
|
||||
- pattern: $ARG
|
||||
- pattern-inside: |
|
||||
Route::$METHOD($ROUTE_NAME, function(...,$ARG,...){...})
|
||||
pattern-sanitizers:
|
||||
- patterns:
|
||||
- pattern: |
|
||||
DB::raw("...",[...])
|
||||
pattern-sinks:
|
||||
- patterns:
|
||||
- pattern: |
|
||||
DB::raw(...)
|
||||
message: HTTP method [$METHOD] to Laravel route $ROUTE_NAME is vulnerable to SQL
|
||||
injection via string concatentation or unsafe interpolation.
|
||||
languages:
|
||||
- php
|
||||
severity: WARNING
|
||||
metadata:
|
||||
category: security
|
||||
cwe: 'CWE-89: Improper Neutralization of Special Elements used in an SQL Command
|
||||
(''SQL Injection'')'
|
||||
owasp:
|
||||
- A01:2017 - Injection
|
||||
- A03:2021 - Injection
|
||||
references:
|
||||
- https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Laravel_Cheat_Sheet.md
|
||||
technology:
|
||||
- php
|
||||
- laravel
|
|
@ -0,0 +1,27 @@
|
|||
rules:
|
||||
- id: laravel-blade-form-missing-csrf
|
||||
patterns:
|
||||
- pattern: |
|
||||
<form ... method="POST" ...>...</form>
|
||||
- pattern-not: |
|
||||
<form ... method="POST" ...>
|
||||
@csrf
|
||||
...
|
||||
</form>
|
||||
message: Found a Blade form POST definition without the `@csrf` decorator. State-changing
|
||||
operations using simple HTTP content types should include an antiforgery token.
|
||||
languages:
|
||||
- generic
|
||||
severity: ERROR
|
||||
paths:
|
||||
include:
|
||||
- '*.blade.php'
|
||||
metadata:
|
||||
technology:
|
||||
- php
|
||||
- laravel
|
||||
- blade
|
||||
category: security
|
||||
cwe: 'CWE-352: Cross-Site Request Forgery (CSRF)'
|
||||
references:
|
||||
- https://laravel.com/docs/9.x/blade#csrf-field
|
|
@ -0,0 +1,26 @@
|
|||
rules:
|
||||
- id: laravel-dangerous-model-construction
|
||||
patterns:
|
||||
- pattern: |
|
||||
$guarded = [];
|
||||
- pattern-inside: |
|
||||
class $CLASS extends Model {
|
||||
...
|
||||
}
|
||||
message: Setting `$guarded` to an empty array allows mass assignment to every property
|
||||
in a Laravel model. This explicitly overrides Eloquent's safe-by-default mass
|
||||
assignment protections.
|
||||
languages:
|
||||
- php
|
||||
metadata:
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
- laravel
|
||||
- eloquent
|
||||
references:
|
||||
- https://laravel.com/docs/9.x/eloquent#allowing-mass-assignment
|
||||
- https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Laravel_Cheat_Sheet.md
|
||||
cwe: 'CWE-915: Improperly Controlled Modification of Dynamically-Determined Object
|
||||
Attributes'
|
||||
severity: ERROR
|
|
@ -0,0 +1,122 @@
|
|||
|
||||
rules:
|
||||
- id: laravel-sql-injection
|
||||
metadata:
|
||||
owasp: 'A3: Injection'
|
||||
cwe: "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')"
|
||||
category: security
|
||||
technology:
|
||||
- laravel
|
||||
references:
|
||||
- https://laravel.com/docs/8.x/queries
|
||||
severity: WARNING
|
||||
message: >-
|
||||
Detected a SQL query based on user input.
|
||||
This could lead to SQL injection, which could potentially result in sensitive data being exfiltrated by attackers.
|
||||
Instead, use parameterized queries and prepared statements.
|
||||
languages: [php]
|
||||
mode: taint
|
||||
pattern-sources:
|
||||
- patterns:
|
||||
- pattern-either:
|
||||
- pattern: $_GET
|
||||
- pattern: $_POST
|
||||
- pattern: $_COOKIE
|
||||
- pattern: $_REQUEST
|
||||
- pattern: $_SERVER
|
||||
pattern-sinks:
|
||||
- patterns:
|
||||
- pattern-either:
|
||||
- patterns:
|
||||
- pattern: $SQL
|
||||
- pattern-either:
|
||||
- pattern-inside: DB::table(...)->whereRaw($SQL, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereRaw($SQL, ...)
|
||||
- pattern-inside: DB::table(...)->groupByRaw($SQL, ...)
|
||||
- pattern-inside: DB::table(...)->havingRaw($SQL, ...)
|
||||
- pattern-inside: DB::table(...)->orHavingRaw($SQL, ...)
|
||||
- pattern-inside: DB::table(...)->orderByRaw($SQL, ...)
|
||||
- patterns:
|
||||
- pattern: $EXPRESSION
|
||||
- pattern-either:
|
||||
- pattern-inside: DB::table(...)->selectRaw($EXPRESSION, ...)
|
||||
- pattern-inside: DB::table(...)->fromRaw($EXPRESSION, ...)
|
||||
- patterns:
|
||||
- pattern: $COLUMNS
|
||||
- pattern-either:
|
||||
- pattern-inside: DB::table(...)->whereNull($COLUMNS, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereNull($COLUMN)
|
||||
- pattern-inside: DB::table(...)->whereNotNull($COLUMNS, ...)
|
||||
- pattern-inside: DB::table(...)->whereRowValues($COLUMNS, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereRowValues($COLUMNS, ...)
|
||||
- pattern-inside: DB::table(...)->find($ID, $COLUMNS)
|
||||
- pattern-inside: DB::table(...)->paginate($PERPAGE, $COLUMNS, ...)
|
||||
- pattern-inside: DB::table(...)->simplePaginate($PERPAGE, $COLUMNS, ...)
|
||||
- pattern-inside: DB::table(...)->cursorPaginate($PERPAGE, $COLUMNS, ...)
|
||||
- pattern-inside: DB::table(...)->getCountForPagination($COLUMNS)
|
||||
- pattern-inside: DB::table(...)->aggregate($FUNCTION, $COLUMNS)
|
||||
- pattern-inside: DB::table(...)->numericAggregate($FUNCTION, $COLUMNS)
|
||||
- pattern-inside: DB::table(...)->insertUsing($COLUMNS, ...)
|
||||
- pattern-inside: DB::table(...)->select($COLUMNS)
|
||||
- pattern-inside: DB::table(...)->get($COLUMNS)
|
||||
- pattern-inside: DB::table(...)->count($COLUMNS)
|
||||
- patterns:
|
||||
- pattern: $COLUMN
|
||||
- pattern-either:
|
||||
- pattern-inside: DB::table(...)->whereIn($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereIn($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->whereNotIn($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereNotIn($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->whereIntegerInRaw($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereIntegerInRaw($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->whereIntegerNotInRaw($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereIntegerNotInRaw($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->whereBetweenColumns($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereBetween($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereBetweenColumns($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->whereNotBetween($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->whereNotBetweenColumns($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereNotBetween($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereNotBetweenColumns($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereNotNull($COLUMN)
|
||||
- pattern-inside: DB::table(...)->whereDate($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereDate($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->whereTime($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereTime($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->whereDay($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereDay($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->whereMonth($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereMonth($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->whereYear($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereYear($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->whereJsonContains($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereJsonContains($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->whereJsonDoesntContain($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereJsonDoesntContain($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->whereJsonLength($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhereJsonLength($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->having($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orHaving($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->havingBetween($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orderBy($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orderByDesc($COLUMN)
|
||||
- pattern-inside: DB::table(...)->latest($COLUMN)
|
||||
- pattern-inside: DB::table(...)->oldest($COLUMN)
|
||||
- pattern-inside: DB::table(...)->forPageBeforeId($PERPAGE, $LASTID, $COLUMN)
|
||||
- pattern-inside: DB::table(...)->forPageAfterId($PERPAGE, $LASTID, $COLUMN)
|
||||
- pattern-inside: DB::table(...)->value($COLUMN)
|
||||
- pattern-inside: DB::table(...)->pluck($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->implode($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->min($COLUMN)
|
||||
- pattern-inside: DB::table(...)->max($COLUMN)
|
||||
- pattern-inside: DB::table(...)->sum($COLUMN)
|
||||
- pattern-inside: DB::table(...)->avg($COLUMN)
|
||||
- pattern-inside: DB::table(...)->average($COLUMN)
|
||||
- pattern-inside: DB::table(...)->increment($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->decrement($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->where($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->orWhere($COLUMN, ...)
|
||||
- pattern-inside: DB::table(...)->addSelect($COLUMN)
|
||||
- patterns:
|
||||
- pattern: $QUERY
|
||||
- pattern-inside: DB::unprepared($QUERY)
|
|
@ -0,0 +1,29 @@
|
|||
rules:
|
||||
- id: laravel-unsafe-validator
|
||||
mode: taint
|
||||
pattern-sources:
|
||||
- patterns:
|
||||
- pattern: $R
|
||||
- pattern-inside: |
|
||||
public function $F(...,Request $R,...){...}
|
||||
pattern-sinks:
|
||||
- patterns:
|
||||
- pattern: |
|
||||
Rule::unique($...X)->ignore(...)
|
||||
message: Found a request argument passed to an `ignore()` definition in a Rule constraint. This
|
||||
can lead to SQL injection.
|
||||
languages:
|
||||
- php
|
||||
severity: ERROR
|
||||
metadata:
|
||||
category: security
|
||||
cwe: 'CWE-89: Improper Neutralization of Special Elements used in an SQL Command
|
||||
(''SQL Injection'')'
|
||||
owasp:
|
||||
- A03:2021 - Injection
|
||||
- A01:2017 - Injection
|
||||
technology:
|
||||
- php
|
||||
- laravel
|
||||
references:
|
||||
- https://laravel.com/docs/9.x/validation#rule-unique
|
|
@ -0,0 +1,23 @@
|
|||
rules:
|
||||
- id: ldap-bind-without-password
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: ldap_bind($LDAP, $DN, NULL)
|
||||
- pattern: ldap_bind($LDAP, $DN, '')
|
||||
- patterns:
|
||||
- pattern: ldap_bind(...)
|
||||
- pattern-not: ldap_bind($LDAP, $DN, $PASSWORD)
|
||||
message: >-
|
||||
Detected anonymous LDAP bind.
|
||||
This permits anonymous users to execute LDAP statements.
|
||||
Consider enforcing authentication for LDAP.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/ru/function.ldap-bind.php
|
||||
cwe: "CWE-287: Improper Authentication"
|
||||
owasp: "A2: Broken Authentication"
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: WARNING
|
|
@ -0,0 +1,18 @@
|
|||
rules:
|
||||
- id: mb-ereg-replace-eval
|
||||
patterns:
|
||||
- pattern: mb_ereg_replace($PATTERN, $REPL, $STR, $OPTIONS);
|
||||
- pattern-not: mb_ereg_replace($PATTERN, $REPL, $STR, "...");
|
||||
message: >-
|
||||
Calling mb_ereg_replace with user input in the options can lead to arbitrary
|
||||
code execution. The eval modifier (`e`) evaluates the replacement argument
|
||||
as code.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/function.mb-ereg-replace.php
|
||||
- https://www.php.net/manual/en/function.mb-regex-set-options.php
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,18 @@
|
|||
rules:
|
||||
- id: mb-eregi-replace-eval
|
||||
patterns:
|
||||
- pattern: mb_eregi_replace($PATTERN, $REPL, $STR, $OPTIONS);
|
||||
- pattern-not: mb_eregi_replace($PATTERN, $REPL, $STR, "...");
|
||||
message: >-
|
||||
Calling mb_eregi_replace with user input in the options can lead to arbitrary
|
||||
code execution. The eval modifier (`e`) evaluates the replacement argument
|
||||
as code.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/function.mb-ereg-replace.php
|
||||
- https://www.php.net/manual/en/function.mb-regex-set-options.php
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,19 @@
|
|||
rules:
|
||||
- id: mcrypt-use
|
||||
patterns:
|
||||
- pattern: $FUNC(...);
|
||||
- metavariable-regex:
|
||||
metavariable: $FUNC
|
||||
regex: (mcrypt_|mdecrypt_).+
|
||||
message: >-
|
||||
Mcrypt functionality has been deprecated and/or removed in recent PHP
|
||||
versions. Consider using Sodium or OpenSSL.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/intro.mcrypt.php
|
||||
- https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/CryptoFunctionsSniff.php
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,22 @@
|
|||
rules:
|
||||
- id: md5-loose-equality
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: $X == $FUNC(...)
|
||||
- pattern: $FUNC(...) == $X
|
||||
- pattern: $FUNC(...) == $FUNC(...)
|
||||
- metavariable-regex:
|
||||
metavariable: $FUNC
|
||||
regex: md5|md5_file
|
||||
message: >-
|
||||
Make sure comparisons involving md5 values are strict (use `===` not `==`) to
|
||||
avoid type juggling issues
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/types.comparisons.php
|
||||
- https://www.whitehatsec.com/blog/magic-hashes/
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,35 @@
|
|||
rules:
|
||||
- id: md5-used-as-password
|
||||
severity: WARNING
|
||||
message: >-
|
||||
It looks like MD5 is used as a password hash. MD5 is not considered a
|
||||
secure password hash because it can be cracked by an attacker in a short
|
||||
amount of time. Use a suitable password hashing function such as bcrypt.
|
||||
You can use `password_hash($PASSWORD, PASSWORD_BCRYPT, $OPTIONS);`.
|
||||
languages: [php]
|
||||
metadata:
|
||||
cwe: "CWE-327: Use of a Broken or Risky Cryptographic Algorithm"
|
||||
owasp:
|
||||
- A02:2017 - Broken Authentication
|
||||
- A02:2021 - Cryptographic Failures
|
||||
references:
|
||||
- https://tools.ietf.org/html/rfc6151
|
||||
- https://crypto.stackexchange.com/questions/44151/how-does-the-flame-malware-take-advantage-of-md5-collision
|
||||
- https://security.stackexchange.com/questions/211/how-to-securely-hash-passwords
|
||||
- https://github.com/returntocorp/semgrep-rules/issues/1609
|
||||
- https://www.php.net/password_hash
|
||||
category: security
|
||||
technology:
|
||||
- md5
|
||||
mode: taint
|
||||
pattern-sources:
|
||||
- patterns:
|
||||
- pattern-either:
|
||||
- pattern: md5(...)
|
||||
- pattern: hash('md5', ...)
|
||||
pattern-sinks:
|
||||
- patterns:
|
||||
- pattern: $FUNCTION(...)
|
||||
- metavariable-regex:
|
||||
metavariable: $FUNCTION
|
||||
regex: (?i)(.*password.*)
|
|
@ -0,0 +1,21 @@
|
|||
rules:
|
||||
- id: non-literal-header
|
||||
patterns:
|
||||
- pattern: header(...)
|
||||
- pattern-not: header("...",...)
|
||||
message: >-
|
||||
Using user input when setting headers with `header()` is potentially dangerous.
|
||||
This could allow an attacker to inject a new line and add a new header into the
|
||||
response.
|
||||
This is called HTTP response splitting.
|
||||
To fix, do not allow whitespace inside `header()`: '[^\s]+'.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/ru/function.header.php
|
||||
- https://owasp.org/www-community/attacks/HTTP_Response_Splitting
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
cwe: "CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Response Splitting')"
|
||||
languages: [php]
|
||||
severity: WARNING
|
|
@ -0,0 +1,26 @@
|
|||
rules:
|
||||
- id: openssl-cbc-static-iv
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: openssl_encrypt($D, $M, $K, $FLAGS, "...",...);
|
||||
- pattern: openssl_decrypt($D, $M, $K, $FLAGS, "...",...);
|
||||
- metavariable-comparison:
|
||||
metavariable: $M
|
||||
comparison: re.match(".*-CBC",$M)
|
||||
message: Static IV used with AES in CBC mode. Static IVs enable chosen-plaintext
|
||||
attacks against encrypted data.
|
||||
languages:
|
||||
- php
|
||||
severity: ERROR
|
||||
metadata:
|
||||
cwe: 'CWE-329: Generation of Predictable IV with CBC Mode'
|
||||
references:
|
||||
- https://csrc.nist.gov/publications/detail/sp/800-38a/final
|
||||
owasp:
|
||||
- A02:2021 - Cryptographic Failures
|
||||
- A03:2017 - Sensitive Data Exposure
|
||||
technology:
|
||||
- php
|
||||
- openssl
|
||||
category: security
|
||||
license: MIT
|
|
@ -0,0 +1,69 @@
|
|||
rules:
|
||||
- id: openssl-decrypt-validate
|
||||
patterns:
|
||||
- pattern: openssl_decrypt(...);
|
||||
- pattern-not-inside: |
|
||||
$DECRYPTED_STRING = openssl_decrypt(...);
|
||||
...
|
||||
if($DECRYPTED_STRING === false){
|
||||
...
|
||||
}
|
||||
- pattern-not-inside: |
|
||||
$DECRYPTED_STRING = openssl_decrypt(...);
|
||||
...
|
||||
if($DECRYPTED_STRING == false){
|
||||
...
|
||||
}
|
||||
- pattern-not-inside: |
|
||||
$DECRYPTED_STRING = openssl_decrypt(...);
|
||||
...
|
||||
if(false === $DECRYPTED_STRING){
|
||||
...
|
||||
}
|
||||
- pattern-not-inside: |
|
||||
$DECRYPTED_STRING = openssl_decrypt(...);
|
||||
...
|
||||
if(false == $DECRYPTED_STRING){
|
||||
...
|
||||
}
|
||||
- pattern-not-inside: |
|
||||
$DECRYPTED_STRING = openssl_decrypt(...);
|
||||
...
|
||||
assertTrue(false !== $DECRYPTED_STRING,...);
|
||||
- pattern-not-inside: |
|
||||
$DECRYPTED_STRING = openssl_decrypt(...);
|
||||
...
|
||||
assertTrue($DECRYPTED_STRING !== false,...);
|
||||
- pattern-not-inside: |
|
||||
$DECRYPTED_STRING = openssl_decrypt(...);
|
||||
...
|
||||
$REFERENCE::assertTrue(false !== $DECRYPTED_STRING,...);
|
||||
- pattern-not-inside: |
|
||||
$DECRYPTED_STRING = openssl_decrypt(...);
|
||||
...
|
||||
$REFERENCE::assertTrue($DECRYPTED_STRING !== false,...);
|
||||
- pattern-not-inside: |
|
||||
$DECRYPTED_STRING = openssl_decrypt(...);
|
||||
...
|
||||
assert(false !== $DECRYPTED_STRING,...);
|
||||
- pattern-not-inside: |
|
||||
$DECRYPTED_STRING = openssl_decrypt(...);
|
||||
...
|
||||
assert($DECRYPTED_STRING !== false,...);
|
||||
message: The function `openssl_decrypt` returns either a string of the decrypted
|
||||
data on success or `false` on failure. If the failure case is not handled, this
|
||||
could lead to undefined behavior in your application. Please handle the case where
|
||||
`openssl_decrypt` returns `false`.
|
||||
languages:
|
||||
- php
|
||||
severity: WARNING
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/function.openssl-decrypt.php
|
||||
cwe: 'CWE-252: Unchecked Return Value'
|
||||
owasp:
|
||||
- A02:2021 - Cryptographic Failures
|
||||
technology:
|
||||
- php
|
||||
- openssl
|
||||
category: security
|
|
@ -0,0 +1,25 @@
|
|||
rules:
|
||||
- id: php-permissive-cors
|
||||
patterns:
|
||||
- pattern: header($VALUE,...)
|
||||
- pattern-either:
|
||||
- pattern: header("...",...)
|
||||
- pattern-inside: |
|
||||
$VALUE = "...";
|
||||
...
|
||||
- metavariable-regex:
|
||||
metavariable: $VALUE
|
||||
regex: (\'|\")\s*(Access-Control-Allow-Origin|access-control-allow-origin)\s*:\s*(\*)\s*(\'|\")
|
||||
message: >-
|
||||
Access-Control-Allow-Origin response header is set to "*".
|
||||
This will disable CORS Same Origin Policy restrictions.
|
||||
metadata:
|
||||
references:
|
||||
- https://developer.mozilla.org/ru/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
||||
owasp: "A6: Security Misconfiguration"
|
||||
cwe: "CWE-346: Origin Validation Error"
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: WARNING
|
|
@ -0,0 +1,14 @@
|
|||
rules:
|
||||
- id: phpinfo-use
|
||||
pattern: phpinfo(...);
|
||||
message: >-
|
||||
The 'phpinfo' function may reveal sensitive information about your environment.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/function.phpinfo
|
||||
- https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/PhpinfosSniff.php
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,19 @@
|
|||
rules:
|
||||
- id: preg-replace-eval
|
||||
patterns:
|
||||
- pattern: preg_replace(...);
|
||||
- pattern-not: preg_replace("...", ...);
|
||||
message: >-
|
||||
Calling preg_replace with user input in the pattern can lead to arbitrary
|
||||
code execution. The eval modifier (`/e`) evaluates the replacement argument
|
||||
as code.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/function.preg-replace.php
|
||||
- https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
|
||||
- https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/PregReplaceSniff.php
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,20 @@
|
|||
rules:
|
||||
- id: source-leak
|
||||
patterns:
|
||||
- pattern: $FUNC(...);
|
||||
- pattern-not: $FUNC("...");
|
||||
- pattern-not: $FUNC(__DIR__ . "...");
|
||||
- metavariable-regex:
|
||||
metavariable: $FUNC
|
||||
regex: \b(show_source|highlight_file)\b
|
||||
message: >-
|
||||
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.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/function.highlight-file
|
||||
- https://en.wikipedia.org/wiki/File_inclusion_vulnerability#Types_of_Inclusion
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -0,0 +1,30 @@
|
|||
rules:
|
||||
- id: symfony-csrf-protection-disabled
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: $X->createForm($TYPE, $TASK, [..., 'csrf_protection' => false, ...], ...)
|
||||
- pattern: $X->prependExtensionConfig('framework', [..., 'csrf_protection' => false, ...], ...)
|
||||
- pattern: $X->loadFromExtension('framework', [..., 'csrf_protection' => false, ...], ...)
|
||||
- pattern: $X->setDefaults([..., 'csrf_protection' => false, ...], ...)
|
||||
- patterns:
|
||||
- pattern-either:
|
||||
- pattern: $X->createForm($TYPE, $TASK, [..., 'csrf_protection' => $VAL, ...], ...)
|
||||
- pattern: $X->prependExtensionConfig('framework', [..., 'csrf_protection' => $VAL, ...], ...)
|
||||
- pattern: $X->loadFromExtension('framework', [..., 'csrf_protection' => $VAL, ...], ...)
|
||||
- pattern: $X->setDefaults([..., 'csrf_protection' => $VAL, ...], ...)
|
||||
- pattern-inside: |
|
||||
$VAL = false;
|
||||
...
|
||||
message: >-
|
||||
CSRF is disabled for this configuration. This is a security risk.
|
||||
Make sure that it is safe or consider setting `csrf_protection` property to `true`.
|
||||
metadata:
|
||||
references:
|
||||
- https://symfony.com/doc/current/security/csrf.html
|
||||
cwe: "CWE-352: Cross-Site Request Forgery (CSRF)"
|
||||
owasp: "A6: Security Misconfiguration"
|
||||
category: security
|
||||
technology:
|
||||
- symfony
|
||||
languages: [php]
|
||||
severity: WARNING
|
|
@ -0,0 +1,21 @@
|
|||
rules:
|
||||
- id: symfony-non-literal-redirect
|
||||
patterns:
|
||||
- pattern: $this->redirect(...)
|
||||
- pattern-not: $this->redirect("...")
|
||||
- pattern-not: $this->redirect()
|
||||
message: >-
|
||||
The `redirect()` method does not check its destination in any way. If you redirect to a URL provided by end-users, your
|
||||
application may be open to the unvalidated redirects security vulnerability.
|
||||
Consider using literal values or an allowlist to validate URLs.
|
||||
languages: [php]
|
||||
metadata:
|
||||
references:
|
||||
- https://symfony.com/doc/current/controller.html#redirecting
|
||||
- https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html
|
||||
owasp: "A1: Injection"
|
||||
cwe: "CWE-601: URL Redirection to Untrusted Site ('Open Redirect')"
|
||||
category: security
|
||||
technology:
|
||||
- symfony
|
||||
severity: WARNING
|
|
@ -0,0 +1,38 @@
|
|||
rules:
|
||||
- id: symfony-permissive-cors
|
||||
patterns:
|
||||
- pattern-inside: |
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
...
|
||||
- pattern-either:
|
||||
- patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
new Symfony\Component\HttpFoundation\Response($X, $Y, $HEADERS, ...)
|
||||
- pattern: new Response($X, $Y, $HEADERS, ...)
|
||||
- pattern-either:
|
||||
- pattern: new $R($X, $Y, [$KEY => $VALUE], ...)
|
||||
- pattern-inside: |
|
||||
$HEADERS = [$KEY => $VALUE];
|
||||
...
|
||||
- patterns:
|
||||
- pattern: $RES->headers->set($KEY, $VALUE)
|
||||
- metavariable-regex:
|
||||
metavariable: $KEY
|
||||
regex: (\'|\")\s*(Access-Control-Allow-Origin|access-control-allow-origin)\s*(\'|\")
|
||||
- metavariable-regex:
|
||||
metavariable: $VALUE
|
||||
regex: (\'|\")\s*(\*)\s*(\'|\")
|
||||
message: >-
|
||||
Access-Control-Allow-Origin response header is set to "*".
|
||||
This will disable CORS Same Origin Policy restrictions.
|
||||
metadata:
|
||||
references:
|
||||
- https://developer.mozilla.org/ru/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
||||
owasp: "A6: Security Misconfiguration"
|
||||
cwe: "CWE-346: Origin Validation Error"
|
||||
category: security
|
||||
technology:
|
||||
- symfony
|
||||
languages: [php]
|
||||
severity: WARNING
|
|
@ -0,0 +1,166 @@
|
|||
rules:
|
||||
- id: tainted-filename
|
||||
severity: WARNING
|
||||
message: >-
|
||||
File name based on user input risks server-side request forgery.
|
||||
metadata:
|
||||
technology:
|
||||
- php
|
||||
category: security
|
||||
cwe: "CWE-918: Server-Side Request Forgery (SSRF)"
|
||||
owasp:
|
||||
- A01:2017 - Injection
|
||||
- A10:2021 - Server-Side Request Forgery
|
||||
languages: [php]
|
||||
mode: taint
|
||||
pattern-sources:
|
||||
- patterns:
|
||||
- pattern-either:
|
||||
- pattern: $_GET
|
||||
- pattern: $_POST
|
||||
- pattern: $_COOKIE
|
||||
- pattern: $_REQUEST
|
||||
- pattern: $_SERVER
|
||||
pattern-sanitizers:
|
||||
- patterns:
|
||||
- pattern-either:
|
||||
- pattern-inside: basename($PATH, ...)
|
||||
- pattern-inside: linkinfo($PATH, ...)
|
||||
- pattern-inside: readlink($PATH, ...)
|
||||
- pattern-inside: realpath($PATH, ...)
|
||||
pattern-sinks:
|
||||
- patterns:
|
||||
- pattern-either:
|
||||
- pattern-inside: opcache_compile_file($FILENAME, ...)
|
||||
- pattern-inside: opcache_invalidate($FILENAME, ...)
|
||||
- pattern-inside: opcache_is_script_cached($FILENAME, ...)
|
||||
- pattern-inside: runkit7_import($FILENAME, ...)
|
||||
- pattern-inside: readline_read_history($FILENAME, ...)
|
||||
- pattern-inside: readline_write_history($FILENAME, ...)
|
||||
- pattern-inside: rar_open($FILENAME, ...)
|
||||
- pattern-inside: zip_open($FILENAME, ...)
|
||||
- pattern-inside: gzfile($FILENAME, ...)
|
||||
- pattern-inside: gzopen($FILENAME, ...)
|
||||
- pattern-inside: readgzfile($FILENAME, ...)
|
||||
- pattern-inside: hash_file($ALGO, $FILENAME, ...)
|
||||
- pattern-inside: hash_update_file($CONTEXT, $FILENAME, ...)
|
||||
- pattern-inside: pg_trace($FILENAME, ...)
|
||||
- pattern-inside: dio_open($FILENAME, ...)
|
||||
- pattern-inside: finfo_file($FINFO, $FILENAME, ...)
|
||||
- pattern-inside: mime_content_type($FILENAME, ...)
|
||||
- pattern-inside: chgrp($FILENAME, ...)
|
||||
- pattern-inside: chmod($FILENAME, ...)
|
||||
- pattern-inside: chown($FILENAME, ...)
|
||||
- pattern-inside: clearstatcache($CLEAR_REALPATH_CACHE, $FILENAME, ...)
|
||||
- pattern-inside: file_exists($FILENAME, ...)
|
||||
- pattern-inside: file_get_contents($FILENAME, ...)
|
||||
- pattern-inside: file_put_contents($FILENAME, ...)
|
||||
- pattern-inside: file($FILENAME, ...)
|
||||
- pattern-inside: fileatime($FILENAME, ...)
|
||||
- pattern-inside: filectime($FILENAME, ...)
|
||||
- pattern-inside: filegroup($FILENAME, ...)
|
||||
- pattern-inside: fileinode($FILENAME, ...)
|
||||
- pattern-inside: filemtime($FILENAME, ...)
|
||||
- pattern-inside: fileowner($FILENAME, ...)
|
||||
- pattern-inside: fileperms($FILENAME, ...)
|
||||
- pattern-inside: filesize($FILENAME, ...)
|
||||
- pattern-inside: filetype($FILENAME, ...)
|
||||
- pattern-inside: fnmatch($PATTERN, $FILENAME, ...)
|
||||
- pattern-inside: fopen($FILENAME, ...)
|
||||
- pattern-inside: is_dir($FILENAME, ...)
|
||||
- pattern-inside: is_executable($FILENAME, ...)
|
||||
- pattern-inside: is_file($FILENAME, ...)
|
||||
- pattern-inside: is_link($FILENAME, ...)
|
||||
- pattern-inside: is_readable($FILENAME, ...)
|
||||
- pattern-inside: is_uploaded_file($FILENAME, ...)
|
||||
- pattern-inside: is_writable($FILENAME, ...)
|
||||
- pattern-inside: lchgrp($FILENAME, ...)
|
||||
- pattern-inside: lchown($FILENAME, ...)
|
||||
- pattern-inside: lstat($FILENAME, ...)
|
||||
- pattern-inside: parse_ini_file($FILENAME, ...)
|
||||
- pattern-inside: readfile($FILENAME, ...)
|
||||
- pattern-inside: stat($FILENAME, ...)
|
||||
- pattern-inside: touch($FILENAME, ...)
|
||||
- pattern-inside: unlink($FILENAME, ...)
|
||||
- pattern-inside: xattr_get($FILENAME, ...)
|
||||
- pattern-inside: xattr_list($FILENAME, ...)
|
||||
- pattern-inside: xattr_remove($FILENAME, ...)
|
||||
- pattern-inside: xattr_set($FILENAME, ...)
|
||||
- pattern-inside: xattr_supported($FILENAME, ...)
|
||||
- pattern-inside: enchant_broker_request_pwl_dict($BROKER, $FILENAME, ...)
|
||||
- pattern-inside: pspell_config_personal($CONFIG, $FILENAME, ...)
|
||||
- pattern-inside: pspell_config_repl($CONFIG, $FILENAME, ...)
|
||||
- pattern-inside: pspell_new_personal($FILENAME, ...)
|
||||
- pattern-inside: exif_imagetype($FILENAME, ...)
|
||||
- pattern-inside: getimagesize($FILENAME, ...)
|
||||
- pattern-inside: image2wbmp($IMAGE, $FILENAME, ...)
|
||||
- pattern-inside: imagecreatefromavif($FILENAME, ...)
|
||||
- pattern-inside: imagecreatefrombmp($FILENAME, ...)
|
||||
- pattern-inside: imagecreatefromgd2($FILENAME, ...)
|
||||
- pattern-inside: imagecreatefromgd2part($FILENAME, ...)
|
||||
- pattern-inside: imagecreatefromgd($FILENAME, ...)
|
||||
- pattern-inside: imagecreatefromgif($FILENAME, ...)
|
||||
- pattern-inside: imagecreatefromjpeg($FILENAME, ...)
|
||||
- pattern-inside: imagecreatefrompng($FILENAME, ...)
|
||||
- pattern-inside: imagecreatefromtga($FILENAME, ...)
|
||||
- pattern-inside: imagecreatefromwbmp($FILENAME, ...)
|
||||
- pattern-inside: imagecreatefromwebp($FILENAME, ...)
|
||||
- pattern-inside: imagecreatefromxbm($FILENAME, ...)
|
||||
- pattern-inside: imagecreatefromxpm($FILENAME, ...)
|
||||
- pattern-inside: imageloadfont($FILENAME, ...)
|
||||
- pattern-inside: imagexbm($IMAGE, $FILENAME, ...)
|
||||
- pattern-inside: iptcembed($IPTC_DATA, $FILENAME, ...)
|
||||
- pattern-inside: mailparse_msg_extract_part_file($MIMEMAIL, $FILENAME, ...)
|
||||
- pattern-inside: mailparse_msg_extract_whole_part_file($MIMEMAIL, $FILENAME, ...)
|
||||
- pattern-inside: mailparse_msg_parse_file($FILENAME, ...)
|
||||
- pattern-inside: fdf_add_template($FDF_DOCUMENT, $NEWPAGE, $FILENAME, ...)
|
||||
- pattern-inside: fdf_get_ap($FDF_DOCUMENT, $FIELD, $FACE, $FILENAME, ...)
|
||||
- pattern-inside: fdf_open($FILENAME, ...)
|
||||
- pattern-inside: fdf_save($FDF_DOCUMENT, $FILENAME, ...)
|
||||
- pattern-inside: fdf_set_ap($FDF_DOCUMENT, $FIELD_NAME, $FACE, $FILENAME, ...)
|
||||
- pattern-inside: ps_add_launchlink($PSDOC, $LLX, $LLY, $URX, $URY, $FILENAME, ...)
|
||||
- pattern-inside: ps_add_pdflink($PSDOC, $LLX, $LLY, $URX, $URY, $FILENAME, ...)
|
||||
- pattern-inside: ps_open_file($PSDOC, $FILENAME, ...)
|
||||
- pattern-inside: ps_open_image_file($PSDOC, $TYPE, $FILENAME, ...)
|
||||
- pattern-inside: posix_access($FILENAME, ...)
|
||||
- pattern-inside: posix_mkfifo($FILENAME, ...)
|
||||
- pattern-inside: posix_mknod($FILENAME, ...)
|
||||
- pattern-inside: ftok($FILENAME, ...)
|
||||
- pattern-inside: fann_cascadetrain_on_file($ANN, $FILENAME, ...)
|
||||
- pattern-inside: fann_read_train_from_file($FILENAME, ...)
|
||||
- pattern-inside: fann_train_on_file($ANN, $FILENAME, ...)
|
||||
- pattern-inside: highlight_file($FILENAME, ...)
|
||||
- pattern-inside: php_strip_whitespace($FILENAME, ...)
|
||||
- pattern-inside: stream_resolve_include_path($FILENAME, ...)
|
||||
- pattern-inside: swoole_async_read($FILENAME, ...)
|
||||
- pattern-inside: swoole_async_readfile($FILENAME, ...)
|
||||
- pattern-inside: swoole_async_write($FILENAME, ...)
|
||||
- pattern-inside: swoole_async_writefile($FILENAME, ...)
|
||||
- pattern-inside: swoole_load_module($FILENAME, ...)
|
||||
- pattern-inside: tidy_parse_file($FILENAME, ...)
|
||||
- pattern-inside: tidy_repair_file($FILENAME, ...)
|
||||
- pattern-inside: get_meta_tags($FILENAME, ...)
|
||||
- pattern-inside: yaml_emit_file($FILENAME, ...)
|
||||
- pattern-inside: yaml_parse_file($FILENAME, ...)
|
||||
- pattern-inside: curl_file_create($FILENAME, ...)
|
||||
- pattern-inside: ftp_chmod($FTP, $PERMISSIONS, $FILENAME, ...)
|
||||
- pattern-inside: ftp_delete($FTP, $FILENAME, ...)
|
||||
- pattern-inside: ftp_mdtm($FTP, $FILENAME, ...)
|
||||
- pattern-inside: ftp_size($FTP, $FILENAME, ...)
|
||||
- pattern-inside: rrd_create($FILENAME, ...)
|
||||
- pattern-inside: rrd_fetch($FILENAME, ...)
|
||||
- pattern-inside: rrd_graph($FILENAME, ...)
|
||||
- pattern-inside: rrd_info($FILENAME, ...)
|
||||
- pattern-inside: rrd_last($FILENAME, ...)
|
||||
- pattern-inside: rrd_lastupdate($FILENAME, ...)
|
||||
- pattern-inside: rrd_tune($FILENAME, ...)
|
||||
- pattern-inside: rrd_update($FILENAME, ...)
|
||||
- pattern-inside: snmp_read_mib($FILENAME, ...)
|
||||
- pattern-inside: ssh2_sftp_chmod($SFTP, $FILENAME, ...)
|
||||
- pattern-inside: ssh2_sftp_realpath($SFTP, $FILENAME, ...)
|
||||
- pattern-inside: ssh2_sftp_unlink($SFTP, $FILENAME, ...)
|
||||
- pattern-inside: apache_lookup_uri($FILENAME, ...)
|
||||
- pattern-inside: md5_file($FILENAME, ...)
|
||||
- pattern-inside: sha1_file($FILENAME, ...)
|
||||
- pattern-inside: simplexml_load_file($FILENAME, ...)
|
||||
- pattern: $FILENAME
|
|
@ -0,0 +1,28 @@
|
|||
rules:
|
||||
- id: tainted-object-instantiation
|
||||
languages:
|
||||
- php
|
||||
severity: WARNING
|
||||
message: <-
|
||||
A new object is created where the class name is based on user input. This
|
||||
could lead to remote code execution, as it allows to instantiate any class in
|
||||
the application.
|
||||
metadata:
|
||||
cwe: "CWE-470: Use of Externally-Controlled Input to Select Classes or Code ('Unsafe Reflection')"
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
mode: taint
|
||||
pattern-sources:
|
||||
- patterns:
|
||||
- pattern-either:
|
||||
- pattern: $_GET
|
||||
- pattern: $_POST
|
||||
- pattern: $_COOKIE
|
||||
- pattern: $_REQUEST
|
||||
- pattern: $_SERVER
|
||||
pattern-sinks:
|
||||
- patterns:
|
||||
- pattern-either:
|
||||
- pattern-inside: new $SINK(...)
|
||||
- pattern: $SINK
|
|
@ -0,0 +1,58 @@
|
|||
rules:
|
||||
- id: tainted-sql-string
|
||||
languages:
|
||||
- php
|
||||
severity: ERROR
|
||||
message: User data flows into this manually-constructed SQL string. User data can
|
||||
be safely inserted into SQL strings using prepared statements or an object-relational
|
||||
mapper (ORM). Manually-constructed SQL strings is a possible indicator of SQL
|
||||
injection, which could let an attacker steal or manipulate data from the database.
|
||||
Instead, use prepared statements (`$mysqli->prepare("INSERT INTO test(id, label)
|
||||
VALUES (?, ?)");`) or a safe library.
|
||||
metadata:
|
||||
cwe: 'CWE-89: Improper Neutralization of Special Elements used in an SQL Command
|
||||
(''SQL Injection'')'
|
||||
owasp:
|
||||
- A10:2021
|
||||
- A01:2017
|
||||
references:
|
||||
- https://owasp.org/www-community/attacks/SQL_Injection
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
mode: taint
|
||||
pattern-sanitizers:
|
||||
- pattern-either:
|
||||
- pattern: mysqli_real_escape_string(...)
|
||||
- pattern: real_escape_string(...)
|
||||
- pattern: $MYSQLI->real_escape_string(...)
|
||||
pattern-sources:
|
||||
- patterns:
|
||||
- pattern-either:
|
||||
- pattern: $_GET
|
||||
- pattern: $_POST
|
||||
- pattern: $_COOKIE
|
||||
- pattern: $_REQUEST
|
||||
pattern-sinks:
|
||||
- pattern-either:
|
||||
- patterns:
|
||||
- pattern: |
|
||||
sprintf($SQLSTR, ...)
|
||||
- metavariable-regex:
|
||||
metavariable: $SQLSTR
|
||||
regex: .*\b(?i)(select|delete|insert|create|update|alter|drop)\b.*
|
||||
- patterns:
|
||||
- pattern: |
|
||||
"...{$EXPR}..."
|
||||
- pattern-regex: |
|
||||
.*\b(?i)(select|delete|insert|create|update|alter|drop)\b.*
|
||||
- patterns:
|
||||
- pattern: |
|
||||
"...$EXPR..."
|
||||
- pattern-regex: |
|
||||
.*\b(?i)(select|delete|insert|create|update|alter|drop)\b.*
|
||||
- patterns:
|
||||
- pattern: |
|
||||
"...".$EXPR
|
||||
- pattern-regex: |
|
||||
.*\b(?i)(select|delete|insert|create|update|alter|drop)\b.*
|
|
@ -0,0 +1,54 @@
|
|||
rules:
|
||||
- id: tainted-url-host
|
||||
languages:
|
||||
- php
|
||||
severity: WARNING
|
||||
message: >-
|
||||
User data flows into the host portion of this manually-constructed URL. This could allow an attacker to send data
|
||||
to their own server, potentially exposing sensitive data such as cookies or authorization information sent with this request.
|
||||
They could also probe internal servers or other resources that the server runnig this code can access. (This is called
|
||||
server-side request forgery, or SSRF.) Do not allow arbitrary hosts. Instead, create an allowlist for approved hosts hardcode
|
||||
the correct host.
|
||||
metadata:
|
||||
cwe: "CWE-918: Server-Side Request Forgery (SSRF)"
|
||||
owasp:
|
||||
- A10:2021
|
||||
- A01:2017
|
||||
references:
|
||||
- https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
|
||||
mode: taint
|
||||
pattern-sources:
|
||||
- patterns:
|
||||
- pattern-either:
|
||||
- pattern: $_GET
|
||||
- pattern: $_POST
|
||||
- pattern: $_COOKIE
|
||||
- pattern: $_REQUEST
|
||||
pattern-sinks:
|
||||
- pattern-either:
|
||||
- patterns:
|
||||
- pattern: |
|
||||
sprintf($URLSTR, ...)
|
||||
- metavariable-pattern:
|
||||
metavariable: $URLSTR
|
||||
language: generic
|
||||
pattern: $SCHEME://%s
|
||||
- patterns:
|
||||
- pattern: |
|
||||
"...{$EXPR}..."
|
||||
- pattern-regex: |
|
||||
.*://\{.*
|
||||
- patterns:
|
||||
- pattern: |
|
||||
"...$EXPR..."
|
||||
- pattern-regex: |
|
||||
.*://\$.*
|
||||
- patterns:
|
||||
- pattern: |
|
||||
"...".$EXPR
|
||||
- pattern-regex: |
|
||||
.*://["'].*
|
|
@ -0,0 +1,20 @@
|
|||
rules:
|
||||
- id: unlink-use
|
||||
patterns:
|
||||
- pattern: unlink(...)
|
||||
- pattern-not: unlink("...",...)
|
||||
message: >-
|
||||
Using user input when deleting files with `unlink()` is potentially dangerous.
|
||||
A malicious actor could use this to modify
|
||||
or access files they have no right to.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/function.unlink
|
||||
- https://owasp.org/www-project-top-ten/2017/A5_2017-Broken_Access_Control.html
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
owasp: "A5: Broken Access Control"
|
||||
cwe: "CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')"
|
||||
languages: [php]
|
||||
severity: WARNING
|
|
@ -0,0 +1,20 @@
|
|||
rules:
|
||||
- id: unserialize-use
|
||||
patterns:
|
||||
- pattern: unserialize(...)
|
||||
- pattern-not: unserialize("...",...)
|
||||
message: >-
|
||||
Calling `unserialize()` with user input in the pattern can lead to arbitrary code
|
||||
execution.
|
||||
Consider using JSON or structured data approaches (e.g. Google Protocol Buffers).
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/ru/function.unserialize.php
|
||||
- https://owasp.org/www-project-top-ten/2017/A8_2017-Insecure_Deserialization.html
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
owasp: "A8: Insecure Deserialization"
|
||||
cwe: "CWE-502: Deserialization of Untrusted Data"
|
||||
languages: [php]
|
||||
severity: WARNING
|
|
@ -0,0 +1,18 @@
|
|||
rules:
|
||||
- id: weak-crypto
|
||||
patterns:
|
||||
- pattern: $FUNC(...);
|
||||
- metavariable-regex:
|
||||
metavariable: $FUNC
|
||||
regex: crypt|md5|md5_file|sha1|sha1_file|str_rot13
|
||||
message: >-
|
||||
Detected usage of weak crypto function. Consider using stronger alternatives.
|
||||
metadata:
|
||||
references:
|
||||
- https://www.php.net/manual/en/book.sodium.php
|
||||
- https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/CryptoFunctionsSniff.php
|
||||
category: security
|
||||
technology:
|
||||
- php
|
||||
languages: [php]
|
||||
severity: ERROR
|
|
@ -1,24 +0,0 @@
|
|||
<html>
|
||||
<?php
|
||||
if(isset($_FILES['nom'])){
|
||||
$name = htmlentities($_FILES['nom']['name']);
|
||||
if(stristr($name, ".jpg")==true || stristr($name, ".png")==true){
|
||||
echo "<h3>The file ".$name." has been uploaded</h3>";
|
||||
echo "<a href='./index.php' id='button'>UPLOAD AGAIN</a><br>";
|
||||
}
|
||||
else{
|
||||
echo "<h3>Only JPG/PNG Files are allowed !</h3>";
|
||||
echo "<a href='./index.php' id='button'>RETRY</a>";
|
||||
}
|
||||
else{
|
||||
?>
|
||||
<form method="post" action="index.php" enctype="multipart/form-data">
|
||||
<div id='iconDl'>
|
||||
<input type="file" name="nom" id='upload' onchange='this.form.submit()' />
|
||||
</div>
|
||||
</form>
|
||||
<p>Click to upload</p>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
// ruleid: assert-use
|
||||
assert($user_input);
|
||||
|
||||
// ok: assert-use
|
||||
assert('2 > 1');
|
||||
|
||||
// todook: assert-use
|
||||
assert($user_input > 1);
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
echo `ping -n 3 {$user_input}`;
|
||||
|
||||
?>
|
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
|
||||
// ruleid: backticks-use
|
||||
echo `ping -n 3 {$user_input}`;
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, "http://www.example.com/");
|
||||
curl_setopt($ch, CURLOPT_HEADER, 0);
|
||||
|
||||
// ruleid: curl-ssl-verifypeer-off
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
|
||||
// ok: curl-ssl-verifypeer-off
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
<?php
|
||||
|
||||
/* Suppose that $var_array is an array returned from
|
||||
wddx_deserialize */
|
||||
|
||||
$size = "large";
|
||||
$var_array = array("color" => "blue",
|
||||
"size" => "medium",
|
||||
"shape" => "sphere");
|
||||
// ok: extract-user-data
|
||||
extract($var_array, EXTR_PREFIX_SAME, "wddx");
|
||||
|
||||
$bad = $_GET['some_param'];
|
||||
// ruleid:extract-user-data
|
||||
extract($bad, EXTR_PREFIX_SAME, "wddx");
|
||||
echo "$color, $size, $shape, $wddx_size\n";
|
||||
|
||||
$bad2 = $_FILES["/some/bad/path"];
|
||||
// ruleid:extract-user-data
|
||||
extract($bad2, EXTR_PREFIX_SAME, "wddx");
|
||||
|
||||
// ok: extract-user-data
|
||||
$ok = $_FILES["/some/bad/path"];
|
||||
extract($ok, EXTR_SKIP, "wddx");
|
||||
?>
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
class ProductRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function test1(int $price): array
|
||||
{
|
||||
$conn = $this->getEntityManager()->getConnection();
|
||||
|
||||
$sql = "SELECT * FROM product p WHERE p.price > " . $_GET['cur_price']. " ORDER BY p.price ASC";
|
||||
// ruleid: doctrine-dbal-dangerous-query
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->execute(['price' => $price]);
|
||||
|
||||
return $stmt->fetchAllAssociative();
|
||||
}
|
||||
|
||||
public function test2(): array
|
||||
{
|
||||
$conn = $this->getEntityManager()->getConnection();
|
||||
|
||||
// ruleid: doctrine-dbal-dangerous-query
|
||||
$query = $conn->createQuery("SELECT u FROM User u WHERE u.username = '" . $_GET['username'] . "'");
|
||||
$data = $query->getResult();
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function okTest1(int $price): array
|
||||
{
|
||||
$conn = $this->getEntityManager()->getConnection();
|
||||
$sql = "SELECT * FROM users WHERE username = ?";
|
||||
// ok: doctrine-dbal-dangerous-query
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->bindValue(1, $_GET['username']);
|
||||
$resultSet = $stmt->executeQuery();
|
||||
return $resultSet;
|
||||
}
|
||||
|
||||
public function okTest2(int $price): array
|
||||
{
|
||||
$conn = $this->foobar();
|
||||
$sql = "SELECT * FROM users WHERE username = ?";
|
||||
// ok: doctrine-dbal-dangerous-query
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->bindValue(1, $_GET['username']);
|
||||
$resultSet = $stmt->executeQuery();
|
||||
return $resultSet;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
function test1($input)
|
||||
{
|
||||
$queryBuilder = $conn->createQueryBuilder();
|
||||
|
||||
$queryBuilder
|
||||
->select('id', 'name')
|
||||
->from('users')
|
||||
// ruleid: doctrine-orm-dangerous-query
|
||||
->where('email = '.$input)
|
||||
;
|
||||
}
|
||||
|
||||
function test2($email, $input)
|
||||
{
|
||||
$queryBuilder = new QueryBuilder($this->connection);
|
||||
|
||||
$queryBuilder
|
||||
->select('id', 'name')
|
||||
->from('users')
|
||||
->where('email = ?')
|
||||
->setParameter(0, $email)
|
||||
// ruleid: doctrine-orm-dangerous-query
|
||||
->andWhere(sprintf('user = %s', $input))
|
||||
;
|
||||
}
|
||||
|
||||
function okTest1($input)
|
||||
{
|
||||
$queryBuilder = $conn->createQueryBuilder();
|
||||
|
||||
$queryBuilder
|
||||
->select('id', 'name')
|
||||
->from('users')
|
||||
// ok: doctrine-orm-dangerous-query
|
||||
->where('email = ?')
|
||||
->setParameter(0, $input)
|
||||
;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
// ruleid: eval-use
|
||||
eval($user_input);
|
||||
|
||||
// ok: eval-use
|
||||
eval('echo "OK"');
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
// ruleid: exec-use
|
||||
exec($user_input);
|
||||
|
||||
// ok: exec-use
|
||||
exec('whoami');
|
||||
|
||||
// ruleid: exec-use
|
||||
passthru($user_input);
|
||||
|
||||
// ruleid: exec-use
|
||||
$proc = proc_open($cmd, $descriptorspec, $pipes);
|
||||
|
||||
// ruleid: exec-use
|
||||
$handle = popen($user_input, "r");
|
||||
|
||||
// ruleid: exec-use
|
||||
$output = shell_exec($user_input);
|
||||
|
||||
// ruleid: exec-use
|
||||
$output = system($user_input, $retval);
|
||||
|
||||
// ruleid: exec-use
|
||||
pcntl_exec($path);
|
|
@ -15,4 +15,6 @@ $target = $_REQUEST['target'];
|
|||
if($target){
|
||||
if (stristr(php_uname('s'), 'Windows NT')) {
|
||||
$cmd = shell_exec( 'ping ' . $target );
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
// ruleid: file-inclusion
|
||||
include($user_input);
|
||||
|
||||
// ok: file-inclusion
|
||||
include('constant.php');
|
||||
|
||||
// ruleid: file-inclusion
|
||||
include_once($user_input);
|
||||
|
||||
// ok: file-inclusion
|
||||
include_once('constant.php');
|
||||
|
||||
// ruleid: file-inclusion
|
||||
require($user_input);
|
||||
|
||||
// ok: file-inclusion
|
||||
require('constant.php');
|
||||
|
||||
// ruleid: file-inclusion
|
||||
require_once($user_input);
|
||||
|
||||
// ok: file-inclusion
|
||||
require_once('constant.php');
|
||||
|
||||
// ruleid: file-inclusion
|
||||
include(__DIR__ . $user_input);
|
||||
|
||||
// ok: file-inclusion
|
||||
include(__DIR__ . 'constant.php');
|
||||
|
||||
// ok: file-inclusion
|
||||
include_safe(__DIR__ . $user_input);
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
// ruleid: ftp-use
|
||||
$conn_id = ftp_connect($ftp_server);
|
||||
|
||||
// ruleid: ftp-use
|
||||
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
|
||||
|
||||
// ok: ftp-use
|
||||
ssh2_scp_send($connection, '/local/filename', '/remote/filename', 0644);
|
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
// Comment
|
||||
phpinfo();
|
||||
?>
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
// https://www.cloudways.com/blog/laravel-security/
|
||||
Route::get('this-is-prone-to-sql-injection', function($name) {
|
||||
return DB::select(
|
||||
// ruleid: laravel-api-route-sql-injection
|
||||
DB::raw("SELECT * FROM users WHERE name = $name"));
|
||||
});
|
||||
|
||||
Route::get('this-is-also-prone-to-sql-injection', function($name) {
|
||||
return DB::select(
|
||||
// ruleid: laravel-api-route-sql-injection
|
||||
DB::raw("SELECT * FROM users WHERE name = " . $name));
|
||||
});
|
||||
|
||||
Route::get('this-is-prone-to-sql-injection-too', function($name) {
|
||||
return DB::select(
|
||||
// ruleid: laravel-api-route-sql-injection
|
||||
DB::raw("SELECT * FROM users WHERE name = $name AND someproperty = foo"));
|
||||
});
|
||||
|
||||
Route::get('safe-from-sql-injection', function($name) {
|
||||
return DB::select(
|
||||
// ok: laravel-api-route-sql-injection
|
||||
DB::raw("SELECT * FROM users WHERE name = ?", [$name]));
|
||||
});
|
||||
?>
|
|
@ -0,0 +1,75 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="{{ app()->getLocale() }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- CSRF Token -->
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
<title>{{ config('app.name', 'Laravel') }}</title>
|
||||
|
||||
<!-- Styles -->
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<nav class="navbar navbar-expand-md navbar-light navbar-laravel">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{{ url('/') }}">
|
||||
{{ config('app.name', 'Laravel') }}
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<!-- Left Side Of Navbar -->
|
||||
<ul class="navbar-nav mr-auto">
|
||||
|
||||
</ul>
|
||||
|
||||
<!-- Right Side Of Navbar -->
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<!-- Authentication Links -->
|
||||
@if(!Auth::check())
|
||||
<li><a class="nav-link" href="{{ url('/login') }}">Login</a></li>
|
||||
<li><a class="nav-link" href="{{ url('/register') }}">Register</a></li>
|
||||
@else
|
||||
<li class="nav-item dropdown">
|
||||
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{{ Auth::user()->name }} <span class="caret"></span>
|
||||
</a>
|
||||
|
||||
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<a class="dropdown-item" href="{{ url('/logout') }}"
|
||||
onclick="event.preventDefault();
|
||||
document.getElementById('logout-form').submit();">
|
||||
Logout
|
||||
</a>
|
||||
<!-- ok: laravel-blade-form-missing-csrf -->
|
||||
<form id="logout-form" action="{{ url('/logout') }}" method="POST" style="display: none;">
|
||||
@csrf
|
||||
</form>
|
||||
<!-- ruleid: laravel-blade-form-missing-csrf -->
|
||||
<form id="logout-form-bad" action="{{ url('/logout') }}" method="POST" style="display: none;">
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
@endif
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="py-4">
|
||||
@yield('content')
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="{{ asset('js/app.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Flight extends Model
|
||||
{
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'flight_id';
|
||||
|
||||
/**
|
||||
* The attributes that aren't mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
// ruleid: laravel-dangerous-model-construction
|
||||
protected $guarded = [];
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
$tainted = $_GET['userinput'];
|
||||
|
||||
// https://laravel.com/docs/8.x/database
|
||||
// Since unprepared statements do not bind parameters, they may be vulnerable to SQL injection. You should never allow user controlled values within an unprepared statement.
|
||||
// ruleid: laravel-sql-injection
|
||||
DB::unprepared("update users set votes = 100 where name = '$tainted'");
|
||||
|
||||
// https://laravel.com/docs/8.x/queries
|
||||
// PDO does not support binding column names. Therefore, you should never allow user input to dictate the column names referenced by your queries, including "order by" columns.
|
||||
// ruleid: laravel-sql-injection
|
||||
$user = DB::table('users')->where($tainted, 'John')->first();
|
||||
// ruleid: laravel-sql-injection
|
||||
$titles = DB::table('users')->pluck($tainted);
|
||||
// ruleid: laravel-sql-injection
|
||||
DB::table('users')->orderBy($tainted);
|
||||
// ruleid: laravel-sql-injection
|
||||
$price = DB::table('orders')->max($tainted);
|
||||
// ruleid: laravel-sql-injection
|
||||
$query = DB::table('users')->select($tainted);
|
||||
|
||||
// ok: laravel-sql-injection
|
||||
$user = DB::table('users')->where('name', $tainted)->first();
|
||||
|
||||
// https://laravel.com/docs/8.x/queries
|
||||
// Raw statements will be injected into the query as strings, so you should be extremely careful to avoid creating SQL injection vulnerabilities.
|
||||
// ruleid: laravel-sql-injection
|
||||
$users = DB::table('users')->select(DB::raw($tainted));
|
||||
// ruleid: laravel-sql-injection
|
||||
$orders = DB::table('orders')->selectRaw($tainted);
|
||||
// ruleid: laravel-sql-injection
|
||||
$orders = DB::table('orders')->whereRaw($tainted);
|
||||
|
||||
// ok: laravel-sql-injection
|
||||
$orders = DB::table('orders')->selectRaw('price * ? as price_with_tax', [$tainted]);
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Accounting;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Auth;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use PDF;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class ChartofAccount extends Controller
|
||||
{
|
||||
public function __construct() {
|
||||
$this->middleware("auth");
|
||||
}
|
||||
|
||||
function index(){
|
||||
if(Auth::user()->accesslevel == env("ACCTNG_HEAD")){
|
||||
$accounts = \App\ChartOfAccount::orderBy("accounting_name")->get();
|
||||
return view("accounting.chart_of_accounts.index", compact("accounts"));
|
||||
}
|
||||
}
|
||||
|
||||
function new_account(Request $request){
|
||||
if(Auth::user()->accesslevel == env("ACCTNG_HEAD")){
|
||||
$validate = Validator::make($request->all(),[
|
||||
// ok: laravel-unsafe-validator
|
||||
"accounting_code" => "required|unique:chart_of_accounts",
|
||||
// ok: laravel-unsafe-validator
|
||||
"accounting_name" => "required|unique:chart_of_accounts",
|
||||
// ok: laravel-unsafe-validator
|
||||
"some_property" => [ Rule::unique("some_column_name")->ignore(Auth::user()->id, "pk_column_name"), "required" ]
|
||||
]);
|
||||
|
||||
if($validate->fails()){
|
||||
return redirect()->back()->withErrors($validate);
|
||||
}
|
||||
|
||||
$newaccount = new \App\ChartOfAccount;
|
||||
$newaccount->accounting_code = $request->accounting_code;
|
||||
$newaccount->accounting_name = $request->accounting_name;
|
||||
$newaccount->category = $request->category;
|
||||
$newaccount->save();
|
||||
|
||||
return redirect()->back()->withSuccess("Successfully created!");
|
||||
}
|
||||
}
|
||||
|
||||
function print_lists(){
|
||||
if(Auth::user()->accesslevel == env("ACCTNG_HEAD")){
|
||||
$accounts = \App\ChartOfAccount::orderBy("accounting_name")->get();
|
||||
$pdf = PDF::loadView('accounting.chart_of_accounts.print_lists',compact('accounts'));
|
||||
$pdf->setPaper('letter','portrait');
|
||||
return $pdf->stream("chart_of_accounts.pdf");
|
||||
}
|
||||
}
|
||||
|
||||
function delete_account($id){
|
||||
if(Auth::user()->accesslevel == env("ACCTNG_HEAD")){
|
||||
$account = \App\ChartOfAccount::find($id);
|
||||
|
||||
$exists = \App\Accounting::where(function($query) use($account){
|
||||
$query->where("accounting_code", $account->accounting_code)
|
||||
->orWhere("accounting_name", $account->accounting_name);
|
||||
})->get();
|
||||
|
||||
if($exists->isEmpty()){
|
||||
$account->delete();
|
||||
|
||||
return redirect()->back()->withSuccess("Account already deleted!");
|
||||
}else{
|
||||
|
||||
return redirect()->back()->withErrors("The account you are trying to delete already have a record.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function update_account($id){
|
||||
if(Auth::user()->accesslevel == env("ACCTNG_HEAD")){
|
||||
$account = \App\ChartOfAccount::find($id);
|
||||
|
||||
$exists = \App\Accounting::where(function($query) use($account){
|
||||
$query->where("accounting_code", $account->accounting_code)
|
||||
->orWhere("accounting_name", $account->accounting_name);
|
||||
})->get();
|
||||
|
||||
if($exists->isEmpty()){
|
||||
return view("accounting.chart_of_accounts.update_form", compact("id","account"));
|
||||
}else{
|
||||
return redirect()->back()->withErrors("The account you are trying to update already have a record.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function update_account_post(Request $request){
|
||||
$validate = Validator::make($request->all(),[
|
||||
// ruleid: laravel-unsafe-validator
|
||||
"accounting_code" => [ Rule::unique("chart_of_accounts")->ignore($request->chart_id,"id"), "required" ],
|
||||
// ruleid: laravel-unsafe-validator
|
||||
"accounting_name" => [ Rule::unique("chart_of_accounts")->ignore($request->chart_id,"id"), "required" ],
|
||||
]);
|
||||
|
||||
if($validate->fails()){
|
||||
return redirect(url("/accounting/chart_of_accounts"))->withErrors($validate);
|
||||
}
|
||||
|
||||
$newaccount = \App\ChartOfAccount::find($request->chart_id);
|
||||
$newaccount->accounting_code = $request->accounting_code;
|
||||
$newaccount->accounting_name = $request->accounting_name;
|
||||
$newaccount->category = $request->category;
|
||||
$newaccount->save();
|
||||
|
||||
return redirect(url("/accounting/chart_of_accounts"))->withSuccess("Successfully updated!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
$ldapconn = ldap_connect("foo.com");
|
||||
|
||||
// ruleid: ldap-bind-without-password
|
||||
$ldapbind = ldap_bind($ldapconn);
|
||||
|
||||
// todoruleid: ldap-bind-without-password
|
||||
LDAP_BIND($ldapconn, "username");
|
||||
|
||||
// ruleid: ldap-bind-without-password
|
||||
ldap_bind($ldapconn, NULL, NULL);
|
||||
|
||||
// ruleid: ldap-bind-without-password
|
||||
ldap_bind($ldapconn, "username", "");
|
||||
|
||||
$a = "";
|
||||
$b = "";
|
||||
// ruleid: ldap-bind-without-password
|
||||
ldap_bind($ldapconn, $a, $b);
|
||||
|
||||
$c = "username";
|
||||
$d = "";
|
||||
// ruleid: ldap-bind-without-password
|
||||
ldap_bind($ldapconn, $c, $d);
|
||||
|
||||
$e = "user";
|
||||
$f = "pass";
|
||||
// ok: ldap-bind-without-password
|
||||
ldap_bind($ldapconn, $e, $f);
|
||||
|
||||
// ok: ldap-bind-without-password
|
||||
ldap_bind($ldapconn, "username", "password");
|
||||
|
||||
// ok: ldap-bind-without-password
|
||||
ldap_bind($ldapconn, $username, $password);
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
// ruleid: mb-ereg-replace-eval
|
||||
mb_ereg_replace($pattern, $replacement, $string, $user_input_options);
|
||||
|
||||
// ok: mb-ereg-replace-eval
|
||||
mb_ereg_replace($pattern, $replacement, $string, "msr");
|
||||
|
||||
// ok: mb-ereg-replace-eval
|
||||
mb_ereg_replace($pattern, $replacement, $string);
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
// ruleid: mcrypt-use
|
||||
mcrypt_ecb(MCRYPT_BLOWFISH, $key, base64_decode($input), MCRYPT_DECRYPT);
|
||||
|
||||
// ruleid: mcrypt-use
|
||||
mcrypt_create_iv($iv_size, MCRYPT_RAND);
|
||||
|
||||
// ruleid: mcrypt-use
|
||||
mdecrypt_generic($td, $c_t);
|
||||
|
||||
// ok: mcrypt-use
|
||||
sodium_crypto_secretbox("Hello World!", $nonce, $key);
|
||||
|
||||
// ok: mcrypt-use
|
||||
openssl_encrypt($plaintext, $cipher, $key, $options=0, $iv, $tag);
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
// ruleid: md5-loose-equality
|
||||
md5("240610708") == "0";
|
||||
|
||||
// ruleid: md5-loose-equality
|
||||
0 == md5("240610708");
|
||||
|
||||
// ruleid: md5-loose-equality
|
||||
0 == md5_file("file.txt");
|
||||
|
||||
// ruleid: md5-loose-equality
|
||||
md5("240610708") == md5_file("file.txt");
|
||||
|
||||
// ok: md5-loose-equality
|
||||
md5("240610708") === "0";
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
function test1($value) {
|
||||
$pass = md5($value);
|
||||
// ruleid: md5-used-as-password
|
||||
$user->setPassword($pass);
|
||||
}
|
||||
|
||||
function test2($value) {
|
||||
$pass = hash('md5', $value);
|
||||
// ruleid: md5-used-as-password
|
||||
$user->setPassword($pass);
|
||||
}
|
||||
|
||||
function okTest1($value) {
|
||||
// ok: md5-used-as-password
|
||||
$pass = hash('sha256', $value);
|
||||
$user->setPassword($pass);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
$data = $_GET["data"];
|
||||
// ruleid: non-literal-header
|
||||
header("Some-Header: $data");
|
||||
|
||||
$data = $_GET["data"];
|
||||
// ruleid: non-literal-header
|
||||
header("Some-Header: ".$data);
|
||||
|
||||
// ok: non-literal-header
|
||||
header("Some-Header: value");
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
function encrypt($plaintext, $password) {
|
||||
$method = "AES-256-CBC";
|
||||
$key = hash('sha256', $password, true);
|
||||
$iv = openssl_random_pseudo_bytes(16);
|
||||
|
||||
// ok
|
||||
$ciphertext = openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv);
|
||||
$hash = hash_hmac('sha256', $ciphertext . $iv, $key, true);
|
||||
|
||||
return $iv . $hash . $ciphertext;
|
||||
}
|
||||
|
||||
function encryptBad($plaintext, $password) {
|
||||
$method = "AES-256-CBC";
|
||||
$key = hash('sha256', $password, true);
|
||||
$iv = "4c25ecc95c8816db753cba44a3b56aca";
|
||||
|
||||
// ruleid: openssl-cbc-static-iv
|
||||
$ciphertext = openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv);
|
||||
$hash = hash_hmac('sha256', $ciphertext . $iv, $key, true);
|
||||
|
||||
return $iv . $hash . $ciphertext;
|
||||
}
|
||||
|
||||
function encryptBad2($plaintext, $password) {
|
||||
$key = hash('sha256', $password, true);
|
||||
$iv = "4c25ecc95c8816db753cba44a3b56aca";
|
||||
|
||||
// ruleid: openssl-cbc-static-iv
|
||||
$ciphertext = openssl_encrypt($plaintext, "AES-256-CBC", $key, OPENSSL_RAW_DATA, $iv);
|
||||
$hash = hash_hmac('sha256', $ciphertext . $iv, $key, true);
|
||||
|
||||
return $iv . $hash . $ciphertext;
|
||||
}
|
||||
|
||||
function decrypt($ivHashCiphertext, $password) {
|
||||
$method = "AES-256-CBC";
|
||||
$iv = substr($ivHashCiphertext, 0, 16);
|
||||
$hash = substr($ivHashCiphertext, 16, 32);
|
||||
$ciphertext = substr($ivHashCiphertext, 48);
|
||||
$key = hash('sha256', $password, true);
|
||||
|
||||
if (!hash_equals(hash_hmac('sha256', $ciphertext . $iv, $key, true), $hash)) return null;
|
||||
|
||||
// ok
|
||||
return openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv);
|
||||
}
|
||||
|
||||
function decryptBad($ivHashCiphertext, $password) {
|
||||
$method = "AES-256-CBC";
|
||||
$iv = "4c25ecc95c8816db753cba44a3b56aca";
|
||||
$hash = substr($ivHashCiphertext, 16, 32);
|
||||
$ciphertext = substr($ivHashCiphertext, 48);
|
||||
$key = hash('sha256', $password, true);
|
||||
|
||||
if (!hash_equals(hash_hmac('sha256', $ciphertext . $iv, $key, true), $hash)) return null;
|
||||
|
||||
// ruleid: openssl-cbc-static-iv
|
||||
return openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv);
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
class OpenSslTest{
|
||||
public static function decrypt_test_1($crypt, $ky) {
|
||||
$key = html_entity_decode($ky);
|
||||
$iv = "@@@@&&&&####$$$$";
|
||||
|
||||
// ruleid: openssl-decrypt-validate
|
||||
$data = openssl_decrypt ( $crypt , "AES-128-CBC" , $key, 0, $iv );
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function decrypt_test_2($crypt, $ky) {
|
||||
$key = html_entity_decode($ky);
|
||||
$iv = "@@@@&&&&####$$$$";
|
||||
|
||||
// ruleid: openssl-decrypt-validate
|
||||
$data = openssl_decrypt ( $crypt , "AES-128-CBC" , $key, 0, $iv );
|
||||
if($data == true){
|
||||
return "";
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function decrypt_test_3($crypt, $ky) {
|
||||
$key = html_entity_decode($ky);
|
||||
$iv = "@@@@&&&&####$$$$";
|
||||
|
||||
// ruleid: openssl-decrypt-validate
|
||||
return openssl_decrypt ( $crypt , "AES-128-CBC" , $key, 0, $iv );
|
||||
}
|
||||
|
||||
public static function decrypt_test_ok($crypt, $ky) {
|
||||
$key = html_entity_decode($ky);
|
||||
$iv = "@@@@&&&&####$$$$";
|
||||
|
||||
// ok: openssl-decrypt-validate
|
||||
$data = openssl_decrypt ( $crypt , "AES-128-CBC" , $key, 0, $iv );
|
||||
if($data == false){
|
||||
return "";
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function decrypt_test_ok_2($crypt, $ky) {
|
||||
$key = html_entity_decode($ky);
|
||||
$iv = "@@@@&&&&####$$$$";
|
||||
|
||||
// ok: openssl-decrypt-validate
|
||||
$data = openssl_decrypt ( $crypt , "AES-128-CBC" , $key, 0, $iv );
|
||||
if(false === $data){
|
||||
return "";
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function decrypt_test_ok_3($crypt, $ky) {
|
||||
$key = html_entity_decode($ky);
|
||||
$iv = "@@@@&&&&####$$$$";
|
||||
|
||||
// ok: openssl-decrypt-validate
|
||||
$data = openssl_decrypt ( $crypt , "AES-128-CBC" , $key, 0, $iv );
|
||||
assertTrue(false !== $data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
namespace testing;
|
||||
|
||||
// ruleid: php-permissive-cors
|
||||
header("Access-Control-Allow-Origin: *");
|
||||
|
||||
// ruleid: php-permissive-cors
|
||||
header("Access-Control-Allow-Origin:* ");
|
||||
|
||||
// todoruleid: php-permissive-cors
|
||||
Header("access-control-allow-origin: *");
|
||||
|
||||
// ok: php-permissive-cors
|
||||
header("Access-Control-Allow-Origin: *something*");
|
||||
|
||||
// ok: php-permissive-cors
|
||||
header("Other-Property: *");
|
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
|
||||
// ruleid: phpinfo-use
|
||||
echo phpinfo();
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
// ruleid: preg-replace-eval
|
||||
preg_replace($user_input_pattern, $replacement, $string);
|
||||
|
||||
// ok: preg-replace-eval
|
||||
preg_replace("/some_regexp/", "replacement", $string_before);
|
|
@ -4,7 +4,7 @@ if (isset($_GET['which']))
|
|||
{
|
||||
$which = $_GET['which'];
|
||||
require_once $which.'noparenthesis.php';
|
||||
require_once($which.'parenthesis.php';)
|
||||
require_once($which.'parenthesis.php');
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
|
||||
|
||||
class Type extends AbstractType
|
||||
{
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
// ruleid: symfony-csrf-protection-disabled
|
||||
$resolver->setDefaults([
|
||||
'data_class' => Type::class,
|
||||
'csrf_protection' => false
|
||||
]);
|
||||
|
||||
// ruleid: symfony-csrf-protection-disabled
|
||||
$resolver->setDefaults(array(
|
||||
'csrf_protection' => false
|
||||
));
|
||||
|
||||
|
||||
$csrf = false;
|
||||
// ruleid: symfony-csrf-protection-disabled
|
||||
$resolver->setDefaults([
|
||||
'csrf_protection' => $csrf
|
||||
]);
|
||||
|
||||
// ok: symfony-csrf-protection-disabled
|
||||
$resolver->setDefaults([
|
||||
'csrf_protection' => true
|
||||
]);
|
||||
|
||||
// ok: symfony-csrf-protection-disabled
|
||||
$resolver->setDefaults([
|
||||
'data_class' => Type::class,
|
||||
]);
|
||||
|
||||
// ok: symfony-csrf-protection-disabled
|
||||
$resolver->setDefaults($options);
|
||||
}
|
||||
}
|
||||
|
||||
class TestExtension extends Extension implements PrependExtensionInterface
|
||||
{
|
||||
public function prepend(ContainerBuilder $container)
|
||||
{
|
||||
|
||||
// ruleid: symfony-csrf-protection-disabled
|
||||
$container->prependExtensionConfig('framework', ['csrf_protection' => false,]);
|
||||
|
||||
// ruleid: symfony-csrf-protection-disabled
|
||||
$container->prependExtensionConfig('framework', ['something_else' => true, 'csrf_protection' => false,]);
|
||||
|
||||
$csrfOption = false;
|
||||
// ruleid: symfony-csrf-protection-disabled
|
||||
$container->prependExtensionConfig('framework', ['csrf_protection' => $csrfOption,]);
|
||||
|
||||
// ruleid: symfony-csrf-protection-disabled
|
||||
$container->loadFromExtension('framework', ['csrf_protection' => false,]);
|
||||
|
||||
// ok: symfony-csrf-protection-disabled
|
||||
$container->loadFromExtension('framework', ['csrf_protection' => null,]);
|
||||
|
||||
// ok: symfony-csrf-protection-disabled
|
||||
$container->prependExtensionConfig('framework', ['csrf_protection' => true,]);
|
||||
|
||||
// ok: symfony-csrf-protection-disabled
|
||||
$container->prependExtensionConfig('framework', ['csrf_protection' => null,]);
|
||||
|
||||
// ok: symfony-csrf-protection-disabled
|
||||
$container->prependExtensionConfig('something_else', ['csrf_protection' => false,]);
|
||||
}
|
||||
}
|
||||
|
||||
class MyController1 extends AbstractController
|
||||
{
|
||||
public function action()
|
||||
{
|
||||
// ruleid: symfony-csrf-protection-disabled
|
||||
$this->createForm(TaskType::class, $task, [
|
||||
'other_option' => false,
|
||||
'csrf_protection' => false,
|
||||
]);
|
||||
|
||||
// ruleid: symfony-csrf-protection-disabled
|
||||
$this->createForm(TaskType::class, $task, array(
|
||||
'csrf_protection' => false,
|
||||
));
|
||||
|
||||
$csrf = false;
|
||||
// ruleid: symfony-csrf-protection-disabled
|
||||
$this->createForm(TaskType::class, $task, array(
|
||||
'csrf_protection' => $csrf,
|
||||
));
|
||||
|
||||
// ok: symfony-csrf-protection-disabled
|
||||
$this->createForm(TaskType::class, $task, ['csrf_protection' => true]);
|
||||
|
||||
// ok: symfony-csrf-protection-disabled
|
||||
$this->createForm(TaskType::class, $task, ['other_option' => false]);
|
||||
|
||||
$this->redirectToRoute('/');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
|
||||
class WebAppController
|
||||
{
|
||||
public function test1(): RedirectResponse
|
||||
{
|
||||
$foobar = $session->get('foobar');
|
||||
// ruleid: symfony-non-literal-redirect
|
||||
return $this->redirect($foobar);
|
||||
}
|
||||
|
||||
public function test2(): RedirectResponse
|
||||
{
|
||||
$addr = $request->query->get('page', 1);
|
||||
// ruleid: symfony-non-literal-redirect
|
||||
return $this->redirect('https://'. $addr);
|
||||
}
|
||||
|
||||
public function okTest1(): RedirectResponse
|
||||
{
|
||||
$foobar = $session->get('foobar');
|
||||
// ok: symfony-non-literal-redirect
|
||||
return $this->redirectToRoute($foobar);
|
||||
}
|
||||
|
||||
public function okTest2(): RedirectResponse
|
||||
{
|
||||
// ok: symfony-non-literal-redirect
|
||||
return $this->redirect('http://symfony.com/doc');
|
||||
}
|
||||
|
||||
public function okTest3(): RedirectResponse
|
||||
{
|
||||
// ok: symfony-non-literal-redirect
|
||||
return $this->redirect();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
namespace symfony;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Response as FooResponse;
|
||||
|
||||
// ruleid: symfony-permissive-cors
|
||||
$response = new Response('content', Response::HTTP_OK, ['Access-Control-Allow-Origin' => '*']);
|
||||
|
||||
// ruleid: symfony-permissive-cors
|
||||
$response = new Response('content', Response::HTTP_OK, Array('Access-Control-Allow-Origin' => '*'));
|
||||
|
||||
// todoruleid: symfony-permissive-cors
|
||||
$response = new response('content', Response::HTTP_OK, Array('Access-Control-Allow-Origin' => '*'));
|
||||
|
||||
// ruleid: symfony-permissive-cors
|
||||
$response = new FooResponse('content', Response::HTTP_OK, ['Access-Control-Allow-Origin' => '*']);
|
||||
|
||||
|
||||
$headers = ['Access-Control-Allow-Origin' => '*'];
|
||||
// ruleid: symfony-permissive-cors
|
||||
$response = new Response('content', Response::HTTP_OK, $headers);
|
||||
|
||||
|
||||
// ruleid: symfony-permissive-cors
|
||||
$response->headers->set(' access-control-allow-origin ', ' * ');
|
||||
|
||||
|
||||
|
||||
$safe = ['foo' => 'bar'];
|
||||
// ok: symfony-permissive-cors
|
||||
$response = new Response('content', Response::HTTP_OK, $safe);
|
||||
|
||||
// ok: symfony-permissive-cors
|
||||
$response = new Response('content', Response::HTTP_OK, ['Access-Control-Allow-Origin' => 'https://www.example.com']);
|
||||
|
||||
// ok: symfony-permissive-cors
|
||||
$response = new Response('content', Response::HTTP_OK, ['Other-Property' => '*']);
|
||||
|
||||
// ok: symfony-permissive-cors
|
||||
$response = new Foo('content', Response::HTTP_OK, ['Access-Control-Allow-Origin' => '*']);
|
||||
|
||||
// ok: symfony-permissive-cors
|
||||
$response->headers->set('Access-Control-Allow-Origin', 'foo');
|
||||
|
||||
// ok: symfony-permissive-cors
|
||||
$response->headers->set('Other-Property', '*');
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
$tainted = $_GET["tainted"];
|
||||
// ruleid: tainted-filename
|
||||
hash_file('sha1', $tainted);
|
||||
|
||||
// ruleid: tainted-filename
|
||||
file($tainted);
|
||||
|
||||
// ok: tainted-filename
|
||||
hash_file($tainted, 'file.txt');
|
||||
|
||||
// ruleid: tainted-filename
|
||||
file(dirname($tainted));
|
||||
|
||||
// Sanitized
|
||||
// ok: tainted-filename
|
||||
file(basename($tainted));
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
$parts = explode("/", $_SERVER['PATH_INFO']);
|
||||
$controllerName = $parts[0];
|
||||
|
||||
// ruleid: tainted-object-instantiation
|
||||
$controller = new $controllerName($parts[1]);
|
||||
|
||||
// ok: tainted-object-instantiation
|
||||
$controller = new MyController($controllerName);
|
||||
|
||||
// ok: tainted-object-instantiation
|
||||
$a = "MyController";
|
||||
$controller = new $a();
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
// True Positives
|
||||
|
||||
function test1() {
|
||||
// ruleid: tainted-sql-string
|
||||
$query = "SELECT * FROM table WHERE Id = '".$_GET['url']."'";
|
||||
$info = mysql_query($query);
|
||||
return $info;
|
||||
}
|
||||
|
||||
function test2() {
|
||||
$part = $_POST['url'];
|
||||
// ruleid: tainted-sql-string
|
||||
$query = "SELECT * FROM table WHERE Id = '$part'";
|
||||
$info = mysql_query($query);
|
||||
return $info;
|
||||
}
|
||||
|
||||
function test3() {
|
||||
// ruleid: tainted-sql-string
|
||||
$query = "SELECT * FROM table WHERE Id = '{$_REQUEST['url']}'";
|
||||
$info = mysql_query($query);
|
||||
return $info;
|
||||
}
|
||||
|
||||
function test4() {
|
||||
// ruleid: tainted-sql-string
|
||||
$query = sprintf("SELECT * FROM table WHERE Id = '%s'", $_COOKIE['foo']);
|
||||
$info = mysql_query($query);
|
||||
return $info;
|
||||
}
|
||||
|
||||
// True Negatives
|
||||
|
||||
function test1() {
|
||||
// ok: tainted-sql-string
|
||||
$query = 'SELECT * FROM table WHERE Id = 1';
|
||||
$info = mysql_query($query);
|
||||
return $info;
|
||||
}
|
||||
|
||||
function test2() {
|
||||
$value = 1;
|
||||
// ok: tainted-sql-string
|
||||
$query = "SELECT * FROM table WHERE Id = '".$value."'";
|
||||
$info = mysql_query($query);
|
||||
return $info;
|
||||
}
|
||||
|
||||
function test3() {
|
||||
// ok: tainted-sql-string
|
||||
$query = "SELECT * FROM table WHERE Id = '{$foobar() ? 1 : 2}'";
|
||||
$info = mysql_query($query);
|
||||
return $info;
|
||||
}
|
||||
|
||||
function test4() {
|
||||
$value = 1;
|
||||
// ok: tainted-sql-string
|
||||
$query = sprintf("SELECT * FROM table WHERE Id = '%s'", $value);
|
||||
$info = mysql_query($query);
|
||||
return $info;
|
||||
}
|
||||
|
||||
function test5() {
|
||||
$part = $_POST['url'];
|
||||
$part = mysqli_real_escape_string($part);
|
||||
// ok: tainted-sql-string
|
||||
$query = sprintf("SELECT * FROM table WHERE Id = '" . $part . "'");
|
||||
$info = mysql_query($query);
|
||||
return $info;
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
function make_request($url) {
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_HEADER, 0);
|
||||
|
||||
$data = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
// True Positives
|
||||
|
||||
function test1() {
|
||||
// ruleid: tainted-url-host
|
||||
$url = 'https://'.$_GET['url'].'/foobar';
|
||||
$info = make_request($url);
|
||||
return $info;
|
||||
}
|
||||
|
||||
function test2() {
|
||||
$part = $_POST['url'];
|
||||
// ruleid: tainted-url-host
|
||||
$url = "https://$part/foobar";
|
||||
$info = make_request($url);
|
||||
return $info;
|
||||
}
|
||||
|
||||
function test3() {
|
||||
// ruleid: tainted-url-host
|
||||
$url = "https://{$_REQUEST['url']}/foobar";
|
||||
$info = make_request($url);
|
||||
return $info;
|
||||
}
|
||||
|
||||
function test4() {
|
||||
// ruleid: tainted-url-host
|
||||
$url = sprintf('https://%s/%s/', $_COOKIE['foo'], $bar);
|
||||
$info = make_request($url);
|
||||
return $info;
|
||||
}
|
||||
|
||||
// True Negatives
|
||||
|
||||
function test1() {
|
||||
// ok: tainted-url-host
|
||||
$url = 'https://www.google.com/'.$_GET['url'].'/foobar';
|
||||
$info = make_request($url);
|
||||
return $info;
|
||||
}
|
||||
|
||||
function test2() {
|
||||
$part = $_POST['url'];
|
||||
// ok: tainted-url-host
|
||||
$url = "some random text /$part/ foobar";
|
||||
$info = make_request($url);
|
||||
return $info;
|
||||
}
|
||||
|
||||
function test3() {
|
||||
// ok: tainted-url-host
|
||||
$url = "https://www.google.com/{$_REQUEST['url']}/foobar";
|
||||
$info = make_request($url);
|
||||
return $info;
|
||||
}
|
||||
|
||||
function test4() {
|
||||
// ok: tainted-url-host
|
||||
$url = sprintf('some random format string %s %s', $_COOKIE['foo'], $bar);
|
||||
$info = make_request($url);
|
||||
return $info;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
$data = $_GET["data"];
|
||||
// ruleid: unlink-use
|
||||
unlink("/storage/" . $data . "/test");
|
||||
|
||||
// ok: unlink-use
|
||||
unlink('/storage/foobar/test');
|
||||
|
||||
?>
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
$data = $_GET["data"];
|
||||
// ruleid: unserialize-use
|
||||
$object = unserialize($data);
|
||||
|
||||
// ok: unserialize-use
|
||||
$object2 = unserialize('O:1:"a":1:{s:5:"value";s:3:"100";}');
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue