xt:Commerce 3.X Second Order SQL Injection Vulnerability (xtc_validate_email) felix |at| malloc.im =============================================================================== Overview: xt:Commerce 3 is an open source shopping software based on osCommerce. It is vulnerable to a second order SQL injection attack that can be used to reset the password of arbitary users and admins Risk: Critical Details: xt:Commerce 3.X is vulnerable to a second order SQL injection in the password_double_opt.php file. The script uses the deprecated eregi function (http://php.net/manual/en/function.eregi.php) to validate customer e-mail addresses: function xtc_validate_email($email) { $valid_address = true; $mail_pat = '^(.+)@(.+)$'; $valid_chars = "[^] \(\)<>@,;:\.\\\"\[]"; $atom = "$valid_chars+"; $quoted_user='(\"[^\"]*\")'; $word = "($atom|$quoted_user)"; $user_pat = "^$word(\.$word)*$"; $ip_domain_pat='^ \[([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\]$'; $domain_pat = "^$atom(\.$atom)*$"; if (eregi($mail_pat, $email, $components)) { ..... ..... return $valid_address; } eregi is vulnerable to nullbyte injections, the function considers an embedded nullbyte as the end of the string and won't parse characters after it. This means a string like "foo@example.com\00' SQL INJECTION" will pass the xtc_validate_email function. The account_edit.php file allows registered customers to change their email address and executes the following code: .... $email_address = xtc_db_prepare_input($_POST['email_address']); // xtc_db_prepare_input is a wrapper for stripslashes() ... if (strlen($email_address) < ENTRY_EMAIL_ADDRESS_MIN_LENGTH) { $error = true; $messageStack->add('account_edit', ENTRY_EMAIL_ADDRESS_ERROR); } if (xtc_validate_email($email_address) == false) { $error = true; $messageStack->add('account_edit', ENTRY_EMAIL_ADDRESS_CHECK_ERROR); } After that the variable $email_address is stored in the database using a prepared statement that is not vulnerable to a SQL injection. The final step of this attack abuses the password recovery function in the password_double_opt.php file: .... if (isset ($_GET['action']) && ($_GET['action'] == 'verified')){ $check_customer_query = xtc_db_query("select customers_id, customers_email_address, password_request_key from ".TABLE_CUSTOMERS. "where customers_id = '".(int)$_GET['customers_id']."' and password_request_key = '".xtc_db_input($_GET['key'])."'"); $check_customer=xtc_db_fetch_arr($check_customer_query); .... $newpass=xtc_create_random_value(ENTRY_PASSWORD_MIN_LENGTH); $crypted_password=xtc_encrypt_password($newpass); ..... xtc_db_query("update ".TABLE_CUSTOMERS." set customers_password = ' ".$crypted_password."' where customers_email_address = ' ".$check_customer['customers_email_address']."'"); As you can see the stored email (customers_email_address) is extracted out of the database and is used without escaping for the UPDATE query in the last line. This enables an attacker to set the password of an arbitary user or admin to the generated random string, which will be send to the email address before the nullbyte. Exploit: The following steps can reproduce the attack: 1. Register as a customer with an valid mail address (foo@evil.com) 2. Use the password recovery function to request a new password. You will get an verification email with a randomized url you need in step 4. 3. Change your email address in the customer area to abuse the SQL Injection: foo@evil.com\0 or customers_id = 1 4. Visit the url specified in the verification email. This will change the password of the administrator with id 1. This new password will arrive per mail. Fix: Change $check_customer['customers_email_address'] to xtc_db_input($check_customer['customers_email_address'] and insert the following line at the beginning of the xtc_validate_email function: if (strpos($email,"\0")!==false) {return false;} This bug was reported in January 11 but no official patch is available. _______________________________________________ Full-Disclosure - We believe in it. Charter: http://lists.grok.org.uk/full-disclosure-charter.html Hosted and sponsored by Secunia - http://secunia.com/