Skip to content

15. ATutor LMS Type Juggling Vulnerability

Get started

URL Username Password

http://atutor/ teacher teacher123

ssh://atutor root toor

With the Atmail VM being retired, you can use Python on the ATutor server to handle emails by running sudo python3 -m smtpd -n -c DebuggingServer 127.0.0.1:587 2>&1 and configuring Postfix to use localhost instead of Atmail's IP address. While this command is running, it will print emails to the terminal.

# Replace 192.168.121.106 with the IP address of your Atmail VM
sudo cat /etc/postfix/transport
...
offsec.local    smtp:[192.168.121.106]:587
...

# Updating the Postfix transport configuration
sudo postmap /etc/postfix/transport

15.2. PHP Loose and Strict Comparisons

In this case, the vulnerability revolves around the use of loose comparisons of user-controlled values, which results in the execution of implicit data type conversions, i.e. type juggling. Ultimately, this allows us to subvert the application logic and perform protected operations from an unauthenticated perspective.

alt text

alt text

15.3. PHP String Conversion to Numbers

Try the following equations in different PHP versions. It may show different results.

$ php -a
Interactive mode enabled

php > var_dump('0eAAAA' == '0');
bool(false)

php > var_dump('0e1111' == '0');
bool(true)

php > var_dump('0e9999' == 0);
bool(true)

15.4. Vulnerability Discovery

To recap what we know so far, confirm.php does not require authentication and can be used to change the email of an existing user. We also know from the previous analysis that in the code logic to update an existing user email address:

  • the $id GET variable corresponds to the unique ID value assigned to each ATutor user in the database and is under attacker control

  • the $e GET variable corresponds to the new email address we would like to set and is under attacker control

  • the attacker controlled $m GET variable is used to decide if we are allowed to update the email address for the target user based on a loose comparison against the calculated $code variable

  • the $code variable is a ten characters MD5 hash substring partially under attacker control

15.5. Attacking the Loose Comparison

15.5.1. Magic Hashes

$ php -a
Interactive mode enabled

php > echo md5('240610708');
0e462097431906509019562988736854

php > var_dump('0e462097431906509019562988736854' == '0');
bool(true)

15.5.2. ATutor and the Magic E-Mail address

$code = substr(md5($e . $row['creation_date'] . $id), 0, 10);

Based on the listing above, we can deduce that in our brute force approach the only value that we can change on each iteration is the $e variable. This is the new email address that we provide for the target user. The account creation date is pulled from the database and should be static. Similarly, the account ID needs to stay static as well, since we are targeting a single account.

Again, if such a Magic Hash is found it will allow us to defeat the vulnerable loose comparison as we can set $m to zero in our GET request. The critical check between $code and $m will then look like the following:

if (0eDDDDDDDD == 0)
  UPDATE THE EMAIL ADDRESS

confirm.php:

if ($code == $m) {
        $sql = "UPDATE %smembers SET email='%s', last_login=NOW(), creation_date=creation_date WHERE member_id=%d";
        $result = queryDB($sql, array(TABLE_PREFIX, $e, $id));

0eDDDDDDDD will evaluate to zero