Post

ACECTF 2025 - web - Webrypto

A PHP web challenge exploiting an error-handling flaw in md5()

ACECTF 2025 - web - Webrypto

Initial Analysis

Challenge Description

1
2
3
4
5
I think we can all agree that most of us grew up watching the iconic cartoon Tom & Jerry. Every kid would feel that surge of adrenaline during the thrilling chases and chaotic conflicts between the mischievous mouse and the ever-determined cat. The excitement of those scenes—the heart-pounding moments of escape—sometimes felt almost real.

But then, I heard a little rumor: what if all those chases were fake? What if Tom and Jerry were actually friends all along? That revelation shook me. I had no one to ask about this mind-bending twist, so I decided to take matters into my own hands—I created a web app to settle this question once and for all.

I know the truth now. Do you think you can uncover it too?

When visiting the website, I found a PHP source code snippet:

1
2
3
4
5
6
7
8
9
10
11
12
<?php
include('flag.php');
highlight_file(__FILE__);

// Check if parameters 'tom' and 'jerry' are not equal
if ($_GET['tom'] != $_GET['jerry']) {
    echo "<br>Parameter 1 Met!<br>";

    if (md5('ACECTF' . $_GET['tom']) == md5('ACECTF' . $_GET['jerry'])) {
        echo $FLAG;  // If the condition is true, print the flag
    }
}

Understanding the Code

  1. The script includes flag.php, which contains the flag.
  2. The source code of the file is displayed.
  3. It checks if the tom and jerry GET parameters have different values.
  4. It applies an MD5 hash with the salt ACECTF and compares the results.
  5. If both conditions are satisfied, the flag is printed.

Analysis and Exploitation

Step 1: Bypassing the First Condition

To pass the first condition, tom and jerry must have different values. A simple URL like this works:

1
https://webchall.link/?tom=a&jerry=b

This satisfies $_GET['tom'] != $_GET['jerry'].

Step 2: Bypassing the Hash Check

PHP’s MD5 function is vulnerable to hash collisions, but since a salt (ACECTF) is added, a traditional MD5 collision attack won’t work. However, there is another vulnerability in PHP: an error-handling flaw caused by hashing an array.

Step 3: Exploiting the Vulnerability:

If we send the parameters as arrays, PHP will treat them differently when hashing. Using the following payload:

1
https://webchall.link/?tom[0]=0&jerry[1]=0
  • tom[0] = 0 and jerry[1] = 0 are treated as arrays.
  • The first condition (tom != jerry) is still true because PHP treats array comparisons differently. Since tom = array(0=>0) and jerry = array(1=>0), they are considered different arrays, thus passing the first check.
  • When PHP tries to hash the values using MD5, it expects a string but receives an array, leading to an error-to-null vulnerability.
  • Since md5("ACECTF".NULL) == md5("ACECTF".NULL) always evaluates to true, this occurs because PHP attempts to hash an array, which is invalid. When md5() receives an array instead of a string, PHP triggers a warning: Warning: md5() expects parameter 1 to be string, array given. As a result, MD5 returns NULL for both values, making them identical and passing the comparison check. When attempting to hash an array, PHP throws a warning and returns NULL. As a result, both hashes compare as equal, satisfying the second condition and revealing the flag!

Conclusion

This challenge demonstrates an error-handling flaw in PHP, where comparisons between arrays and strings behave unexpectedly. Instead of exploiting hash collisions directly, we bypassed the security check using a PHP array conversion trick.

Key Takeaways

  • PHP has weak type handling that can lead to unintended vulnerabilities.
  • MD5 is not collision-resistant, but adding a salt makes basic attacks harder.
  • Using arrays in GET parameters can lead to unexpected behaviors in security checks.
  • Error-handling flaws can be exploited when input validation is not strict.
  • PHP generates a warning when trying to hash an array, but the execution continues, which can be leveraged for exploits.

Hope this write-up helps you in future CTF challenges!

This post is licensed under CC BY 4.0 by the author.