LIMB
Вход Регистрация

тема

Ломаем OpenCart

Funniestfunny · · 9 ответов · 979 просмотров

Не удалось прогрузить медиа


Всем привет, в этой статье мы рассмотрим всевозможные методы взлома OpenCart
Opencart - e-commerce CMS (т.е специальная система, позволяющая создать интернет магазин "из коробки"). OpenCart имеет несколько версий (1.5, 2.x. 3.x, 4.x). Самой популярной и по сей день является 3.x
Также существуют форки OpenCart (OcStore, LiveStore, однако они относятся к по большей части к СНГ и их трогать не будем).


Файловая структура
├── config.php - Креды к БД, также там может быть поддомен, который например не смог найти subfinder
├── admin/config.php - Тот же конфиг, только там уже раскрывается URL к админке
├── index.php - Раскрывает версию OpenCart
└── catalog/model/{имя модуля} - Здесь находятся модули опенкарта

Админка
Интерфейс админки OpenCart зависит напрямую от версии, однако зачастую вы увидите просто темно серый сайдбар
Из самого полезного в админке, как мне кажется, это возможность скачивать отдельные таблицы из БД, для этого необходимо перейти в System --> Maintenance --> Backup / Restore. Там можно снять выделение, либо же наоборот выделить определенные таблицы и скачать их
Не удалось прогрузить медиа


База данных
БД OpenCart содержит немалое количество таблиц, однако если рассматривать самые ценные, то нас интересуют всего 4 таблицы

oc_setting
oc_order
oc_user
oc_customer

oc - Это префикс таблицы, его можно изменить при первичной установке, либо совсем убрать. Мне часто попадались таргеты, где префикса не было, а также были префиксы типа ak, ws и т.д, обычно префиксы зависят от названия магазина.
Таблица oc_order содержит всю информацию о заказах (В т.ч и персоналку)
Таблица oc_customer содержит всю информацию о покупателях (Персоналка, пароли также)
Таблица oc_user содержит информацию о тех, кто может зайти в админ панель, каждому юзеру обычно дается своя группа, существует как админ, так и менеджер
Таблица oc_setting достаточно интересная таблица, она очень часто содержит креды от smtp, а также ftp/sftp

Модули
В опенкарт существует два типа модулей: Встроенные, и те, которые устанавливаются. Однако у каждого модуля есть своя функция, вот небольшой список функций которые могут быть:

Работа с заказами 
Работа с платежами
Модули для защиты сайта
Аналитические модули 
Модули, отвечающие за виджеты сайта (украшения, и т.п, они нас мало интересуют)

