Буквально на днях Group-IB сообщала об активности мобильного Android-трояна Gustuff. Он работает исключительно на международных рынках, атакуя клиентов 100 крупнейших иностранных банков, пользователей мобильных 32 криптокошельков, а также крупных e-commerce ресурсов. А вот разработчик Gustuff — русскоязычный киберпреступник под ником Bestoffer. Еще недавно он нахваливал свой троян как «серьезный продукт для людей со знаниями и опытом».

Специалист по анализу вредоносного кода Group-IB Иван Писарев в своем исследовании подробно рассказывает о том, как работает Gustuff и в чем его опасность.

За кем охотится Gustuff


Gustuff относится к новому поколению вредоносных программ с полностью автоматизированными функциями. По словам разработчика, троян стал новой улучшенной версией вредоносной программы AndyBot, которая с ноября 2017 года атакует телефоны с ОС Android и крадет деньги через фишинговые веб-формы, маскирующиеся под мобильные приложения известных международных банков и платежных систем. Bestoffer сообщал, что цена аренды «Gustuff Bot» составляла $800 в месяц.

Анализ сэмпла Gustuff показал, что потенциально троян нацелен на клиентов, использующих мобильные приложения крупнейших банков, таких как Bank of America, Bank of Scotland, J.P.Morgan, Wells Fargo, Capital One, TD Bank, PNC Bank, а также на криптокошельки Bitcoin Wallet, BitPay, Cryptopay, Coinbase и др.

Изначально созданный как классический банковский троян, в текущей версии Gustuff значительно расширил список потенциальных объектов для атаки. Кроме Android-приложений банков, финтех-компаний и криптосервисов, Gustuff нацелен на пользователей приложений маркетплейсов, онлайн-магазинов, платежных систем и мессенджеров. В частности, PayPal, Western Union, eBay, Walmart, Skype, WhatsApp, Gett Taxi, Revolut и других.

Точка входа: расчет на массовое заражение


Для Gustuff характерен «классический» вектор проникновения на Android-смартфоны через СМС-рассылки со ссылками на APK. При заражении Android-устройства трояном по команде сервера может произойти дальнейшее распространение Gustuff'а по базе контактов инфицированного телефона либо по базе данных сервера. Функциональные возможности Gustuff рассчитаны на массовое заражение и максимальную капитализацию бизнеса своих операторов – в нем присутствует уникальная функция «автозалива» в легитимные мобильные банковские приложения и криптокошельки, что позволяет ускорить и масштабировать кражу денег.

Исследование трояна показало, что функция автозалива реализована в нем при помощи Accessibility Service — сервиса для людей с ограниченными возможностями. Gustuff – не первый троян, который успешно обходит защиту от взаимодействия с элементами окон других приложений с помощью данного сервиса Android. Однако использование Accessibility Service в сочетании с автозаливом остается до сих пор достаточно редким явлением.

После загрузки на телефон жертвы Gustuff, используя Accessibility Service, получает возможность взаимодействовать с элементами окон других приложений (банковских, криптовалютных, а также приложений для онлайн-шоппинга, обмена сообщениями и др.), выполняя необходимые для злоумышленников действия. К примеру, по команде сервера троян может нажимать на кнопки и изменять значения текстовых полей в банковских приложениях. Использование механизма Accessibility Service позволяет трояну обходить механизмы защиты, используемые банками для противодействия мобильным троянам прошлого поколения, а также изменения в политике безопасности, внедренные Google в новые версии ОС Android. Так, Gustuff «умеет» отключать защиту Google Protect: по заверениям автора, данная функция срабатывает в 70% случаев.



Также Gustuff может демонстрировать фейковые PUSH-уведомления с иконками легитимных мобильных приложений. Пользователь кликает на PUSH-уведомление и видит загруженное с сервера фишинговое окно, куда сам вводит запрашиваемые данные банковской карты или криптокошелька. В другом сценарии работы Gustuff происходит открытие приложения, от имени которого демонстрировалось PUSH-уведомление. В этом случае вредоносная программа по команде сервера через Accessibility Service может заполнять поля формы банковского приложения для мошеннической транзакции.

В функциональные возможности Gustuff также входят отправка на сервер информации о заражённом устройстве, возможность чтения/отправления СМС-сообщений, отправление USSD-запросов, запуск SOCKS5 Proxy, переход по ссылке, отправление файлов (в том числе фотосканов документов, скриншотов, фотографий) на сервер, сброс устройства до заводских настроек.

Анализ вредоносной программы


Перед установкой вредоносного приложения ОС Android демонстрирует пользователю окно, содержащее в себе список запрашиваемых Gustuff'ом прав:

