PHP loose comparision & type juggling
PHP LOOSE COMPARISION & TYPE JUGGLING
SVTH: Phạ Đức Tùng, Đỗ Nguyễn Hoàng Ân
GVHD: ThS Đặng Đình Quân
ắ — PHP, one of the most prominent scripting programming languages along with
JavaScript and Python, ―especially suited to web development‖ [1] is ―fast, flexible and pragmatic‖ [1].
Naturally, there is no type-safe restriction but loose comparison. In what was an effort to produce a
more straightforward language to developer, variables are not meant to be declared with an explicit
type. While this does compose a flawlessly coding experience, chances for application result in state
of perplexing persists.
This paper aims to demonstrate the variables comparison mechanic and type coercion feature
of PHP. Furthermore, this study enlightens one of the most crucial issues of rookie PHP programmers
or even intermediate ones that undeviatingly runs the web application to be vulnerable.
ừ kh a— loose comparision, PHP, type juggling
I. INTRODUCTION
In programming, declaring a variable, which requires variable‘s data type and the label
or name of that variable, is a basic step for beginners to learn any programming languages.
After that, variables will be initialized with a value with the same data type as declared in the
variable declaration. If there are any problems, an exception will be announced to
programmers. However, in PHP, there is no need to apply any type specification in the
process of declaration, only the name of the variable and its value. Therefore, type juggling
feature is created to deal with PHP variables. [2]
II. VALUES DIFFERENTIATION IN PHP
For developers familiar with compiled languages for instance Java, C#..., such
languages provide type-safe flow, restrict programmers to use particular datatype at
compilation time. The feature itself keeps the application a distance as far as possible away
from bugs. However, considering the personal preferences, PHP comes with both loose
comparison operator == and strict comparison operator ===.
A. Type checking
In order for your program to run, all the variable types must be verified. This Typing
Checking may provide a static check (compile-time) or at dynamic check (run-time).
Therefore, if a language lacks its typing rules strongly, one can refer to the process as Weakly
typed, if not, as Strongly typed Invalid source specified.. Type checking is to make sure that
the program is ―type-safe‖, reduce the risk of type errors. For instance:
int AddTwoNumbers(int a, int b) {
return a + b;
}
98
Normally, if programmers try to call that using:
int Sum = AddTwoNumbers(5, "5");
The compiler would throw an error, because programmers passing a string(―5‖), but the
argument expects an integer.
Therefore, in a type-unsafe programming language like PHP, it is possible to use the
function like this:
AddTwoNumbers(5, "5");
Although many languages can use the + operator for strings, integers and float together, but
this often result in a type error because this expression is usually not meant to execute
multiple data types.
Many programming languages are considered not to be type - safe, it means there are no
action that prevent a type-error, and they are Dynamically typed languages.
1) Loose vs. Strict
a) Loose comparison
The tables Invalid source specified. below describe more other types, where anything
in double quotes is string:
TRUE
TRUE
FALSE
FALSE TRUE
FALSE TRUE
FALSE TRUE FALSE FALSE TRUE
FALSE TRUE FALSE FALSE TRUE
FALSE FALSE TRUE
FALSE FALSE TRUE FALSE FALSE FALSE FALSE
FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE
FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE
FALSE FALSE FALSE FALSE TRUE
1
0
-1
"1"
"0"
FALSE TRUE
FALSE TRUE
FALSE FALSE FALSE FALSE
FALSE TRUE FALSE
FALSE FALSE
"-1"
NULL
FALSE FALSE
TRUE
array() "php" ""
TRUE
FALSE
1
FALSE TRUE
TRUE
TRUE FALSE
FALSE TRUE
FALSE FALSE TRUE
FALSE TRUE
FALSE FALSE
TRUE
0
FALSE TRUE
TRUE
TRUE
-1
TRUE
TRUE
FALSE FALSE FALSE TRUE
FALSE TRUE
FALSE FALSE
FALSE FALSE
FALSE FALSE
FALSE FALSE
FALSE TRUE
FALSE FALSE
"1"
"0"
"-1"
NULL
FALSE TRUE
TRUE
FALSE TRUE
FALSE TRUE
TRUE
TRUE
array() FALSE TRUE
FALSE FALSE FALSE FALSE FALSE FALSE TRUE
"php"
""
TRUE
FALSE FALSE TRUE
FALSE TRUE
FALSE FALSE FALSE FALSE FALSE FALSE
TRUE
FALSE
FALSE TRUE
FALSE FALSE FALSE FALSE TRUE
FALSE
FALSE TRUE
Table 1 - Loose comparison
A loose comparison in PHP is an operation which use two equal signs (==). It can lead
echo gettype(0); // Outputs "integer"
to som
echo gettype(FALSE); // Outputs "boolean"
echo gettype('guitar'); // Outputs "string"
Here, the confusion starts when comparing these types of data:
var_dump(0 == FALSE); // bool(true)
var_dump(0 =='guitar'); // bool(true)
var_dump(FALSE=='test'); // bool(false)
This is appropriate when 0 and FALSE are equal as they all represent ―falsy‖ value.
However, when comparing 0 with ―guitar‖, it is almost impossible to make any conclusion
that the output returns TRUE. In fact, because PHP will manage to convert ―guitar‖ to an
integer, so it turns into 0 for the comparison.
In the last line of the example, the result for FALSE and ―test‖ is FALSE. It just
conflicts the previous example. If ―test‖ become 0, and 0 == FALSE, why it does not become
TRUE?
Therefore, in majority cases, loose comparisons are not a problem. But it does cause
really annoying bugs and provides weaknesses in security.
b) Strict comparison
TRUE
FALSE
FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE
FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
1
0
-1
"1"
"0"
"-1"
NULL
array()
"php" ""
TRUE
FALSE
1
TRUE
FALSE FALSE
FALSE FALSE
FALSE FALSE
FALSE FALSE
FALSE FALSE
FALSE FALSE
FALSE FALSE
FALSE FALSE
FALSE FALSE
FALSE FALSE
FALSE TRUE
0
-1
"1"
"0"
"-1"
NULL
array()
FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE
$num_int = 7
"php"
""
FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
TRUE
FALSE
$string_one = "7_string";
$st
F
r
A
i
LS
n
E
g_
F
t
A
w
LS
o
E
=
FA
"7";FALSE FALSE FALSE FALSE FALSE FALSE FALSE
LS
E
FALSE TRUE
if ($num_int === $ string_one) {
// This will return False
echo("Cannot print");
}
if ($num_int === $string_two) {
// This condition statement will return False
value
echo("Cannot print");
}
With this strict comparison, programmers can avoid many unexpected bugs, which makes the
program become more robust.
B. Type juggling
The reason behind loose comparison in PHP is because of ―type juggling‖, which is
sometime addressed as ―type coercion‖. An explanation for this term is that when executing
an operation, PHP will have to convert them to the most appropriate type so that they are
computable. For instance:
$test_int = 1;
$test_str = "1";
if ($test_in == $test_str) {
echo("PHP can compare int and string");
} // no error
// Output: PHP can compare int and string
100
The statements will run with no problems and output ―PHP can compare int and string.‖
This might seem helpful at first because programmers are flexible in handling different types
of user inputs.
However, in real world situation, this ―type juggling‖ can also contain considerable
amounts of bugs and security vulnerabilities also. As example:
echo '40th' + 7; // Outputs 47
This unexpected result means that if a string starts with a number, PHP will try to
extract that number and use it as a value for the mathematical operations. This problematic
behavior also happens when programmers try to do an operation with a string which does not
contain any integer:
echo 'fortieth' + 7; // Outputs 7
This should not be computed, because they are different in both data type and value.
However, this PHP‘s type coercion still tries to convert the string to 0, then execute the
operations. Although this does not change the types of the variable themselves, the only
change is in how the operands are evaluated and what type of the expression itself isInvalid
source specified.
iii. VULNERABILITIES ARISE
C.Magic trick for the exploitation
Since == is the default comparison operator in other languages, bugs emerge in
apprentice developer‘s PHP program is reasonably ordinary. Notwithstanding, even though
type juggling is not facile to be truly exploit because the input parse in HTML is always string
after transferring to the program, still attacker can take advantage to dig out the application
if ($_POST["password"] == "@dm1np@55w0rd") {
respec
login_with_role($this->ROLE_ADMIN);
}
The code clearly demonstrates the fact that if password was submitted as 0, application
would have given admin permission undoubtedly. This is a dream for any cybercrime!
As been stated, HTML input parses the property to string, thus, $_POST["password"]
would be ―0‖ instead of 0 and PHP performs no type conversion. Yet how about the
application manages input by using famous json_decode() or unserialize(), which are trendy
in modern RESTful API backed webservice:
// JSON blob looks like this:
//{
// "username": "admin",
// "password": 0
//}
$credential = json_decode($_POST['credential']);
// vulnerable
if ($credential["username"] == "admin" &&
$credential["password"] == "@dm1np@55w0rd") {
login_with_role($this->ROLE_ADMIN);
// the Laravel encryption payload
{
}
"iv": "137f87545d8d2f994c65a6f336507747",
"value":
"c30fbe54e025b2a509db7a1fc174783c35d023199f9a0e24ae23a934277aec66",
"mac":
interpr
"68f6611d14aa021a80c3fc09c638de6de12910486c0c82703315b5d83b8229bb"
manip
}
place,
// the neglected MAC check code
$payload = json_decode(base64_decode($payload), true);
study
if ($payload['mac'] != hash_hmac('sha256', $payload['value'], $this-
specif
>key))
throw new DecryptException("MAC for payload is invalid.");
Obviously, as mentioned in Section II - Division 2.3, PHP compulsorily transform a
string into a number while in loose comparison, hence:
"68f6...29bb" => int(68)
The MAC itself, in substance, is a result of hexadecimal string calculated by
hash_hmac(), along these lines, if the encryption payload was provided with an integer, type
juggling arises:
{
"iv": "137f87545d8d2f994c65a6f336507747",
"value":
"c30fbe54e025b2a509db7a1fc174783c35d023199f9a0e24ae23a934277aec66",
"mac": 68
}
This vulnerability result in ―padding oracle‖, ciphertext decryption, arbitrary text without
capturing the encryption key, sensational repercussion of cryptography world. According to
MWR InfoSecurity (2014), the indicated exploitation of the crypto flaw leads to
impersonation via ―Remember Me‖ cookie and RCE (the most dangerous) with possibly other
bugs.
102
D. Example of vulnerabilities
The following challenge comes from a learning platform, hosted externally on the
speculation that the source would be broken in the future, which can be found at
secret hidden behind secret.php, source code attached:
function gen_secured_random() { // cause random is the way
$a = rand(1337,2600)*42;
$b = rand(1879,1955)*42;
$a < $b ? $a ^= $b ^= $a ^= $b : $a = $b;
return $a+$b;
}
function secured_hash_function($plain) { // cause md5 is the best hash ever
$secured_plain = sanitize_user_input($plain);
return md5($secured_plain);
}
function sanitize_user_input($input) { // cause someone told me to never
trust user input
$re = '/[^a-zA-Z0-9]/';
$secured_input = preg_replace($re, "", $input);
return $secured_input;
}
require_once "./secret.php";
if (isset($_POST['s']) && isset($_POST['h'])) {
$seed = sanitize_user_input($_POST['s']);
$hash = secured_hash_function($_POST['h']);
$r = gen_secured_random();
if($seed != false && $hash != false) {
if($seed.$r == $hash) {
echo "Well done! The flag is ${flag}";
}
else {
echo "Fail...";
}
}
else {
echo "Hmmm...";
}
} else {
echo "input please";
}
This section might walk the challenge through the solution!
It is observable that the one and only way to get the flag is to make $seed concatenates
$r looks like $hash. However, $r is absolutely randomized, unpredictable; thus, forcing these
two strings to be total equal is impassable. Paying attention to $hash, the input hashed with
MD5 algorithm. As stated, PHP type juggling convert any string resembles number into
number:
echo('0e462...854' == '0efwa...1j2d') // true
The line of code is actually comparing 0 with 0. Indeed, there is existence of a hash
titled ―magic hash‖ Invalid source specified.:
echo hash('md5','240610708',false) // 0e462097431906509019562988736854
Similarly, $seed concatenates $r, as well as $hash, can be converted to 0. Since $r is a
random number, the $seed could take ―0e‖ as input to produce a number-like string:
―0e153…236‖. For elucidation:
E. Type Juggling Evasion
Study of the research shows that developers have several approaches to stay away from
$a = 7;
this b
$b = "7_string";
―===
echo($a === $b); // false - good
only if
echo($a === (int) b); // true - bad
It is preservable that casting type immediately before comparing would cause an
strcmp(array(0 => ""), "0a37...c11"); // will return 0 - confused
enigm
strcmp((string) array(0 => ""), "0a37...c11"); // type-safed cast, error
should be thrown
IV. KẾT LUẬN
According to the research, PHP loose comparison and type juggling cause issues for
beginner in PHP developing or even intermediate programmers, therefore, the results do
support the hypothesis. Moreover, this paper provided a way for developers to avoid
aforementioned mistake and write code more precisely.
PHP is such a fantastic programming language that is powerful (blogging system
WordPress), deep (social network Facebook) and simple for beginner. Despite having the
flexibility, PHP sacrifices security for ease of use, numbers of features provoke grievous
exposure. Such bugs, additionally, can create superfluous pitfalls into which even professional
not on guard (MAC verification by Laravel in 2013 was broken again after 2 months Invalid
104
source specified.). PHP developers should always be cautious at comparing values in order to
avoid type juggling.
REFERENCES
[1] "PHP: TYPE JUGGLING - MANUAL", PHP.NET, 2020. [ONLINE]. AVAILABLE:
TTPS://WWW.PHP.NET/MANUAL/EN/LANGUAGE.TYPES.TYPE-JUGGLING.PHP.
[2] "PHP TYPE JUGGLING - PHPPOT", PHPPOT, 2020. [ONLINE]. AVAILABLE:
HTTPS://PHPPOT.COM/PHP/PHP-TYPE-JUGGLING/.
[3] M. BHATNAGAR, "MAGIC LIES HERE - STATICALLY VS DYNAMICALLY TYPED
LANGUAGES", MEDIUM, 2020. [ONLINE]. AVAILABLE: HTTPS://ANDROID.JLELSE.EU/MAGIC-
LIES-HERE-STATICALLY-TYPED-VS-DYNAMICALLY-TYPED-LANGUAGES-D151C7F95E2B.
[ACCESSED: 24- APR- 2020].
[4] "LARAVEL COOKIE FORGERY, DECRYPTION, AND RCE", F-SECURE LABS, 2020.
[ONLINE]. AVAILABLE: HTTPS://LABS.F-SECURE.COM/ARCHIVE/LARAVEL-COOKIE-FORGERY-
DECRYPTION-AND-RCE/. [ACCESSED: 30- APR- 2020].
[5] R. HANSEN, "MAGIC HASHES", WHITEHATSEC.COM, 2020. [ONLINE]. AVAILABLE:
HTTPS://WWW.WHITEHATSEC.COM/BLOG/MAGIC-HASHES/. [ACCESSED: 30- APR- 2020].
Bạn đang xem tài liệu "PHP loose comparision & type juggling", để tải tài liệu gốc về máy hãy click vào nút Download ở trên
File đính kèm:
php_loose_comparision_type_juggling.pdf