Модули могут быть как платными, так и бесплатными. Однако забавно, что даже в платных модулях очень часто встречаются уязвимости
Каждый желающий может написать свой модуль, а затем выложить его на маркетплейс опенкарта (https://www.opencart.com/index.php?route=marketplace/extension)



Nuclei-Шаблоны

Для определения уязвимостей на сайтах будет использоваться сканер nuclei, который позволяет писать шаблоны и удобно использовать их
Все шаблоны будут находиться здесь: https://github.com/absolutelyxfunny/opencart-templates 


Рассмотрим существующие уязвимости
1.1 Уязвимости в модулях

CVE-2025-1116 [unAuth SQLi] 
в модуле Live Ajax Search(https://www.opencart.com/index.php?route=marketplace/extension/info&extension_id=18983) в функции searchresults() не экранируется keyword, что и приводит к ошибке 

Небольшой список сайтов, где нашлась эта уязвимость
public function searchresults(){                                                                                                                                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                                                                                                                                                           
      if(isset($this->request->get['keyword'])){                                                                                                                                                                                                                                                                                                                                                                                           
          $keyword=$this->request->get['keyword'];      <-- Не экранируется,  не escape, ваще ничего                                                                                                                                                                                                                                                                                                      
      }else{                                                                                                                                                                                                                                                                                                                                                                                                                               
          $keyword='';                                                                                                                                                                                                                                                                                                                                                                                                                     
      }                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                                                                                           
      $setting1 = $this->model_setting_setting->getSetting($this->id);                                                                                                                                                                                                                                                                                                                                                                     
      $settings = $setting1['d_ajax_search_setting'];
                                                                                                                                                                                                                                                                                                                                                                                                                                           
      $params=array();                                                                                                                                                                                                                                                                                                                                                                                                                     
      foreach ($settings['extension'] as $key => $value) {                                                                                                                                                                                                                                                                                                                                                                                 
          if($value['enabled'] == 1){                                                                                                                                                                                                                                                                                                                                                                                                      
              array_push($params, $key);                                                                                                                                                                                                                                                                                                                                                                                                   
          }                                                                                                                                                                                                                                                                                                                                                                                                                                
      }                                                                                                                                                                                                                                                                                                                                                                                                                                    
      if(!empty($params) && $setting1['d_ajax_search_status'] == 1){                                                                                                                                                                                                                                                                                                                                                                       
          $result=$this->model_extension_module_d_ajax_search->search($keyword,$params);  <-- Здесь можно увидеть, что keyword напрямую подставляется                                                                                                                                                                                                                                                                                                           
          $this->response->setOutput(json_encode($result));                                                                                                                                                                                                                                                                                                                                                                                
      }                                                                                                                                                                                                                                                                                                                                                                                                                                    
  }
Небольшой список сайтов, где нашлась эта уязвимость




CVE-2024-21514 [unAuth SQLi]
Уязвимость в ядре OpenCart в модуле Divido, в одной из функций попросту не экранируется order_id, что и привело к уязвимости. На гитхабе есть сканер (поддерживающий массовое сканирование): https://github.com/bigb0x/CVE-2024-21514
Однако отмечу, что при скане почему-то таблицы удалены были, поэтому эксплуатация была невозможной 
public function getLookupByOrderId($order_id) {                                                                                                                                                                                                                                                                                                                                                                                          
      return $this->db->query("SELECT * FROM " . DB_PREFIX . "divido_lookup WHERE order_id = " . $order_id);                                                                                                                                                                                                                                                                                                                           
  }  
order_id Просто вставляется напрямую, что забавно, в другой функции, которая  выполняет тот же самый функционал order_id уже закрыт за int


return $this->db->query("SELECT * FROM " . DB_PREFIX . "divido_lookup WHERE order_id = " . (int)$order_id



Уязвимость в OpenCart Core 4.0.2.3 [unAuth SQLi] - Time based 
Как я понял, в функции Search в OpenCart версии 4.0.2.3 не экранировался search. Эта уязвимость есть в стандартных шаблонах nuclei
PoC: https://www.exploit-db.com/exploits/51940


Уязвимость в множестве модулей [UnAuth SQLi]
Это достаточно старые уязвимости, атаки были замечены еще в 2018г. Однако, они до сих пор встречаются даже на крупных сайтах 
Всего уязвимых модулей 10. Вот их список: 
1) manufacturer
2) product
3) search
4) seo
5) enquiry
6) journal3
7) pav
8) blog_list
9) blog
10) d_blog_module

1) https://site.com/index.php?route=product/manufacturer/info&manufacturer_id= 
2) https://site.com/index.php?route=product/product&path=4_16&product_id=431'
3) https://site.com/index.php?route=product/search&tag='
4) https://site.com/'
5) https://site.com/index.php?route=information/contact&enquiry='
6) https://site.com/index.php?route=journal3/product&product_id='
7) https://site.com/index.php?route=pavblog/blog&blog_id=160'
8) https://site.com/index.php?route=product/blog_list&blogger_id=11'
9) https://site.com/index.php?route=blog/blog&blog_id=140' 
10) https://site.com/index.php?route=extension/d_blog_module/search&tag='


К счастью, ребята с дамаги еще давно написали шаблон на скан таких уязвимостей, называется он id_checker
Немного уязвимых таргетов:
Шаблон для сканирования также есть на гитхабе

[0day] LFI (unauth), Модуль Image Compress, 2.5k инсталлов). Позволяет скачать config.php
Эту уязвимость нашел я еще недели 2 назад, поэтому я думаю можно считать ее 0day, т.к информации о ней в сети не нашел 
Основная проблема в том что метод getImage() может вызвать каждый, то есть нет проверки вообще существует ли сессия. А фукнция file_get_contents() читает вообще любой файл, до которого у php есть доступ. Используя это мы можем скачать config.php, или прочитать /etc/passwd
Пример уязвимых таргетов: 
Шаблон также находится на гитхабе



1.2 Мисконфиги
Создатели сайтов могут оставлять конфиг открытым пользователям, или же сделать бэкап конфига и оставить его в корне
Для определения такого у меня есть шаблон, логика проста: просто подставлять все backup расширения. В целом, таким методом можно много сканить, т.к конфиги могут называться и датами, например config.php.bak-2026, config.php.bak-2026-02-02. Вариаций очень очень много
Также можно искать на бэкап сайта / админки. Иногда на сайтах оставляют admin.zip, где может лежать сразу дамп базы, или креды к БД. В том числе оставляют и просто site.com/site.com.zip, site.com/backup.zip Там может также лежать полный бэкап сайта, вариаций тут опять же много

Пример вариаций:
config.php.bak20260102
config.php.bak2026-01-02
backup-2026-0102.zip
backup20260102.zip
admin_2026_01_02.zip
admin_20260102.zip