image alt

Установка приложения произойдет только после получения согласия пользователя. После запуска приложения троян покажет пользователю окно:

image alt

После чего удалит свою иконку.

Gustuff упакован, по словам автора, упаковщиком от FTT. После запуска приложение периодически обращается к CnC- серверу с целью получения команд. В нескольких исследованных нами файлах в качестве управляющего сервера использовался IP-адрес 88.99.171[.]105 (в дальнейшем будем обозначать как <%CnC%>).

После запуска программа начинает отправку сообщений серверу http://<%CnC%>/api/v1/get.php.

В качестве ответа ожидается JSON следующего формата:

{
    "results" : "OK",
    "command":{
        "id": "<%id%>",
        "command":"<%command%>",
        "timestamp":"<%Server Timestamp%>",
        "params":{
		<%Command parameters as JSON%>
        },
    },
}

При каждом обращении приложение отправляет информацию о зараженном устрои?стве. Формат сообщения представлен ниже. Стоит отметить, что поля full, extra, apps и permission – опциональные и будут отправлены только в случае команды-запроса от CnC.

{
    "info":
    {
        "info":
        {
            "cell":<%Sim operator name%>,
            "country":<%Country ISO%>,
            "imei":<%IMEI%>,
            "number":<%Phone number%>,
            "line1Number":<%Phone number%>,
            "advertisementId":<%ID%>
        },
        "state":
        {
            "admin":<%Has admin rights%>,
            "source":<%String%>,
            "needPermissions":<%Application needs permissions%>,
            "accesByName":<%Boolean%>,
            "accesByService":<%Boolean%>,
            "safetyNet":<%String%>,
            "defaultSmsApp":<%Default Sms Application%>,
            "isDefaultSmsApp":<%Current application is Default Sms Application%>,
            "dateTime":<%Current date time%>,
            "batteryLevel":<%Battery level%>
        },
        "socks":
        {
            "id":<%Proxy module ID%>,
            "enabled":<%Is enabled%>,
            "active":<%Is active%>
        },
        "version":
        {
            "versionName":<%Package Version Name%>,
            "versionCode":<%Package Version Code%>,
            "lastUpdateTime":<%Package Last Update Time%>,
            "tag":<%Tag, default value: "TAG"%>,
            "targetSdkVersion":<%Target Sdk Version%>,
            "buildConfigTimestamp":1541309066721
        },
    },
    "full":
    {
        "model":<%Device Model%>,
        "localeCountry":<%Country%>,
        "localeLang":<%Locale language%>,
        "accounts":<%JSON array, contains from "name" and "type" of accounts%>,
        "lockType":<%Type of lockscreen password%>
    },
    "extra":
    {
        "serial":<%Build serial number%>,
        "board":<%Build Board%>,
        "brand":<%Build Brand%>,
        "user":<%Build User%>,
        "device":<%Build Device%>,
        "display":<%Build Display%>,
        "id":<%Build ID%>,
        "manufacturer":<%Build manufacturer%>,
        "model":<%Build model%>,
        "product":<%Build product%>,
        "tags":<%Build tags%>,
        "type":<%Build type%>,
        "imei":<%imei%>,
        "imsi":<%imsi%>,
        "line1number":<%phonenumber%>,
        "iccid":<%Sim serial number%>,
        "mcc":<%Mobile country code of operator%>,
        "mnc":<%Mobile network codeof operator%>,
        "cellid":<%GSM-data%>,
        "lac":<%GSM-data%>,
        "androidid":<%Android Id%>,
        "ssid":<%Wi-Fi SSID%>
    },
    "apps":{<%List of installed applications%>},
    "permission":<%List of granted permissions%>
} 

Хранение конфигурационных данных


Gustuff хранит важную для работы информацию в preference-фаи?ле. Имя фаи?ла, как и имена параметров в нем – результат вычисления MD5-суммы от строки 15413090667214.6.1<%name%>, где <%name%> — исходное имя-значение. Python-интерпретация функции генерации имени:

 nameGenerator(input):
    output = md5("15413090667214.6.1" + input) 

В дальнеи?шем будем обозначать как nameGenerator(input).

Таким образом, имя первого фаи?ла: nameGenerator(«API_SERVER_LIST»), он содержит значения со следующими именами:

