Being able to use arrays in $_GET
in this way is in itself not a security vulnerability. The DoS vector seems negligible to me, although this may indeed be amplified by the code using it.
However, the examples you provided missed the most important part of this feature (from an attackers point of view): it is not only possible to pass regular arrays in GET
and POST
parameters this way, but also associative arrays. In fact, PHP does not destinguish between the two:
PHP arrays can contain integer and string keys at the same time as PHP does not distinguish between indexed and associative arrays.
– PHP: Arrays - Manual
This means that if a client supplies POST
parameters like this:
<input type="text" name="pass[pass1]" value="Password 1">
<input type="text" name="pass[pass2]" value="Password 2">
$_POST
/ $_GET
will look like this:
$_POST = array(
...
'pass' => array(
'pass1' => 'Password 1',
'pass2' => 'Password 2',
),
...
);
But if the server was expecting it to be a normal array instead of an associative one, it could lead to a security vulnerability:
//Simplified example, bug is possible with parameterized queries as well
//Expects ?pass[]=password1&pass[]=password2
$query = 'INSERT INTO users (index, password) ';
$parts = array();
foreach($_GET['user'] AS $index=>$value){
parts[]=" VALUES ({$index}, ".$pdo->real_escape_string($value).')';
}
$query .= implode(", ", $parts);
$pdo->exec($query);//
$query
with expected input:
INSERT INTO USERS (index, password) VALUES(0, 'password1'), VALUES(1, 'password2')
$query
with ?pass[0,'');DROP DATABASE DATABASE();--]=foo
:
INSERT INTO USERS (index, password) VALUES(0,'');DROP DATABASE DATABASE();--, 'foo')

In fact, this is the exact same mistake that lead to the security flaw called "Drupalgeddon" – and it received that name for a good reason.
A vulnerability in this API allows an attacker to send specially crafted requests resulting in arbitrary SQL execution. Depending on the content of the requests this can lead to privilege escalation, arbitrary PHP execution, or other attacks. – SA-CORE-2014-005 - Drupal core - SQL injection
Automated attacks began compromising Drupal 7 websites that were not patched or updated to Drupal 7.32 within hours of the announcement of SA-CORE-2014-005 - Drupal core - SQL injection. You should proceed under the assumption that every Drupal 7 website was compromised unless updated or patched before Oct 15th, 11pm UTC, that is 7 hours after the announcement. – Drupal Core - Highly Critical - Public Service announcement - PSA-2014-003
It was also the vulnerability that most likely lead to the disclosure of the Panama Papers (probably should've installed those security updates…).
The Drupal vulnerability was remedied by updating the code to pass the received array to array_values()
, which returns an indexed array containing only values of the array it received, thus getting rid of any malicious keys.
The example code could be fixed in the same way:
Before:
foreach($_GET['user'] AS $index=>$value){
After:
foreach(array_values($_GET['user']) AS $index=>$value){
More information about Drupalgeddon, including a working exploit: Drupal 7: Drupalgeddon Exploit
Note that this stuff works the same way, regardless if you're working with $_GET
or $_POST
. I'm not sure about $_REQUEST
and $_COOKIE
.
query=
, the page won't mistakenly takequery[]=
in its place (did you intend to imply so?). The third scenario would only occur ifquery[][][][]=
is expected by the page, and so I wouldn't consider it an injection.query[][][]=
as$_GET['query']
and not as$_GET['query[][][]']
.?query[1==1]=foo
,?query[die()]=foo
,?query[-1]=foo
?=
and&
in$GET
/$_POST
array name.