Шаблоны для сканирования сайта на такие дыры есть на гитхабе (zip-backup-files.yaml, OpenCartConfig.yaml)

1.3 Где брать таргеты? 
Я приложил список сайтов, которые работают на OpenCart, только убрал оттуда страны СНГ (по доменам, .com домен оставил) (https://github.com/absolutelyxfunny/opencart-templates/blob/main/OpenCart_sites.txt)
Если же вы хотите сами добывать такие сайты, то пишите сканер, либо же можете воспользоваться моим (https://forum.LIMB.cc/threads/1677). OpenCart детектить легко, например по их системе рутирования (route=extension, route=product), зачастую открытая админка (/admin), где уже говорится, что сайт на OpenCart. Также подставляется кука OCSESSID, по которой понятно, что это OpenCart
Вдобавок, можно определять гео сайта изучая куки, когда вы заходите на сайт, то он автоматически определяет валюту, например зайдя на сайт motopar.net мы можем увидеть валюту TL (Турецкая лира)    
Не удалось прогрузить медиа



Сценарий 1
1.1 Представим, у вас есть креды к БД сайта, но как попасть в базу?
Зачастую на большинстве сайтов ставят phpMyAdmin, через который как раз таки и удается попасть в БД. Либо же Adminer. Это приложения, которые позволяют управлять БД в вебе
Очень часто их легко найти: Просто подставить site.com/phpmyadmin, site.com/phpmyadmin/index.php, site.com/adminer.php. Но некоторые создатели сайтов могут их прятать, например он может находиться на поддомене phpmyadmin.site.com Или же работать исключительно на каком-то порту (например в связке с cPanel)
Также иногда у них могут быть нестандартные руты, в этом репозитории (https://github.com/kaimi-io/web-fuzz-wordlists/) есть много словарей для фаззинга, там большие словари, также там не только phpmyadmin и adminer, но и другие
1.2 Вы нашли phpmyadmin, зашли в БД, а дальше можно пойти к админке сайта, однако для начала нам нужно изменить пароль админа (Таблица oc_user). Сам OpenCart использует такую систему хеширования: sha1(salt + sha1(salt + sha1(password))). Однако пароли все равно можно менять. Копируем соль (salt) и идем на сайт(Работает только для OpenCart версий 2.0 и выше) https://speckygeek.com/tools/opencart2-password-generator/index.php, там пишем пароль который мы хотим и вставляем соль, сайт отдаёт нам хэш, мы его меняем уже в phpmyadmin и заходим в админку

Сценарий 2 (работает только если у сайта открыта админка и есть кнопка "forgot password (забыли пароль)")
2.1 Представим, у вас есть Boolen Based Blind SQLi, однако крутить такую скулю очень долго
Сначала мы дампим oc_user, добываем логин и почту админа. А затем идем к админке, нажимаем "forgot password", и пихаем туда почту админа, нажимаем восстановить пароль, а потом дампим у этого же админа в oc_user его code (он состоит из 40 символов). Копируем код, а потом вставляем его в URL, выглядеть это должно так: site.com/admin/index.php?route=common/reset&code={ваш код}, например site.com/admin/index.php?route=common/reset&code=TXLTJNZZrlVi9awmxQ0XnWx5FNVVqg0UTp63YaGE, ставите новый пароль и заходите в админку
Как это работает? Код приходит на почту админу и записывается сразу же в бд, мы можем воспользоваться этим :))


1.5 Заливаем веб шелл
Представим, мы уже находимся в админке, но хочется пройти к серверу - для этого зальем веб шелл через установщик модулей (см.фото)
Не удалось прогрузить медиа

Переходим во вкладку Extensions -> Installer --> Upload. Затем выбираем ocmod.zip архив, это расширение для всех модулей OpenCart, в этом модуле и находится наш шелл
Как только вы видите надпись что загрузка успешна, то переходите по такому URL site.com/catalog/view/javascript/simplifycommerce/gel4y.php 
Сам модуль можно скачать здесь: https://www.mediafire.com/file/ar0tqnoezc3uvh2/simplify-opencart-module.ocmod.zip/file


Заключение
OpenCart очень дырявая CMS, в модулях до сих пор очень много дыр, начиная от SQLi, заканчивая RCE. Сам факт, что пароль админа можно сменить таким методом поражает
👍97 ❤️19 🔥28 😁7 😮16 🤔22
Сколько стоит продажа бага в модуле опенкарт при его N установках?
красавчик имба
👍1
ОтветFunniestfunny

Не удалось прогрузить медиа Всем привет, в этой статье мы рассмотрим всевозможные методы взлома OpenCart Opencart - e-commerce CMS (т.е специальная система, позволяющая создать интернет магазин "из коробки"). OpenCart…

Отлично, можете пройти на оплату. Небольшой совет.. если в чем-то не уверены, не начинайте об этом рассуждать в ключе "насколько я понял", "мне кажется" и так далее, все таки тут есть определенная тех.смета под каждую язву, и конкретные условия эксплуатации - пишите так, как знаете, а если не знаете и лень что-то читать, просто описывайте суть кратко).

