We can attempt to hash various values, like uidusernamefilename, and many others, and see if any of their md5 hashes match the above value. If we find a match, then we can replicate it for other users and collect their files. For example, let’s try to compare the md5 hash of our uid, and see if it matches the above hash:

echo -n 1 | md5sum

Unfortunately, the hashes do not match. We can attempt this with various other fields, but none of them matches our hash. In advanced cases, we may also utilize Burp Comparer and fuzz various values and then compare each to our hash to see if we find any matches. In this case, the md5 hash could be for a unique value or a combination of values, which would be very difficult to predict, making this direct reference a Secure Direct Object Reference. However, there’s one fatal flaw in this web application.

Function Disclosure

As most modern web applications are developed using JavaScript frameworks, like AngularReact, or Vue.js, many web developers may make the mistake of performing sensitive functions on the front-end, which would expose them to attackers. For example, if the above hash was being calculated on the front-end, we can study the function and then replicate what it’s doing to calculate the same hash. Luckily for us, this is precisely the case in this web application.

If we take a look at the link in the source code, we see that it is calling a JavaScript function with javascript:downloadContract('1'). Looking at the downloadContract() function in the source code, we see the following:

function downloadContract(uid) {
    $.redirect("/download.php", {
        contract: CryptoJS.MD5(btoa(uid)).toString(),
    }, "POST", "_self");
}

In this case, the value being hashed is btoa(uid), which is the base64 encoded string of the uid variable, which is an input argument for the function. Going back to the earlier link where the function was called, we see it calling downloadContract('1'). So, the final value being used in the POST request is the base64 encoded string of 1, which was then md5 hashed.

echo -n 1 | base64 -w 0 | md5sum

We are using the -n flag with echo, and the -w 0 flag with base64, to avoid adding newlines, in order to be able to calculate the md5 hash of the same value, without hashing newlines, as that would change the final md5 hash.

Mass Enumeration

for i in {1..10}; do echo -n $i | base64 -w 0 | md5sum | tr -d ' -'; done
#!/bin/bash
 
for i in {1..10}; do
    for hash in $(echo -n $i | base64 -w 0 | md5sum | tr -d ' -'); do
        curl -sOJ -X POST -d "contract=$hash" http://SERVER_IP:PORT/download.php
    done
done