Имя переменнои? Значение
nameGenerator(«API_SERVER_LIST») Содержит список CnC-адресов в виде массива.
nameGenerator(«API_SERVER_URL») Содержит CnC-адрес.
nameGenerator(«SMS_UPLOAD») Флаг по умолчанию установлен. Если флаг установлен – отправляет СМС-сообщения на CnC.
nameGenerator(«SMS_ROOT_NUMBER») Номер телефона, на которыи? будут отправлены SMS-сообщении? принятые зараженным устри?оством. По умолчанию null.
nameGenerator(«SMS_ROOT_NUMBER_RESEND») Флаг по умолчанию сброшен. Если установлен – при получении зараженным устрои?ством SMS оно будет отправлено на root-номер.
nameGenerator(«DEFAULT_APP_SMS») Флаг по умолчанию сброшен. Если данныи? флаг установлен – приложение будет обрабатывать входящие SMS- сообщения.
nameGenerator(«DEFAULT_ADMIN») Флаг по умолчанию сброшен. Если флаг установлен – приложение имеет права администратора.
nameGenerator(«DEFAULT_ACCESSIBILITY») Флаг по умолчанию сброшен. Если флаг установлен – запущен сервис, использующии? Accessibility Service.
nameGenerator(«APPS_CONFIG») JSON-объект, содержит список деи?ствии?, которые необходимо выполнить при срабатывании Accessibility-события, связанного с определенным приложением.
nameGenerator(«APPS_INSTALLED») Хранит список установленных на устрои?стве приложении?.
nameGenerator(«IS_FIST_RUN») Флаг при первом запуске сбрасывается.
nameGenerator(«UNIQUE_ID») Содержит уникальныи? идентификатор. Генерируется при первом запуске бота.

Модуль обработки команд от сервера


Приложение хранит адреса CnC-серверов в виде массива закодированных по Base85 строк. Список CnC — серверов может быть изменен при поступлении соответствующеи? команды, в таком случае адреса будут хранится в preference-фаи?ле.

В ответ на запрос сервер отправляет приложению команду. Стоит отметить, что команды и параметры представлены в JSON-формате. Приложение может обрабатывать следующие команды:
Команда Описание
forwardStart Начать отправление получаемых зараженным устройством SMS-сообщений на CnC-сервер.
forwardStop Остановить отправление получаемых зараженным устройством SMS-сообщений на CnC-сервер.
ussdRun Выполнить USSD-запрос. Номер, на который необходимо совершить USSD-запрос находится в JSON-поле «number».
sendSms Отправить одно SMS-сообщение (при необходимости сообщение «дробится» на части). В качестве параметра команда принимает JSON-объект, содержащий поля «to» — номер назначения и «body» — тело сообщения.
sendSmsAb Отправить SMS-сообщения (при необходимости сообщение «дробится» на части) всем из списка контактов зараженного устройства. Интервал между отправлением сообщений – 10 секунд. Тело сообщения находится в JSON-поле «body»
sendSmsMass Отправить SMS-сообщения (при необходимости сообщение «дробится» на части) контактам, указанным в параметрах команды. Интервал между отправлением сообщений – 10 секунд. В качестве параметра команда принимает JSON-массив (поле «sms»), элементы которого содержат поля «to» — номер назначения и «body» — тело сообщения.
changeServer Данная команда в качестве параметра может принимать значение с ключом «url» — тогда бот изменит значение nameGenerator(“SERVER_URL”), либо «array» — тогда бот запишет массив в nameGenerator (“API_SERVER_LIST”) Таким образом приложение меняет адрес CnC-серверов.
adminNumber Команда предназначена для работы с root-номером. Команда принимает JSON-объект со следующими параметрами: «number» — изменить nameGenerator(“ROOT_NUMBER”) на полученное значение, «resend» — изменить nameGenerator(“SMS_ROOT_NUMBER_RESEND”), «sendId» — отправить на nameGenerator(“ROOT_NUMBER”) uniqueID.
updateInfo Отправить на сервер информацию о зараженном устройстве.
wipeData Команда предназначена для удаления пользовательских данных. В зависимости от какого имени было запущено приложение происходит либо полное стирание данных с перезагрузкой устройства (primary user), либо удаление только пользовательских данных (secondary user).
socksStart Запустить Proxy-модуль. Работа модуля описана в отдельном разделе.
socksStop Остановить работу Proxy-модуля.
openLink Перейти по ссылке. Ссылка находится в JSON-параметре по ключу «url». Для открытия ссылки используется «android.intent.action.VIEW».
uploadAllSms Отправить на сервер все принятые устройством SMS-сообщения.
uploadAllPhotos Отправить на URL изображения с зараженного устройства. URL приходит как параметр.
uploadFile Отправить на URL файл с зараженного устройства. URL приходит как параметр.
uploadPhoneNumbers Отправить на сервер номера телефонов из списка контактов. Если в качестве параметра приходит JSON-объект значение с ключом «ab», приложение получает список контактов из телефонной книги. Если в качестве параметра приходит JSON-объект с ключом «sms», приложение читает список контактов из отправителей SMS-сообщений.
changeArchive Приложение загружает файл с адреса, который приходит в качестве параметра по ключу «url». Загруженный файл сохраняется с именем «archive.zip». После этого приложение разархивирует файл, при необходимости используя пароль для архива «b5jXh37gxgHBrZhQ4j3D». Разархивированный файлы сохраняет в директорию [external storage]/hgps. В данной директории приложение хранит web-фейки (описано далее).
actions Команда предназначена для работы с Action Service, который описан в отдельном разделе.
test Ничего не делает.
download Команда предназначена для загрузки файла с удаленного сервера и сохранении его в директорию «Downloads». URL и имя файла приходят в качестве параметра, поля в JSON-объекте параметре соответственно: «url» и «fileName».
remove Удаляет файл из директории «Downloads». Имя файла приходит в JSON-параметре с ключом «fileName». Стандартное имя файла – «tmp.apk».
notification Показать уведомление с текстами описания и заголовка, определяемыми управляющим сервером.