Как базовая сводка - неплохо.
Ответadraosi

красавчик имба

В этот раз давайте ограничимся предупреждением. Надеюсь, впредь такого не повторится?
👍3
ОтветleakinN_nname

Отлично, можете пройти на оплату. Небольшой совет.. если в чем-то не уверены, не начинайте об этом рассуждать в ключе "насколько я понял", "мне кажется" и так далее, все таки тут есть определенная тех.смета под каждую…

Окей, спасибо большое что ответил) Впервые статью пишу прост, но учту. Если есть какие-то рекомендации к статье - буду не против услышать
ОтветFunniestfunny

Окей, спасибо большое что ответил) Впервые статью пишу прост, но учту. Если есть какие-то рекомендации к статье - буду не против услышать

Есть. Присмотритесь к технологиям анализа этих самых плагинов для опенкарта, не опенкарта, хоть для вордпресса или мод-икс. Это очень интересно, и в потенциале - профитно.

Ставим докер, устанавливаем свой локальный инстанс тестируемой CMS.. ну и дальше поехали. Это уникальный контент, который высоко ценится во всех местах, куда вы с ним придете, особенно если не просто найдете и опишете уязвимость, но и укомплектуете ее действительно рабочим темплейтом и эксплоитом. Даже если уязвимость до вас уже была описана, в процессе разработки эксплоита читатели поймут ее куда глубже. На данный момент - свод базы, безусловно, хорош, и материал для практики вы людям дали, но опять же, это паблик, который всеми уже промучан и не раз)).

И это не совсем рекомендация к вашей нынешней статье. Это скорее возможный вектор развития такой тематики).
👍2
ОтветleakinN_nname

В этот раз давайте ограничимся предупреждением. Надеюсь, впредь такого не повторится?

крутой "имба"  уровня быдло- лолза.. да плевать ему на ваши предупреждения, господин модератор

Вопрос. Сколько приблизительно может стоить новая не-паблик уязвимость Опенкарт?
@adraosi  - ты в состоянии конкретно ответить на конкретный вопрос по этой теме?
👍1
В статье демонстрируются базовые векторы для атак opencart, почти обо всем рассказывали уже на других бордах, но тут собрано все в одном месте это удобно. Я думаю все таки благодаря развитию ИИ чуть стало проще искать 0day в плагинах/модулях.

ОтветFunniestfunny

Эту уязвимость нашел я еще недели 2 назад

Каким образом? ИИшка тоже нашла бы? Хорошим дополнением было бы для статьи)

@leakinN_nname думаю можно этот материал автору улучшить и после этого подать на оплату. Если б он продемонстрировал как ИИшка помогает искать 0дэи в дополнениях для cms, как локально развернуть или пообщаться с claude.ai было бы здорово. Думаю если не жалеть деньги и покупать платные плагины, то можно много вульн найти о которых еще не писали исследователи.

Вообщем автору было бы неплохо расписать про поиск 0day в плагинах с помощью искусственного интеллекта или ручками.

Круто, что таргеты дал уязвимые. Можно было как раз раскрутить и продемонстрировать.

Также админера и других панелей может не быть как подключиться к бд тогда?

ОтветFunniestfunny

https://www.mediafire.com

я думаю медиафайр уже никто не использует лет 10 назад через нее читы с ратником в подарок лили злодеи. Лучше мегу использовать она стабильно работает и долго хранит файлы. 

Автору спасибо за материал!
Ответcybergangster

В статье демонстрируются базовые векторы для атак opencart, почти обо всем рассказывали уже на других бордах, но тут собрано все в одном месте это удобно. Я думаю все таки благодаря развитию ИИ чуть стало проще искать…

Пусть лучше людские-заводские SAST&DAST решения для локального тестинга тогда уж демонстрируют. Это гораздо лучше, чем птыаться научить осла играть на флейте в сжатый срок. Там и нейронки, и агрегация, и управление заточены под это, такого софта - валом вали. А в остальном согласен, да. Надо демонстрировать векторы поиска, о чем я и сказал человеку чуть выше. Но он агрегировал информацию, скомпилировал в одну относительно читаемую и осмысленную статью, и оставил материал на обучение новичкам. Это хороший тон.
👍4

Гостевой просмотр. Чтобы отвечать и ставить реакции, войдите или зарегистрируйтесь.