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  
http://se2spring2020.ezyro.com/. Assumes PHP knowledge acquired, the goal is to find the  
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].  
pdf 8 trang baolam 12860 Free
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:

  • pdfphp_loose_comparision_type_juggling.pdf