Introduction to Bypassing PHP strcmp()
What will be covered today?
- What is strcmp()
- Buggy Code review
- Bypassing strcmp()
- Fixing the bug(s)
What is PHP strcmp()?
str = String & cmp = Compare
str+cmp=strcmp()
The strcmp() function compares two strings, please note the strcmp() function is case-sensitive.
Syntax: strcmp(string1,string2) (String1) specifies the first string to compare and (string2) specifies the second string to compare.
Return Values:
0 - if two strings are equal.
<0 - if string1 is less than string2
0 - if string1 is greater than string2
Example:
<?php
echo strcmp("HackThePlanet!","HackThePlanet!")."<br>"; // the two strings are equal
echo strcmp("HackThePlanet!","Hacker")."<br>"; // string1 is greater than string2
echo strcmp("HackThePlanet!","HackThePlanet! H4x0r!")."<br>"; // string1 is less than string2
?>
Note: This will help you along your journey in understanding and mastering web application security, I highly suggest researching more in-depth any information shown in this blog if you are curious.
Solving the challenge
An overview of the challenge, when visiting the URL we get greeted with the following message.
I have forgot my secret token password :( can you recover it for me? The source code can be found at /src.txt I need my secret flag.txt file
It seems that someone has forgot their "token" which allows him to view "flag.txt" sounds interesting? It also mentions that we can view the source at /src.txt, lets check that out shall we?
<?php
$secret_token = (file_get_contents("token.txt"));
if(isset($_GET['token'])){
if(strcmp($secret_token, $_GET['token']) == 0){
$success = true;
echo (file_get_contents("flag.txt"));
}
else{
$success = false;
}
}
else {
$success = false;
}
?>
The code is very messy so there may be a bug, lets dig deeper and break down the code.
$secret_token = (file_get_contents("token.txt"));
Here it is defining a variable called "secret_token" which contains a secret token its using the file_get_contents function. The file_get_contents() reads a file into a string.
if(isset($_GET['token']))}
if(isset($_GET['token'])) line checks whether the token parameter in the URL is set and is not a NULL value.
if(isset($_GET['token']))}
if(strcmp($secret_token, $_GET['token']) == 0){
$success = true;
echo (file_get_contents("flag.txt"));
}
This is doing a simple strcmp between our GET request and the $secret_token variable. == is an insecure comparison (loose comparison known as the Equal Operator) if the two strings are equal to each other then it returns true, this does not check data types. If we submit an empty array token[]=something PHP translates GET variables like this to an empty array which causes strcmp() to barf: strcmp(array(), "token") -> NULL which will return 0
Hypothetically speaking if we send a request like example.com/challenge/secret.php?token[]=he.. this should return true and authenticate us (This is an authentication bypass) Its basically a Type Juggling Vulnerability.
Flag: RST{s0me_ways_0f_comparing_tw0_strings_is_v4ry_ins4cure}
Authentication Bypassed! Nice :)
Patching the bug
As mentioned the vulnerability arises when we use loose comparisons so if we use a strict comparison that may help as it also checks data types.
What's the difference between a loose comparison and a strict comparison?
The operator == casts between two different types if they are different, while the === operator performs a 'typesafe comparison'. That means that it will only return true if both operands have the same type and the same value
The strict comparison checks the data types as mentioned above however the loose comparison does not.
Constructing a patched version of this code?
<?php
$secret_token = (file_get_contents("token.txt"));
if(isset($_GET['token'])){
if(strcmp($secret_token, $_GET['token']) === 0){
$success = true;
echo (file_get_contents("flag.txt"));
}
else{
$success = false;
}
}
else {
$success = false;
}
?>
We can try using a strict compairison "===" lets give try this!
Bingo! It's now patched, such an easy but critical mistake can happen just by either mis-typing or using the wrong comparisons.
Notes
I suggest always using strict comparisons UNLESS you really have/want to use loose comparisons.
Google anything you're unsure on E.g. Type Juggling Vulnerabilities.
That's all, I hope you learned something today!