The casting case

No, this isn’t a post on theater :) rather it is an interesting case of how a number gets “casted” from different types effectively bypassing safety checks and finally causing a crash to occur – and possibly the execution of code, as the memmove function is called with an overly large value to use for copying.

It starts of with a program receiving a value of -2147483648 as the length, why is this value important? it has certain characteristics to it which is important:
1) It had to be negative
2) It had to be fairly large as it needs to overflow the a variable of a type of int
3) It couldn’t be too large as there were checks just before it to make sure it was too big

This magic number is not accidental it is actually (if you look at it in hex) it is the 0×80000000 equivalent, i.e. it is the negative representation of this number. So as soon as you cast it to “unsigned int”, it looks positive, and when you cast it to just “int” it looks negative.

So if you programmed your code to do a check, and you didn’t make sure you casted the value when you did the check, for example you did:
if (con->content_len < buffered_len)

Where content_len is an "int", while you are comparing to an "unsigned int" value, the comparison will be flawed and the check will be true, even if the value being passed is negative and should be discarded.

Further, if you then call:
memmove(conn->buf, conn->buf + conn->request_len, conn->content_len);

The memmove’s last parameter is defined as an “unsigned int”, which in turn will cause this code to copy a positive value, rather then a negative value (not sure this would have helped in this case…), and in our scenario a very large memmove copy – which causes of course an Access Violation as the function reads data it shouldn’t be able to access.

This type of vulnerability and others like it can be easily detected by using beSTORM fuzzer, as it has the inherited capabilities of checking the relationships of values and their length, such as in this case.

UPDATE: My mistake on the example, my copy-paste skills were a bit flawed in this… I placed the patched version instead of the unpatched one.. causing the mixup, thanks for pointing it out jduck.

  • jduck

    The example is incorrect. If either side of the comparison is unsigned then integer promotion will result in an unsigned comparison.

    It is only when both sides of the comparison are signed that this issue will occur. This also applies to the case where you mistakenly cast the unsigned value to a signed one, oops hehe