Формат команды notification:

{
    "results" : "OK",
    "command":{
    "id": <%id%>,
    "command":"notification",
    "timestamp":<%Server Timestamp%>,
    "params":{
        "openApp":<%Open original app or not%>,
        "array":[
                      {"title":<%Title text%>,
                      "desc":<%Description text%>,
                      "app":<%Application name%>}
                   ]
                   },
        },
}

Уведомление, создаваемое исследуемым файлом, выглядит идентично уведомлениям, создаваемым приложением, указанным в поле app. Если значение поля openApp — True, при открытии уведомления запускается приложение, указанное в поле app. Если значение поля openApp — False, то:

  • открывается фишинговое окно, содержимое которого загружается из директории <%external storage%>/hgps/<%filename%>
  • открывается фишинговое окно, содержимое которого загружается с сервера <%url%>?id=<%Bot id%>&app=<%Application name%>
  • открывается фишинговое окно, замаскированное под Google Play Card, с возможностью ввести данные карты.

Результат исполнения любой команды приложение отправляет на <%CnC%>\set_state.php в виде JSON-объекта следующего формата:

{
    "command":
    {
        "command":<%command%>,
        "id":<%command_id%>,
        "state":<%command_state%>
    }
    "id":<%bot_id%>
}

ActionsService

В список команд, которые обрабатывает приложение, входит action. При получении команды модуль обработки команд обращается к данному сервису с целью исполнения расширеннои? команды. В качестве параметра сервис принимает JSON-объект. Сервис может выполнять следующие команды:

