2018 is barely two weeks old, and already it looks like we’ve got new piece of macOS malware! Hooray 🙂
Please don’t infect yourself!
Background
Earlier today (01/11), someone on MalwareBytes’ forum created a post titled “DNS Hijacked”:
So far nobody has answered or offered to help ‘MikeOfMaine’ 🙁 And, as far as I’m aware there haven’t been any recent macOS malware that hijacks DNS settings – so I was intrigued! So without further adieu, let’s dive in to analyzing (what I’m calling) OSX/MaMi!
Analysis
Though currently I am unaware of the malware’s infection vector, it is hosted on various sites such as https://regardens.info:
curl -L https://regardens.info/ > MaMi % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 178 0 178 0 0 381 0 --:--:-- --:--:-- --:--:-- 381 100 552k 100 552k 0 0 314k 0 0:00:01 0:00:01 --:--:-- 581k MacBookPro:Downloads patrickw$ file MaMi MaMi: Mach-O 64-bit executable x86_64
As shown by WhatsYourSign, nothing too special about the file; it’s an unsigned Mach-O 64-bit executable:
As is often the case with new malware, it’s currently marked as ‘clean’ by all 59 engines on VirusTotal (this will hopefully change shortly as AV products start adding detections):
And speaking of ‘new’ if we load the malware’s binary in a disassembler, we find an app version of 1.1.0, which (due to such low version number), may seem to indicate the malware likely hasn’t been around for too long.
000000010003818f db "AppVersion: %@\nAppBuild: %@", 0 00000001000381ab db "1.1.0", 0 00000001000381b1 db "0", 0
Before we dig further into the disassembly, let’s dump the Objective-C class names and methods, as often this can allow us to quickly gain insight the malware’s (likely) capabilities or at least guide our analysis.
I use J. Levin’s invaluable jtool utility to dump such info:
$ ./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:;
Some very interesting methods! Of course we’ll continue our analysis to confirm, but seems this malware is indeed a ‘dns hijacker’ (method: setupDNS), with a host of other abilities such as:
-
- taking screenshots
-
- generating simulated mouse events
-
- perhaps persists as a launch item (programArguments, runAtLoad)
-
- downloading & uploading files
-
- executing commands
- …and more!
Jumping back to the disassemlby, within the application’s main entrypoint (-[AppDelegate applicationDidFinishLaunching:]), we see a massive encrypted string that is passes to a setDefaultConfiguration: method:
[SBConfigManager setDefaultConfiguration:@"uZmgulcipekSbayTO9ByamTUu_zVtsflazc2Nsuqgq0dXko OzKMJMNTULoLpd-QV9qQy6VRluzRXqWOGscgheRvikLkPRzs1pJbey2QdaUSXUZCX-UNERrosul22NsW2vYpS7HQO4 VG5l8qic3rSH_fAhxsBXpEe557eHIr245LUYcEIpemnvSPTZ_lNp2XwyOJjzcJWirKbKwtc3Q61pDwTzKvE0..."];
Applying some classified decryption methods I learned as an intern working in NSA’s Cryptanalysis and Exploitation Services (CES) group – it was trivial to decrypt this configuration data. I’m totally kidding – not about the internship – but about how to decrypt. Just step over that method in a debugger (lldb) and the data is sitting decrypted in memory:
# 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; }
Ok, that’s a lot of configuration data! The most interesting part is probably the ‘setup_dns’ array:
"setup_dns" = ( "82.163.143.135", "82.163.142.137" );
…we’ll see those DNS addresses used shortly!
In lldb we can set a breakpoints on methods of interest such as setupCert and setupDNS methods;
# lldb MaMi (lldb) b -[AppDelegate setupCert] Breakpoint 1: where = dcdata`-[AppDelegate setupCert], address = 0x0000000100001e0b (lldb) b -[AppDelegate setupDNS] Breakpoint 2: where = dcdata`-[AppDelegate setupDNS], address = 0x00000001000027bc
Once these breakpoints are hit, we can step thru the each instruction, or as I had fired up ProcInfo, the open-source process monitor I recently wrote (on github: ProcInfo) just let the malware run to see what it does. I’m voting for the latter as it’s almost midnight.
# ./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" )
First we see the malware invoking the security tool to install a new certificate (dcdata.bin) it’s downloaded from the internet. Let’s take a peak at this cert:
$ 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 Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (2048 bit) Modulus (2048 bit):
We can also view the (now installed) certificate via the ‘Keychain Access’ app. It’s in the System keychain as a root certificate authority….MitM anybody?!
Back to process monitoring:
# ./procInfo process start: pid: 1177 path: /bin/cp args: ( "/bin/cp", "/Library/Preferences/SystemConfiguration/preferences.plist", "/Library/Preferences/SystemConfiguration/preferences.plist.old" )
Interesting! It’s mucking with the SystemConfiguration/preferences.plist file. What’s in there? If you guessed DNS settings – you’re right!
And remember the two DNS addresses from the decrypted config data? 82.163.143.135 and 82.163.142.137, they’ve been added to the plist file:
$ grep -B 4 -A 2 82. /Library/Preferences/SystemConfiguration/preferences.plist DNS ServerAddresses 82.163.143.135 82.163.142.137
If you’re more inclined to use the UI, you can see these changes via the System Preference app (Network pane):
So, the DNS settings on the infected host have been hijacked as well.
What about the other interesting methods? (e.g. takeScreenshotAt, mouseClick, runAppleScript). We in my brief reversing/analysis/debugging session I didn’t see them being executed. Moreover, though the malware has an embedded launch item plist it didn’t attempt to persist (though as it’s altered system settings, it really doesn’t need to hang around – in fact it does self-delete). When I coerced the malware to execute the method that modifed the launch item plist, initMaMiSettings, the value it configured in the ProgramArguments key – which tells the OS what to persistently execute – was simply: ls -la && sleep 28 && ls:
# lldb MaMi (lldb) po $rax { AbandonProcessGroup = "<key>AbandonProcessGroup</key><true/>"; FooterStage = "</dict></plist>"; HeaderStage = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE plist PUBLIC \"- //Apple//DTD PLIST 1.0//EN\" \"https://www.apple.com/DTDs/PropertyList-1.0.dtd\"> <plist version=\"1.0\"><dict>"; KeepAlive = "<key>KeepAlive</key><true/>"; LabelStage = "<key>Label</key><string>%Label%</string>"; ProgramArguments = "<key>ProgramArguments</key><array><string>/bin/sh</string> <string>-c</string><string>%ProgramArguments%</string></array>"; RunAtLoad = "<key>RunAtLoad</key><true/>"; ... } (lldb) po %$rsi ls -la && sleep 28 && ls
Perhaps in order for the methods to be executed or for the malware to be persisted, requires some attack-supplied input, or other preconditions that just weren’t met in my VM. I’ll keep digging!
Conclusions
Ok, that’s a wrap. OSX/MaMi isn’t particular advanced – but does alter infected systems in rather nasty and persistent ways. By installing a new root certifcate and hijacking the DNS servers, the attackers can perform a variety of nefarious actions such as man-in-the-middle’ing traffic (perhaps to steal credentials, or inject ads).
Source:https://objective-see.com/blog/blog_0x26.html
Working as a cyber security solutions architect, Alisa focuses on application and network security. Before joining us she held a cyber security researcher positions within a variety of cyber security start-ups. She also experience in different industry domains like finance, healthcare and consumer products.