Ломаем noname CC shop

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

Но этого вступления здесь не будет.

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

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

Forced Browsing & Leak info

После того, как я развернул локальную копию сайта, я собрал структуру файлов/папок и просканировал ее с помощью Burp Intruder. И практически сразу - наиудивительнейшие открытия.

При простом обращении к файлам:

  • ./core/1.php
  • ./core/3.php

Мы можем увидеть следующее:

Не так важно раскрытие пути, это практически ничего не дает (SQL-инъекций и LFI нету). На скриншоте замазано значение key из массива. Забегая вперед, для работы с сервисом, который предоставляет карты для продажи, нужно знать только API-ключ и url куда отправлять запросы. И вот key - это то самое значение API-ключа. Т.е. для человека, который знает, как делать шопы привязанные к конкретному API, достаточно знать только этот ключ, для того, чтобы слить баланс шопа.

Файл ./core/4.php позволяет делать поиск доступных городов по штатам:

Файлы:

  • ./core/chat/show.php
  • ./core/chat/messages.txt

Отображают содержимое чата. Т.е. можно читать, о чем пишут в чатике, не заходя в магазин и даже не регистрируясь.

Активная XSS и прочие веселья в чате.

Взглянем на содержимое файла ./core/chat/send.php:

Мы видим, что во первых - не нужно даже быть зарегистрированным, чтобы отправить сообщение. А во вторых - нет проверки, что именно тот пользователь что указан в sender и отправил сообщение.

Достаточно отправить post-запрос с параметрами sender и message:

И мы можем увидеть в чате:

Но нам этого недостаточно. Попробуем отправить html-код.
В качестве параметров указываем:

Заходим в магазин:

Имеем активную XSS, которая дает нам кучу возможностей. Например, можно повесить простенький веб-сниффер. А так как по умолчанию сессионные куки не имеют флага httponly, то мы можем украсть куки любого посетителя магазина, в том числе и админа. Подставляем куки себе и заходим.

Брутфорс и подбор логинов пользователей

Немного отвлечемся и обратим наше внимание на форму логина:

Сразу можем отметить, что нет капчи - можно брутить сколько угодно. Попробуем зайти под заведомо несуществующим пользователем abcdef1234567890:

А теперь под пользователем admin:

Как видите, перед тем как брутфорсить, мы можем точно определить, зарегистрирован пользователь или нет. Более того, обращаясь к файлу ./core/chat/show.php можно собрать логины пользователей, не привлекая внимания.

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

Активная XSS при регистрации пользователя

Попробуем зарегистрировать пользователя:

В качестве логина указываем следующую строку:

И теперь, когда admin зайдет на страницу пользователей:

Что важно - верстка не бьется, и если не alert(), то понять, что что-то произошло довольно сложно. С данной XSS можно угнать куки админа, не тратя время на обычных пользователей.

Тикеты с XSS

Создаем тикет:

Админ открывает тикет, чтобы прочитать и...

Опять таки, угоняем куки, подставляем себе и т.д.

Делаем свой аккаунт админом

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

Великолепно. Но это совсем не всё, на что мы можем влиять. Если посмотрим в html-код страницы, то можем увидеть:

Как мы видим, часть функционала убрали в комментарии. Но нам ничто не мешает просто отредактировать html с помощью firebug или другого подобного инструмента. Вдобавок, мы допишем еще один пункт в меню:

Жмем OK, заходим под пользователем l33t_hacker:

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

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

И никаких подозрений - сколько занесли пользователи, столько мы и тратим. К тому же, мы можем свободно редактировать любые статьи в магазине. И можем добавить еще парочку активных xss, так сказать впрок.

Ошибка в логике: покупаем сс по своей цене

Допустим, админ редко заходит в магазин, везде пользуется noscript или поставил флаг httponly у сессионных cookie. Выходит, что у нас нет возможности стырить его куки, а вот получить пачку свежих сс и при этом заплатить как можно меньше - очень хочется. Что же делать?

Алгоритм действий простой.

Включаем burp suite. Добавляем в корзину карту, которую хотим купить. Сохраняем http-запрос добавляющий карту:

Теперь переходим в корзину и удаляем карту из корзины. Повторяем запрос, но меняем последнее значение:

Обновляем страницу с корзиной:

Такая цена нас уже устраивает. Но всегда хочется еще чего-то большего. Вместо "0.0001" поставим "-1000000":