1. PARAMS_ACTION — при получении такои? команды сервис в первую очередь получает из JSON- параметра значение по ключу Type, может быть следующим:

  • serviceInfo – подкоманда получает из JSON-параметра значение по ключу includeNotImportant. Если флаг равен True — приложение устанавливает флаг FLAG_ISOLATED_PROCESS на сервис, использующии? Accessibility Service. Таким образом, сервис будет запущен в отдельном процессе.
  • root — получить и отправить на сервер информацию об окне, которое сеи?час в фокусе. Приложение получает информацию при помощи класса AccessibilityNodeInfo.
  • admin — запросить права администратора.
  • delay — приостановить работу ActionsService на то количество миллисекунд, которое указано в параметре по ключу «data».
  • windows — отправить список видимых пользователю окон.
  • install — установить приложение на зараженное устрои?ство. Название пакета — архива находится в ключе «fileName». Сам архив находится в директории Downloads.
  • global – подкоманда предназначена для осуществления перехода с текущего окна:
    • на меню Quick Settings
    • назад
    • домои?
    • к уведомлениям
    • к окну недавно открытых приложении?

  • launch — запустить приложение. Наименование приложения приходит как параметр по ключу data.
  • sounds — изменить режим звука на silence.
  • unlock — включает подсветку экрана и клавиатуры на полную яркость. Приложение выполняет данное деи?ствие при помощи WakeLock, в качестве тэга указывает строку [Application lable]:INFO
  • permissionOverlay — функция не реализована (ответ на исполнение команды — {«message»:«Not support»} или {«message»:«low sdk»})
  • gesture — функция не реализована (ответ на исполнение команды — {«message»:«Not support»}или {«message»:«Low API»})
  • permissions — данная команда необходима для запроса прав для приложения. Однако функция запроса не реализована, таким образом команда не имеет смысла. Список запрашиваемых прав приходит как JSON-массив с ключом «permissions». Стандартныи? список:

    • android.permission.READ_PHONE_STATE
    • android.permission.READ_CONTACTS
    • android.permission.CALL_PHONE
    • android.permission.RECEIVE_SMS
    • android.permission.SEND_SMS
    • android.permission.READ_SMS
    • android.permission.READ_EXTERNAL_STORAGE
    • android.permission.WRITE_EXTERNAL_STORAGE

  • open — вывести на экран фишинговое окно. В зависимости от приходящего от сервера параметра приложение может демонстрировать следующие фишинговые окна:

    • Показать фишинговое окно, содержимое которого прописано в фаи?ле в директории <%external directory%>/hgps/<%param_filename%>. Результат взаимодеи?ствия пользователя с окном будет отправлен по адресу <%CnC%>/records.php
    • Показать фишинговое окно, содержимое которого предварительно грузится с адреса <%url_param%>?id=<%bot_id%>&app=<%packagename%>. Результат взаимодеи?ствия пользователя с окном будет отправлен по адресу <%CnC%>/records.php
    • Показать фишинговое окно, замаскированное под Google Play Card.
  • interactive — команда предназначена для взаимодеи?ствия с элементами окон других приложении? при помощи AcessibilityService. Для взаимодеи?ствия в программе реализован специальныи? сервис. Исследуемое приложение может взаимодеи?ствовать с окнами:
    • Активным на данныи? момент. В таком случае параметр содержит id либо text (наименование) объекта, с которым необходимо взаимодеи?ствовать.
    • Видимыми пользователю на момент исполнения команды. Приложение выбирает окна по id.

    Получив объекты AccessibilityNodeInfo для интересующих элементов окна, приложение в зависимости от параметров может выполнять деи?ствия:
    • focus — установить фокус на объект.
    • click — кликнуть на объект.
    • actionId — выполнить деи?ствие по ID.
    • setText — изменить текст объекта. Изменение текста возможно двумя способами: выполнить деи?ствие ACTION_SET_TEXT (если версия Android зараженного устрои?ства – моложе либо равна LOLLIPOP), либо поместив в буфер обмена строку и вставив его в объект (для версии? старше). Данная команда может быть использована для изменения данных в банковском приложении.

2. PARAMS_ACTIONS — то же, что и PARAMS_ACTION, только приходит JSON-массив команд.

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

boolean interactiveAction(List aiList, JSONObject action, JsonObject res) {
    int count = action.optInt("repeat", 1);
    Iterator aiListIterator = ((Iterable)aiList).iterator();
    int count = 0;
    while(aiListIterator.hasNext()) {
        Object ani = aiListIterator.next();
        if(1 <= count) {
            int index;
            for(index = 1; true; ++index) {
                if(action.has("focus")) {
                    if(((AccessibilityNodeInfo)ani).performAction(1)) {
                        ++count;
                    }
                }
                else if(action.has("click")) {
                    if(((AccessibilityNodeInfo)ani).performAction(16)) {
                        ++count;
                    }
                }
                else if(action.has("actionId")) {
                    if(((AccessibilityNodeInfo)ani).performAction(action.optInt("actionId"))) {
                        ++count;
                    }
                }
                else if(action.has("setText")) {
                    customHeader ch = CustomAccessibilityService.a;
                    Context context = this.getApplicationContext();
                    String text = action.optString("setText");
                    if(performSetTextAction(ch, context, ((AccessibilityNodeInfo)ani), text)) {
                        ++count;
                    }
                }
                if(index == count) {
                    break;
                }
            }
        }
        ((AccessibilityNodeInfo)ani).recycle();
    }
    res.addPropertyNumber("res", Integer.valueOf(count));
}

Функция замены текста:

boolean performSetTextAction(Context context, AccessibilityNodeInfo ani, String text) {
    boolean result;
    if(Build$VERSION.SDK_INT >= 21) {
        Bundle b = new Bundle();
        b.putCharSequence("ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE", ((CharSequence)text));
        result = ani.performAction(0x200000, b);  // ACTION_SET_TEXT
    }
    else {
        Object clipboard = context.getSystemService("clipboard");
        if(clipboard != null) {
        ((ClipboardManager)clipboard).setPrimaryClip(ClipData.newPlainText("autofill_pm", ((CharSequence)text)));
        result = ani.performAction(0x8000);  // ACTION_PASTE
        }
        else {
            result = false;
        }
    }
    return result;
}

