The Integer-Overflow (IOF) vulnerability family is responsible for a dominant part of C/C++ code vulnerabilities, as I shown in my previous post with a specific example. However, the Integer vulnerability class has more than IOFs in it, and this will be the topic of this post.
CVE 2016-10158:
The exif_convert_any_to_int function in ext/exif/exif.c in PHP … allows remote attackers to cause a denial of service (application crash) via crafted EXIF data…
This vulnerability meant that parsing a hostile TIFF/JPEG file in all PHP versions, could lead to a server crash. Instead of a NULL-dereference or Out-Of-Bounds access, this CVE is caused by an Integer Exception, on intel CPUs.
Integer Basics – Intel:
It is known (I hope) that a division by 0, on intel CPUs, will raise an arithmetic exception. And this is why the PHP developers included a code check to handle this edge case:
case TAG_FMT_SRATIONAL: s_den = php_ifd_get32s(4+(char* )value, motorola_intel); if (s_den == 0) { return 0; } else { return php_ifd_get32s(value, motorola_intel) / s_den; }
However, by reading the full specifications of the DIV command we can see that there is one more edge case:
… If the quotient is too large for the designated register.
Since signed integers are a-symmetric there are more negative values than positive values:
- x > 0 : 1 <= x <= 2 **31 – 1
- x = 0
- x < 0 : -2 ** 31 <= x < 0
This means that the value 2 ** 31 is too big for a signed integer. And how can we trigger such a large quotient?
MIN_INT / -1
Since this is a relatively unknown edge case, the PHP implementation failed to handle the exception, resulting in a Denial-Of-Service (DoS) when parsing the hostile file.
Comment: credit for Ido for pointing out a mistake in the original post in which I mistakenly focused the remainder instead of the quotient.
Added Bonus:
It is somewhat common to implement the ABS macro like this:
#define ABS(_X_) ( (_X_) >= 0 (_X_) ? (-1 * (_X_)) )
However, if we look again at the MIN_INT case, we will see that the multiplication will create a value that is outside the range of a signed int. And so in our case the result will remain MIN_INT, and will remain negative.
White hat security researcher. Recently finished my M.s.c at TAU, and now focus on security research, mainly in open sources. View all posts by eyalitkin