Реально тонкое взаимодействие

Ещё в группе «Реверс»
- Почему IDA не сворачивает константы и как это исправить
Почему IDA не сворачивает константы и как это исправить 👨💻 В последнее время в ВПО все…
- Распознаем STL-код легко
Распознаем STL-код легко 😐 Нередко в процессе реверс-инжиниринга мы сталкиваемся с STL-кодом, анализ которого на первый…
- Опять CFG
Опять CFG 👋 Частой задачей при извлечении конфигураций ВПО на потоке является получение границ функций и…
- Деобфусцируем имена функций .NET вручную
Деобфусцируем имена функций .NET вручную 🙌 ВПО на .NET обожает пакеры, обфускацию (имен, CFG и прочего)…
- Идея для правила корреляции в SIEM
Идея для правила корреляции в SIEM 💡 Хотя отслеживание всей цепочки атаки, описанной в постах выше,…
Реально тонкое взаимодействие 🕊
В ходе реверс-инжиниринга протокола одного из бразильских банковских троянов обнаружилось использование интересного сетевого фреймворка — RealThinClient. Процесс общения между клиентом и сервером в этом фреймворке построен на сериализации структур вызова функции в строковый формат и их последующей десериализации на другой стороне. Это делает RTC не только мощным инструментом разработки, но и удобной платформой для скрытого обмена командами — например, в случае малварного поведения.
Сначала клиент и сервер проходят через кастомное рукопожатие, в ходе которого устанавливаются ключи шифрования и дешифрования для обеих сторон. После этого фреймворк предоставляет возможность выполнять функции на стороне как клиента, так и сервера.
Перейдем сразу к примеру и на нем разберемся в логике работы инструмента. Клиент хочет залогиниться на сервере и отправляет запрос, как на скриншоте.
Что здесь происходит
1. Клиент формирует запрос:
• Устанавливает параметр FC (function call) в значение Login.
• Добавляет параметры: логин, пароль и id. Они передаются в виде структуры-словаря RE=3 (record), содержащей ключи user, pwd, id и т. п. В user можно передать зашифрованный малварный запрос. RE обозначает тип rtc_Record — это структура вида «ключ:значение», аналогичная словарю или JSON-объекту.
• На стороне Delphi это будет примерно так:
with FunctionCall.Param do
begin
asText['user'] := '...'; // rtc_Text
asText['pwd'] := ''; // rtc_Text
asString['id'] := '8DF313279CD34B81A3FB438708B4E8F1'; // rtc_String
end;
А при сериализации все это превратится в следующее:
RE=3;
user:T=...;
pwd:T=...;
id:S=...
📁 Когда мы вызываем удаленную функцию через RTC SDK, мы создаем объект TRtcFunctionInfo — это класс, который описывает удаленную вызываемую функцию, ее имя, параметры и результат выполнения. Он используется как на клиенте (для упаковки вызова), так и на сервере (для распаковки и выполнения). Объект TRtcFunctionInfo упаковывается в контейнер TRtcValue и сериализуется в строку или поток байтов.
TRtcValue может хранить любой поддерживаемый тип данных: строку, число, массив, запись, дату, вложенную функцию и т. п. Фактически он используется везде, где нужно передать или получить данные по сети, например в параметрах удаленной функции (Param.asValue[...]) или результатах выполнения функций (Result.asValue). Это делает его гибким, но и потенциально непрозрачным, что хорошо для скрытой передачи команд, особенно если используются вложенные структуры типа rtc_Function.
• Перед отправкой запроса клиент регистрирует хендлер OnLoginResult для обработки результата выполнения функции на сервере.
2. Запрос отправляется на сервер RTC:
• Сервер принимает HTTP-запрос и интерпретирует параметр FC как указание на то, какую функцию нужно вызвать.
• На стороне сервера вызывается обработчик для функции Login. Выполняется Delphi-процедура, связанная с этим именем.
3. Сервер отвечает:
• Результат функции возвращается клиенту, и он вызывает свой хендлер OnLoginResult для обработки полученного ответа.
• Ответ сервера десериализуется обратно в TRtcValue, чтобы мы смогли снова получить доступ к его структуре. Сервер может вернуть не просто данные, а вложенный вызов функции. Это структура, поле в которой содержит rtc_Function, rtc_Record или rtc_Array, которые клиент десериализует и выполняет.
Например:
if xData.isType = rtc_Record then
ExecuteRec(xData.asRecord)
else if xData.isType = rtc_Array then
ExecuteArr(xData.asArray)
👾 Это может успешно использоваться в малвари: сервер возвращает зашифрованное описание команды, которую клиент должен выполнить. Таким образом, в легитимный RTC-поток можно прятать вполне себе вредоносное поведение.
#reverse #hacktool
@ptescalator
Ещё в группе «Реверс»
- Почему IDA не сворачивает константы и как это исправить
Почему IDA не сворачивает константы и как это исправить 👨💻 В последнее время в ВПО все…
- Распознаем STL-код легко
Распознаем STL-код легко 😐 Нередко в процессе реверс-инжиниринга мы сталкиваемся с STL-кодом, анализ которого на первый…
- Опять CFG
Опять CFG 👋 Частой задачей при извлечении конфигураций ВПО на потоке является получение границ функций и…
- Деобфусцируем имена функций .NET вручную
Деобфусцируем имена функций .NET вручную 🙌 ВПО на .NET обожает пакеры, обфускацию (имен, CFG и прочего)…
- Идея для правила корреляции в SIEM
Идея для правила корреляции в SIEM 💡 Хотя отслеживание всей цепочки атаки, описанной в постах выше,…