Еще лучше, да и после покупки в плюсе остаемся!

Ошибка в логике: баланс * кол-во сессий = профит

Даже если закрыть уязвимость, связанную с изменением цены, остается возможность покупать карты, загоняя баланс в минус. Взглянем на код скрипта ./components/com_shop/shop.php, а именно, на функцию buy():

Нам разрешают покупать, если сумма покупки меньше, чем баланс пользователя. При этом и сумма покупки и баланс хранятся в сессии. Далее, после покупки баланс в БД меняет значение. Но (!) непосредственно перед покупкой нет проверки на то, сколько в данный момент в самой БД у пользователя денег.

Поэтому возможен такой трюк:

  1. Открываем 5 разных браузеров
  2. В каждом браузере заходим в один и тот же аккаунт, на котором лежит, к примеру, 100 баксов.
  3. В каждом браузере добавляем в корзину разных карт на 100$.
  4. В каждом браузере переходим на страницу с оплатой.
  5. В каждом браузере нажимаем "Buy".
  6. Получаем карт на 500$ и аккаунт, загнанный в -400$
  7. Регаем новый аккаунт, добавляем 100 баксов на счет.
  8. Повторяем пункты 1-7.

При этом кол-во браузеров может быть не 5, а 50. Или 500.

Прочее.

В принципе, всего вышеописанного достаточно, чтобы составить общее впечатление о коде. Я не упоминал мелкие баги, типа reflected XSS, раскрытие путей и ошибки, связанные с функционалом, который был запрятан куда подальше.

Сейчас, когда с анализом кода мы закончили, мне хотелось бы поговорить о нескольких тезисах автора софта (жирным выделил я):

  1. "Я создаю сайты, я не хакер, я не могу знать уязвимости, к сожалению".

Подобное утверждение имело силу, если бы речь шла о школьном портале, сделанном за тройку в четверти по информатике. Однако - это шоп по продаже сс и сделанный не на сдачу с Жигулевского, а за 1500$.

1500$ - это месяц работы серьезного специалиста (middle/senior), который не допускает таких хрестоматийных ошибок. А из этого приложения, при небольшой доработке, можно сделать что-то типа Damn Vulnerable CC Shop на котором можно обучать юных хакеров.

Ну и если мы заглянем на php.net, в раздел документации, то можем обратить внимание:

Первая глава - "Установка и настройка".
Вторая глава - "Справочник языка".
Третья глава - "Безопасность".
Четвертая глава - "Отличительные особенности".
И только уже пятая глава - "Справочник функций".

Нормальный кодер должен знать какие существуют уязвимости и как предотвратить их появление у себя в коде. Никакого хакерства в этом нет.

2. "Я тебе его сделал, причем с нуля".

Не совсем правда, а возможно, совсем неправда. Если внимательно изучить html-код можно увидеть такое:

И если News, FAQ, "Добавить статью" еще можно оправдать тем, что какой-то функционал продуман, но еще не дописан, то как объяснить RDP? И соответствующую таблицу в базе данных - prefix_shop_cat_rdp?

Самое очевидное и разумное объяснение - это то, что код был переделан из какой-то заготовки, а не написан с нуля. Была эта заготовка написана самим автором или кем-то еще - уже не узнать, да и не так важно.

И наконец:

3. "Админы крупных порталов платят деньги сторонним разработчикам, чтобы они нашли их уязвимости, потому что они сами не могут этого сделать"

Ложное утверждение. Платят потому что это дешевле, чем нанимать профессионалов высокого класса. Выходит, что индусы ищут ошибки индусов, пока белые люди делают деньги.

4. "Никто не вешает возникшие проблемы на разработчиков, потому что понимают, что сами они не всесильны и не могут все знать."

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

5. "Apple, Контакт и т.д все платят хакерам, что по твоему там дебилы сидят и не могут найти в своей же работе уязвимости?"

Bugbounty это ТОЛЬКО про эффективность экономическую. Малыми деньгами ты покрываешь гигантские периметры на уровень "выше среднего" (с).

А вообще знаете...

В этот самый момент я осознал, что все, что написал выше было ошибкой. Ведь все нормальные шопы так и пишут - пока пару лямов не слили  - считай и не запустился. Пока админа кребс не вычислил - считай и не поработали нормально, так, детская возня. Пока блеков не набралось на лямов двадцать  - нуб и школота.

P.S