forked from Wavyzz/dolibarr
Fix javascript obfuscating with HTML comments
This commit is contained in:
@@ -239,78 +239,99 @@ class CoreTest extends PHPUnit\Framework\TestCase
|
||||
|
||||
|
||||
/**
|
||||
* testSqlAndScriptInject
|
||||
* testSqlAndScriptInjectWithPHPUnit
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSqlAndScriptInject()
|
||||
public function testSqlAndScriptInjectWithPHPUnit()
|
||||
{
|
||||
global $dolibarr_main_prod;
|
||||
|
||||
global $dolibarr_main_url_root;
|
||||
global $dolibarr_main_data_root;
|
||||
global $dolibarr_main_document_root;
|
||||
global $dolibarr_main_data_root_alt;
|
||||
global $dolibarr_main_document_root_alt;
|
||||
global $dolibarr_main_db_host;
|
||||
global $dolibarr_main_db_port;
|
||||
global $dolibarr_main_db_type;
|
||||
global $dolibarr_main_db_prefix;
|
||||
|
||||
|
||||
// This is code copied from main.inc.php !!!!!!!!!!!!!!!
|
||||
|
||||
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
|
||||
/**
|
||||
* Security: SQL Injection and XSS Injection (scripts) protection (Filters on GET, POST, PHP_SELF).
|
||||
* Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET, POST, PHP_SELF).
|
||||
*
|
||||
* @param string $val Value
|
||||
* @param string $type 1=GET, 0=POST, 2=PHP_SELF
|
||||
* @return int >0 if there is an injection
|
||||
* @param string $val Value brut found int $_GET, $_POST or PHP_SELF
|
||||
* @param string $type 1=GET, 0=POST, 2=PHP_SELF, 3=GET without sql reserved keywords (the less tolerant test)
|
||||
* @return int >0 if there is an injection, 0 if none
|
||||
*/
|
||||
function testSqlAndScriptInject($val, $type)
|
||||
{
|
||||
// phpcs:enable
|
||||
$inj = 0;
|
||||
// For SQL Injection (only GET and POST are used to be included into bad escaped SQL requests)
|
||||
if ($type != 2)
|
||||
{
|
||||
$inj += preg_match('/delete\s+from/i', $val);
|
||||
$inj += preg_match('/create\s+table/i', $val);
|
||||
$inj += preg_match('/update.+set.+=/i', $val);
|
||||
$inj += preg_match('/insert\s+into/i', $val);
|
||||
$inj += preg_match('/select.+from/i', $val);
|
||||
$inj += preg_match('/union.+select/i', $val);
|
||||
$inj += preg_match('/into\s+(outfile|dumpfile)/i', $val);
|
||||
$inj += preg_match('/(\.\.%2f)+/i', $val);
|
||||
}
|
||||
// For XSS Injection done by adding javascript with script
|
||||
// This is all cases a browser consider text is javascript:
|
||||
// When it found '<script', 'javascript:', '<style', 'onload\s=' on body tag, '="&' on a tag size with old browsers
|
||||
// All examples on page: http://ha.ckers.org/xss.html#XSScalc
|
||||
// More on https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
|
||||
$inj += preg_match('/<script/i', $val);
|
||||
$inj += preg_match('/<iframe/i', $val);
|
||||
$inj += preg_match('/Set\.constructor/i', $val); // ECMA script 6
|
||||
if (! defined('NOSTYLECHECK')) $inj += preg_match('/<style/i', $val);
|
||||
$inj += preg_match('/base[\s]+href/si', $val);
|
||||
$inj += preg_match('/<.*onmouse/si', $val); // onmousexxx can be set on img or any html tag like <img title='...' onmouseover=alert(1)>
|
||||
$inj += preg_match('/onerror\s*=/i', $val); // onerror can be set on img or any html tag like <img title='...' onerror = alert(1)>
|
||||
$inj += preg_match('/onfocus\s*=/i', $val); // onfocus can be set on input text html tag like <input type='text' value='...' onfocus = alert(1)>
|
||||
$inj += preg_match('/onload\s*=/i', $val); // onload can be set on svg tag <svg/onload=alert(1)> or other tag like body <body onload=alert(1)>
|
||||
//$inj += preg_match('/on[A-Z][a-z]+\*=/', $val); // To lock event handlers onAbort(), ...
|
||||
$inj += preg_match('/:|:|:/i', $val); // refused string ':' encoded (no reason to have it encoded) to lock 'javascript:...'
|
||||
//if ($type == 1)
|
||||
//{
|
||||
$inj += preg_match('/javascript:/i', $val);
|
||||
$inj += preg_match('/vbscript:/i', $val);
|
||||
//}
|
||||
// For XSS Injection done by adding javascript closing html tags like with onmousemove, etc... (closing a src or href tag with not cleaned param)
|
||||
if ($type == 1) $inj += preg_match('/"/i', $val); // We refused " in GET parameters value
|
||||
if ($type == 2) $inj += preg_match('/[;"]/', $val); // PHP_SELF is a file system path. It can contains spaces.
|
||||
return $inj;
|
||||
// Decode string first
|
||||
// So <svg onload='console.log("123")' become <svg onload='console.log("123")'
|
||||
// So ":'" become ":'" (due to ENT_HTML5)
|
||||
$val = html_entity_decode($val, ENT_QUOTES | ENT_HTML5);
|
||||
|
||||
// TODO loop to decode until no more thing to decode ?
|
||||
|
||||
// We clean string because some hacks try to obfuscate evil strings by inserting non printable chars. Example: 'java(ascci09)scr(ascii00)ipt' is processed like 'javascript' (whatever is place of evil ascii char)
|
||||
// We should use dol_string_nounprintableascii but function is not yet loaded/available
|
||||
$val = preg_replace('/[\x00-\x1F\x7F]/u', '', $val); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
|
||||
// We clean html comments because some hacks try to obfuscate evil strings by inserting HTML comments. Example: on<!-- -->error=alert(1)
|
||||
$val = preg_replace('/<!--[^>]*-->/', '', $val);
|
||||
|
||||
$inj = 0;
|
||||
// For SQL Injection (only GET are used to be included into bad escaped SQL requests)
|
||||
if ($type == 1 || $type == 3)
|
||||
{
|
||||
$inj += preg_match('/delete\s+from/i', $val);
|
||||
$inj += preg_match('/create\s+table/i', $val);
|
||||
$inj += preg_match('/insert\s+into/i', $val);
|
||||
$inj += preg_match('/select\s+from/i', $val);
|
||||
$inj += preg_match('/into\s+(outfile|dumpfile)/i', $val);
|
||||
$inj += preg_match('/user\s*\(/i', $val); // avoid to use function user() that return current database login
|
||||
$inj += preg_match('/information_schema/i', $val); // avoid to use request that read information_schema database
|
||||
$inj += preg_match('/<svg/i', $val); // <svg can be allowed in POST
|
||||
}
|
||||
if ($type == 3)
|
||||
{
|
||||
$inj += preg_match('/select|update|delete|truncate|replace|group\s+by|concat|count|from|union/i', $val);
|
||||
}
|
||||
if ($type != 2) // Not common key strings, so we can check them both on GET and POST
|
||||
{
|
||||
$inj += preg_match('/updatexml\(/i', $val);
|
||||
$inj += preg_match('/update.+set.+=/i', $val);
|
||||
$inj += preg_match('/union.+select/i', $val);
|
||||
$inj += preg_match('/(\.\.%2f)+/i', $val);
|
||||
}
|
||||
// For XSS Injection done by closing textarea to execute content into a textarea field
|
||||
$inj += preg_match('/<\/textarea/i', $val);
|
||||
// For XSS Injection done by adding javascript with script
|
||||
// This is all cases a browser consider text is javascript:
|
||||
// When it found '<script', 'javascript:', '<style', 'onload\s=' on body tag, '="&' on a tag size with old browsers
|
||||
// All examples on page: http://ha.ckers.org/xss.html#XSScalc
|
||||
// More on https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
|
||||
$inj += preg_match('/<audio/i', $val);
|
||||
$inj += preg_match('/<embed/i', $val);
|
||||
$inj += preg_match('/<iframe/i', $val);
|
||||
$inj += preg_match('/<object/i', $val);
|
||||
$inj += preg_match('/<script/i', $val);
|
||||
$inj += preg_match('/Set\.constructor/i', $val); // ECMA script 6
|
||||
if (!defined('NOSTYLECHECK')) $inj += preg_match('/<style/i', $val);
|
||||
$inj += preg_match('/base\s+href/si', $val);
|
||||
$inj += preg_match('/=data:/si', $val);
|
||||
// List of dom events is on https://www.w3schools.com/jsref/dom_obj_event.asp
|
||||
$inj += preg_match('/onmouse([a-z]*)\s*=/i', $val); // onmousexxx can be set on img or any html tag like <img title='...' onmouseover=alert(1)>
|
||||
$inj += preg_match('/ondrag([a-z]*)\s*=/i', $val); //
|
||||
$inj += preg_match('/ontouch([a-z]*)\s*=/i', $val); //
|
||||
$inj += preg_match('/on(abort|afterprint|beforeprint|beforeunload|blur|canplay|canplaythrough|change|click|contextmenu|copy|cut)\s*=/i', $val);
|
||||
$inj += preg_match('/on(dblclick|drop|durationchange|ended|error|focus|focusin|focusout|hashchange|input|invalid)\s*=/i', $val);
|
||||
$inj += preg_match('/on(keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|offline|online|pagehide|pageshow)\s*=/i', $val);
|
||||
$inj += preg_match('/on(paste|pause|play|playing|progress|ratechange|resize|reset|scroll|search|seeking|select|show|stalled|start|submit|suspend)\s*=/i', $val);
|
||||
$inj += preg_match('/on(timeupdate|toggle|unload|volumechange|waiting)\s*=/i', $val);
|
||||
//$inj += preg_match('/on[A-Z][a-z]+\*=/', $val); // To lock event handlers onAbort(), ...
|
||||
$inj += preg_match('/:|:|:/i', $val); // refused string ':' encoded (no reason to have it encoded) to lock 'javascript:...'
|
||||
$inj += preg_match('/javascript\s*:/i', $val);
|
||||
$inj += preg_match('/vbscript\s*:/i', $val);
|
||||
// For XSS Injection done by adding javascript closing html tags like with onmousemove, etc... (closing a src or href tag with not cleaned param)
|
||||
if ($type == 1) {
|
||||
$val = str_replace('enclosure="', 'enclosure=X', $val); // We accept enclosure="
|
||||
$inj += preg_match('/"/i', $val); // We refused " in GET parameters value.
|
||||
}
|
||||
if ($type == 2) $inj += preg_match('/[;"]/', $val); // PHP_SELF is a file system path. It can contains spaces.
|
||||
return $inj;
|
||||
}
|
||||
|
||||
|
||||
// Run tests
|
||||
// More on https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
|
||||
|
||||
@@ -404,5 +425,9 @@ class CoreTest extends PHPUnit\Framework\TestCase
|
||||
$test='Set.constructor`alert\x281\x29```';
|
||||
$result=testSqlAndScriptInject($test, 0);
|
||||
$this->assertGreaterThanOrEqual($expectedresult, $result, 'Error on testSqlAndScriptInject iii');
|
||||
|
||||
$test="on<!-- ab\nc -->error=alert(1)";
|
||||
$result=testSqlAndScriptInject($test, 0);
|
||||
$this->assertGreaterThanOrEqual($expectedresult, $result, 'Error on testSqlAndScriptInject jjj');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user