Таким образом, при правильной настройке управляющего сервера Gustuff способен заполнить текстовые поля в банковском приложении и нажать на необходимые для совершения транзакции кнопки. Трояну даже не нужно проходить авторизацию в приложении — достаточно отправить команду на демонстрацию PUSH-уведомления с последующим открытием ранее установленного банковского приложения. Пользователь сам пройдет авторизацию, после чего Gustuff сможет произвести автозалив.

Модуль обработки СМС-сообщении?


Приложение устанавливает обработчик события на принятие зараженным устрои?ством СМС-сообщении?. Исследуемое приложение может принимать команды от оператора, которые приходят в теле СМС- сообщения. Команды приходят в формате:

7!5=<%Base64 encoded command%>

Приложение ищет во всех приходящих СМС-сообщениях строку 7!5=, при обнаружении строки – декодирует из Base64 строку по смещению 4 и исполняет команду. Команды аналогичны командам с CnC. Результат исполнения отправляется на тот же номер, с которого поступила команда. Формат ответа:

7*5=<%Base64 encode of «result_code command»%>

Опционально приложение может отправлять все принимаемые сообщения на Root-номер. Для этого в preference-фаи?ле должен быть указан Root-номер и установлен флаг редиректа сообщении?. СМС-сообщение отправляется на номер злоумышленника в формате:

<%From number%> — <%Time, format: dd/MM/yyyy HH:mm:ss%> <%SMS body%>

Также опционально приложение может отправлять сообщения на CnC. СМС-сообщение отправляется на сервер в JSON-формате:

{
    "id":<%BotID%>,
    "sms":
    {
        "text":<%SMS body%>,
        "number":<%From number%>,
        "date":<%Timestamp%>
    }
}

Если установлен флаг nameGenerator(«DEFAULT_APP_SMS») – приложение останавливает обработку СМС-сообщения и очищает список входящих сообщении?.

Proxy-модуль


В исследуемом приложении присутствует Backconnect Proxy модуль (далее Proxy-модуль), которыи? имеет отдельныи? класс, включающии? в себя статические поля с конфигурациеи?. Конфигурационные данные хранятся в семпле в открытом виде:

image alt


Все деи?ствия, совершаемые Proxy-модулем, логируются в фаи?лы. Для этого приложение в External Storage создает директорию с названием «logs» (поле ProxyConfigClass.logsDir в конфигурационном классе), в которои? хранятся лог-фаи?лы. Логирование происходит в фаи?лы с именами:

  1. main.txt – в данныи? фаи?л происходит логирование работы класса с названием CommandServer. В дальнеи?шем логирование строки str в данныи? фаи?л будем обозначать как mainLog(str).
  2. session-<%id%>.txt — в данныи? фаи?л происходит сохранение лог-данных, связанных с определеннои? сессиеи? проксирования. В дальнеи?шем логирование строки str в данныи? фаи?л будем обозначать как sessionLog (str).
  3. server.txt – в данныи? фаи?л происходит логирование всех данных, записываемых в вышеописанные фаи?лы.

Формат лог-данных:

<%Date%> [Thread[<%thread id%>], id[]]: log-string

Возникающие в процессе работы Proxy-модуля исключения также логируются в фаи?л. Для этого приложение формирует JSON-объект формата:

{
    "uncaughtException":<%short description of throwable%>
    "thread":<%thread%>
    "message":<%detail message of throwable%>
    "trace":        //Stack trace info
        [
            {
                "ClassName":
                "FileName":
                "LineNumber":
                "MethodName":
            },
            {
                "ClassName":
                "FileName":
                "LineNumber":
                "MethodName":
            }
        ]
}

После чего конвертирует его в строковое представление и логирует.

Запуск Proxy-модуля осуществляется после поступления соответсвующеи? комнады. При поступлении команды на запуск Proxy-модуля приложение запускает сервис с названием MainService, которыи? отвечает за управление работои? Proxy-модуля – его запуск и остановку.

Этапы запуска сервиса:

1. Запускает таи?мер, срабатывающии? раз в минуту и проверяющии? активность Proxy-модуля. Если модуль не активен – запускает его.
Также при срабатывании события android.net.conn.CONNECTIVITY_CHANGE происходит запуск Proxy-модуля.

2. Приложение создает wake-lock с параметром PARTIAL_WAKE_LOCK и захватывает его. Таким образом не позволяет переи?ти CPU устрои?ства в спящии? режим.

3. Запускает класс обработки команд Proxy-модуля, предварительно логируя строку mainLog(«start server») и

Server::start() host[<%proxy_cnc%>], commandPort[<%command_port%>], proxyPort[<%proxy_port%>]

