29

I noticed in several penetration tests that PHP is converting values like 1e9 to 1000000000 while the max accepted string length of this number is 3 (in the database storage and as maxlength property on the HTML forms).

Nevertheless, when inputting 1e9 (3), PHP will return 1000000000 (10) as its output. That is a higher number than the application expects and can properly handle. Therefore I would consider a better validation of user input to prevent this.

Firstly, I assume this behavior is not dangerous but just undesirable, is it legitimate to assume this? Secondly, can I consider this as an actual (low severity) vulnerability?

Also the input 9e9 will result in the max 32-bit value 2147483647 (10) instead of 9000000000 (10). Is this alone (32-bit system or configuration) considered as leakage of system information or dangerous anyhow?

1
  • 41
    The problem is PHP.
    – cat
    Jun 20, 2016 at 13:47

2 Answers 2

18

Strictly speaking? No, by itself it isn't a vulnerability. But it does suggest there's potentially a problem that needs further investigation.

This is one of the inherent problems with pen testing. You find something ambiguous like this, and don't know if it's exploitable. To even start to find out if this is a vulnerability, you need to understand what the input limitation does.

For instance, if the program was designed to limit bank transfers to under $1000 and the input field was the amount, and there's no further checks anywhere, you've just found a huge vulnerability.

On the other hand, if the field is just the first 3 digits of a phone number that creates a phone number database for parents to enter contact numbers for a school, and the validation is simply to make sure the user only input the first 3 digits, you've likely found nothing but a corner case where a very nerdy parent can screw up his/her own phone # entry in the database.

1
  • 3
    Great answer. Rereading the question, I think this is more useful than mine since it focus on the pentesting perspective.
    – Anders
    Jun 20, 2016 at 15:37
26

Why does this happen?

It's because PHP has loose typing. Take a look at this example:

$x = "1e6";
echo strlen($x); // 3
echo $x * 1;     // 1 000 000

On the second line, $x is assumed to be a string, and as such is obviously three characters long. On the third line, $x is interpreted as an integer, or 1 000 000 in this case.

Is it a problem?

This can definitely cause bugs, and every bug is a potential security vulnerability. But on it's own, it does not make your application vulnerable by default. But lets try to imagine a scenario where it would cause a problem.

Let's say a forum has numbered groups that users can freely join, but the first 10 groups (0 to 9) are reserved for administrators. The code for joingroup.php looks like this:

$group = $_POST['group'];
if(strlen($group) > 1 || $isadmin) {
    join_group($group, $uid);
}
else {
    // Fail.
}

You could sneak into an admin group without actually being an admin by posting e.g. 0.3e1, that has string length 5 but evaluates to 3. I know, it is a silly example. The point I want to make is that if you rely on strlen() (or anything else that treats the input as a string) to validate numeric data, you might be vulnerable.

Just posting 3.0 or  3 would bypass this check as well. For more on how PHP implicitly converts strings to numbers, check the manual.

How should I deal with this in PHP?

Validate user input. Check that you actually get an integer when you expect to get an integer:

if(!ctype_digit($group)) {
    // Fail.
}

It is also a good idea to always treat something that should be an integer as an integer and not a string:

$group = (int) $_POST['group']
if($group > 9 || $isadmin) {
    // ...

Is this leaking system information?

Apparently this can reveal the maximum integer value. Perhaps someone could deduce that you are using PHP from this, but there are probably many other ways to do that already. The max value is platform dependent, so it could be used for fingerprinting. But in practice 32 bits are probably used on a 32-bit system, and 64 bits on a 64-bit system. So that is the only information you are leaking.

6
  • 6
    While I have no love for PHP, the problem with if(strlen($group) > 1 || $isadmin) is using string comparison to compare numerical values, not PHP's parsing of numbers.
    – Taemyr
    Jun 20, 2016 at 15:49
  • @Anders Thanks a lot for your great answer. Small detail. It's also (unfortunately) common that 32-bit software is installed and configured on a 64-bit system. Secondly would you consider yourself reporting about this as an actual low severity info leakage in context of "Insight in used system architecture/configuration."? Or is this really nitpicking?
    – Bob Ortiz
    Jun 20, 2016 at 22:19
  • 1
    @EvanderConsus Not sure if I would report it. I would say that using .php file extentions or having the X-Powered-By header set is worse, and even that is pretty minor IMO. Guess it depends on how detailed the report should be.
    – Anders
    Jun 20, 2016 at 22:31
  • 2
    @Taemyr You are right, but the possibility to even do that is PHP's "fault"... Jun 21, 2016 at 6:38
  • 1
    @BobOrtiz I have no experience with strict typing in PHP, so I am not sure. But the root problem here is the dynamic typing, so I highly suspect it is a move in the right direction.
    – Anders
    Jan 17, 2022 at 9:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .