Tags: hash-collision web crc16 crc8
Rating:
## Introduction
### Context Explanation
*Craphp* is a web-based CTF challenge where the user is presented with an interface asking for a password to retrieve a flag. The challenge also provides access to the server's source code (`index.php`), which we leveraged to analyze the vulnerabilities and design a strategy for exploitation. The critical insight in solving this challenge lies in understanding and exploiting weaknesses in the use of CRC (Cyclic Redundancy Check) hash algorithms within the authentication logic.

### Directive
Our objective is to bypass the authentication mechanism and eventually retrieve the flag from the server. The crux of the solution is identifying a vulnerability in the CRC hash algorithm used for password comparison, which allows us to craft a collision: a password that produces the same two hash outputs (CRC16 and CRC8) as the hardcoded password.
---
## Solution
### Analyzing Source Code
By examining the source code provided (`index.php`), we identified the fundamental authentication mechanism:
1. The hardcoded password is stored in `$MYPASSWORD = "AdM1nP@assW0rd!";`.
2. The authentication logic proceeds as follows:
- User-submitted input (`$_POST['password']`) is rejected if its length does not match that of `$MYPASSWORD`.
- Two hash functions `crc16` and `crc8` calculate hash values for the hardcoded `$MYPASSWORD` and the submitted password.
- The calculated hashes (`$pwhash3` and `$pwhash4`) from the user's password are compared against the stored hashes (`$pwhash1` and `$pwhash2`) from `$MYPASSWORD`.
- If both hashes match but the submitted password does not equal `$MYPASSWORD`, the server results in a successful bypass and sends back the hidden `$FLAG`.
Here’s the relevant snippet of the code where the authentication logic is implemented:
```php
if(isset($_POST['password']) && strlen($MYPASSWORD) == strlen($_POST['password'])) {
$pwhash1 = crc16($MYPASSWORD);
$pwhash2 = crc8($MYPASSWORD);
$password = $_POST['password'];
$pwhash3 = crc16($password);
$pwhash4 = crc8($password);
if($MYPASSWORD == $password) {
die("oops. Try harder!");
}
if($pwhash1 != $pwhash3) {
die("Oops. Nope. Try harder!");
}
if($pwhash2 != $pwhash4) {
die("OoOps. Not quite. Try harder!");
}
$access = true;
if($access) {
echo "You win a flag: $FLAG";
} else {
echo "Denied! :-(";
}
} else {
echo "Try harder!";
}
```
### Observations and Vulnerability Insight
At first glance, this design might seem secure. However, a significant cryptographic vulnerability exists due to the use of non-cryptographically secure hash functions (`crc16` and `crc8`):
- **CRC Collisions:** Both CRC16 and CRC8 are designed for error detection in transmission systems and **not** for cryptographic purposes. They are not resistant to collisions—different inputs can produce identical CRC values. This is especially problematic in situations like this, where multiple CRC hashes are used for validating passwords.
- An adversary can exploit these weak hash functions to generate a password that produces matching CRC16 **and** CRC8 hash values without knowledge of the real password.
Given this, the attack boils down to creating a **password collision** such that:
```php
"AdM1nP@assW0rd!" != $password
strlen("AdM1nP@assW0rd!") == strlen($password)
crc16("AdM1nP@assW0rd!") == crc16($password)
crc8("AdM1nP@assW0rd!") == crc8($password)
```
---
## Exploitation
### Crafting the Collision
Our strategy involves brute-forcing to find a password of the same length as `$MYPASSWORD` (15 characters) that satisfies the CRC collision condition.
We wrote a PHP script to automate this process. The script:
1. Computes the CRC16 and CRC8 of the hardcoded `$MYPASSWORD`.
2. Randomly generates candidate passwords of the same length.
3. Computes CRC16 and CRC8 for each candidate password.
4. Compares the hash values of each candidate with the corresponding hashes of `$MYPASSWORD`.
5. Stops when a collision is found and outputs the colliding password.
Here is the script:
```php
> 1) ^ 0xA001);
} else { $crc = $crc >> 1; }
}
}
return $crc;
}
// https://stackoverflow.com/questions/507041/crc8-check-in-php/73305496#73305496
function crc8($input)
{
$crc8Table = [
0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
];
$byteArray = unpack('C*', $input);
$len = count($byteArray);
$crc = 0;
for ($i = 1; $i <= $len; $i++) {
$crc = $crc8Table[($crc ^ $byteArray[$i]) & 0xff];
}
return $crc & 0xff;
}
?>
```
---
### Accessing the Flag
Running the script eventually yields a matching random password that satisfies the CRC collision condition:
```shell
┌──(kali㉿kali)-[~/Desktop]
└─$ php crc_collision.php
Collision found ! : Tp#UTARjQMz+6X8
```
Submitting this password to the web application succeeds in bypassing the CRC checks, and the server returns the flag:

```
You win a flag: ENO{Cr4hP_CRC_Collison_1N_P@ssw0rds!}
```