где proxy_cnc, command_port и proxy_port – параметры, полученные из конфигурации Proxy- сервера.

Класс обработки команд имеет название CommandConnection. Сразу после запуска выполняет следующие деи?ствия:

4. Подключается к ProxyConfigClass.host: ProxyConfigClass.commandPort и отправляет туда данные о зараженном устрои?стве в JSON-формате:

{
    "id":<%id%>,
    "imei":<%imei%>,
    "imsi":<%imsi%>,
    "model":<%model%>,
    "manufacturer":<%manufacturer%>,
    "androidVersion":<%androidVersion%>,
    "country":<%country%>,
    "partnerId":<%partnerId%>,
    "packageName":<%packageName%>,
    "networkType":<%networkType%>,
    "hasGsmSupport":<%hasGsmSupport%>,
    "simReady":<%simReady%>,
    "simCountry":<%simCountry%>,
    "networkOperator":<%networkOperator%>,
    "simOperator":<%simOperator%>,
    "version":<%version%>
}

Где:

  • id – идентификатор, пытается получить из Shared Preference фаи?ла с именем «x» значение с полем «id». Если данное значение получить не удалось — генерирует новое. Таким образом, Proxy-модуль имеет свои? идентификатор, которыи? генерируется аналогично Bot ID.
  • imei — IMEI устрои?ства. Если в процессе получения значения произошла ошибка — вместо этого поля будет записано текстовое сообщение об ошибке.
  • imsi — International Mobile Subscriber Identity устрои?ства. Если в процессе получения значения произошла ошибка — вместо этого поля будет записано текстовое сообщение об ошибке.
  • model — The end-user-visible name for the end product.
  • manufacturer — The manufacturer of the product/hardware (Build.MANUFACTURER).
  • androidVersion — строка в формате "<%release_version%> (<%os_version%>),<%sdk_version%>"
  • country — текущее местоположение устрои?ства.
  • partnerId – пустая строка.
  • packageName – package name.
  • networkType — тип текущего сетевого соединения (пример: «WIFI», «MOBILE»). В случае ошибки возвращает null.
  • hasGsmSupport – true – если телефон поддерживает GSM, иначе false.
  • simReady – состояние SIM-карты.
  • simCountry — ISO-код страны (на основании проваи?дера сим-карты).
  • networkOperator — наименование оператора. Если в процессе получения значения произошла ошибка — вместо этого поля будет записано текстовое сообщение об ошибке.
  • simOperator — The Service Provider Name (SPN). Если в процессе получения значения произошла ошибка — вместо этого поля будет записано текстовое сообщение об ошибке.
  • version — данное поле хранится в конфиг-классе, для исследуемых версии? бота оно было равно «1.6».

5. Переходит в режим ожидания команд от сервера. Команды от сервера поступают в формате:

  • 0 offset – command
  • 1 offset – sessionId
  • 2 offset – length
  • 4 offset — data

При поступлении команды приложение логирует:

mainLog(«Header { sessionId<%id%>], type[<%command%>], length[<%length%>] }»)

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

Name Command Data Description
connectionId 0 Connection ID Создать новое подключение
SLEEP 3 Time Приостановить работу Proxy-модуля
PING_PONG 4 - Отправить PONG-сообщение

PONG-сообщение состоит из 4 байт и выглядит следующим образом: 0x04000000.

При поступлении команды connectionId (на создание нового подключения) CommandConnection создает экземпляр класса ProxyConnection.

  • В проксировании принимают участие два класса: ProxyConnection и end. При создании класса ProxyConnection происходит подключение к адресу ProxyConfigClass.host: ProxyConfigClass.proxyPort и передача JSON-объекта:

 {
    "id":<%connectionId%>
}

В ответ сервер присылает SOCKS5-сообщение, которое содержит адрес удаленного сервера, с которым необходимо установить соединение. Взаимодеи?ствие с эти сервером происходит посредством класса end. Схематично установку соединения можно представить следующим образом:

image alt

Сетевые взаимодеи?ствия


Для предотвращения анализа трафика сетевыми снифферами взаимодеи?ствие между CnC-сервером и приложением может быть защищено посредством протокола SSL. Все передаваемые данные как с сервера так и на сервер представлены в JSON-формате. Приложение в ходе работы выполняет следующие запросы:

  • http://<%CnC%>/api/v1/set_state.php — результат исполнения команды.
  • http://<%CnC%>/api/v1/get.php — получение команды.
  • http://<%CnC%>/api/v1/load_sms.php — выгрузка SMS-сообщении? с зараженного устрои?ства.
  • http://<%CnC%>/api/v1/load_ab.php — выгрузка списка контактов с зараженного устрои?ства.
  • http://<%CnC%>/api/v1/aevents.php – запрос производится при обновлении параметров, находящихся в preference-фаи?ле.
  • http://<%CnC%>/api/v1/set_card.php — выгрузка данных, полученных при помощи фишинг-окна, маскирующегося под Google Play Market.
  • http://<%CnC%>/api/v1/logs.php – выгрузка лог-данных.
  • http://<%CnC%>/api/v1/records.php – выгрузка данных, полученных при помощи фишинговых окон.
  • http://<%CnC%>/api/v1/set_error.php – оповещение о возникшеи? ошибке.

Рекомендации


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

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

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

Правила безопасности для пользователей:


  • не устанавливать приложения для мобильного устройства с ОС Android из каких-либо источников, кроме Google Play;
  • при установке приложения обращать особое внимание на запрашиваемые приложением права;
  • регулярно устанавливать обновления ОС Android;
  • обращать внимание на расширения загружаемых файлов;
  • не посещать подозрительные ресурсы;
  • не переходить по ссылкам, полученным в SMS-сообщениях.

При участии Семена Рогачева, младшего специалиста по исследованию вредоносного кода Лаборатории компьютерной криминалистики Group-IB.

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


  1. UnclShura
    10.04.2019 15:38

    А что, кто-то вообще ведется на эти нигерийские вирусы? Это-ж как надо головой поехать чтобы:

    1. Глубоко в меню включить загрузку из непровереных источников
    2. Загрузить что-то по ссылке из SMS(!)
    3. Дать ему разрешение делать все, что угодно

    Просто пункт 1 подразумевает или некие знания или откровенное пиратство. При этом если 2 и 3 выполнены, то что-то мне подсказывает, что у данной персоны и карты-то нет не говоря о крипте.


    1. pyrk2142
      10.04.2019 16:29

      Кажется, что установщик Fortnite мотивировал включить установку из любых источников, как в первом пункте.


      1. UnclShura
        10.04.2019 16:56

        Что однозначно-бы указывало на троян в установщике. А значит сразу фф топку!


        1. Stalker_RED
          10.04.2019 17:52

          Как-же ффтопку, а поиграть хочицца же!


    1. IvanPisarev
      11.04.2019 12:01

      Да, люди реально игнорируют уведомления и устанавливают приложения по ссылкам из СМС. Еще больше людей игнорирует список запрашиваемых приложением прав, что и сделало Android-трояны такими популярными и распространенными. При этом у них может быть хороший опыт общения с Android'ом. Простое соблюдение правил безопасности может решить множество проблем)


  1. MedicusAmicus
    10.04.2019 18:21

    А что, установка приложений только из GP гарантирует безопасность?
    Что-то я смущен и обескуражен.
    А я-то в приступе паранойи вручную отключаю разрешения, которые не явно необходимы. Картам — инет и гео, а вот звонки и смс — не. А калькулятору или фонарику — вообще сидеть тихо.


    1. IvanPisarev
      11.04.2019 12:02

      Нет, к сожалению, не гарантирует. В GP периодически появляются вредоносные приложения (чаще всего загрузчики — по команде сервера подгружают и запускают троян), и количество скачиваний у них достаточно большое.

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

      Спасибо за комментарий!


    1. Jogger
      11.04.2019 12:09

      Разумеется не гарантирует.


  1. XanderBass
    10.04.2019 20:49

    Приложение для фотографий запрашивает разрешение на совершение звонков и отправку SMS/MMS. Каким тупицей нужно быть, чтобы ничего не заподозрить?


    1. IvanPisarev
      11.04.2019 12:03

      Достаточно большое количество пользователей Android-устройств игнорируют список запрашиваемых прав по разным причинам. Плюс современные Android-банкеры достаточно коварны — чтобы усыпить бдительность своих жертв они мимикрируют под легитимные приложения, которым реально необходим большой список прав для выполнения своих функций. Некоторые Andorid-трояны размещают в GP, что также может ввести пользователя в заблуждение. И опять же не стоит забывать, что некоторые операторы делают красивые фишинговые веб-страницы, призывающие установить приложение, просто кликнув вот на эту похожую на легитимный сайт ссылочку.


    1. Alexey2005
      11.04.2019 13:56

      Так под Android даже самый распоследний фонарик запрашивает весь набор разрешений, включая звонки/SMS. Нужно потратить очень много времени, чтоб найти в Google Play приложение, которое всего этого не требует, и по функционалу оно будет уступать топовым приложениям, которые всё это требуют.