Ay MaMi
› Analyzing a New macOS DNS Hijacker: OSX/MaMi
01/11/2018
love these blog posts? support my tools & writing on patreon! Mahalo :)
2018 is barely two weeks old, and already it looks like we've got new piece of macOS malware! Hooray :)
Want to play along? I've shared both the malware's binary executable ('
MaMi'), which can be downloaded
here (password:
infect3d).
Please don't infect yourself!
Background
Earlier today (01/11), someone on MalwareBytes' forum created a post titled "DNS Hijacked":
As I hadn't seen an answer to 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 http://regardens.info:
curl -L http://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
...
$ 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
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\" \"http://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!
(Windows) Relatives
After chatting with @noarfromspace, about this malware, he dug up an interesting article from 2015. Titled, "The mystery of 82.163.143.172 and 82.163.142.174", the article dicusses a piece of Windows malware named DNSUnlocker that also hijacked DNS settings on Windows systems. This DNSUnlocker malware seems closely related to OSX/MaMi for a few reasons:
- DNS servers:
DNSUnlocker, hijacks Windows victim's DNS servers to: 82.163.143.172 and 82.163.142.174
OSX/MaMi, hijacks Mac victim's DNS servers to: 82.163.143.135 and 82.163.142.137
- Certificate:
The certifcate installed by both malware specimens is the same:
Clearly DNSUnlocker, while older (circa 2015) and Windows only, is closely related to OSX/MaMi. If I had to guess, I'd say it's likely OSX/MaMi is a (fully re-written?) macOS version of DNSUnlocker, with a lot of extra macOS-specific evilness.
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).
Let's end with some Q&A!
Q: How do I get infected?
A: At this time, this is unknown. However, it's likely the attacker are using (rather lame) methods such as malicious email, web-based fake security alerts/popups, or social-engineering type attacks to target mac users
Q: How do I know if I'm infected?
A: Check your DNS settings, looking to see if they've been set to 82.163.143.135 and 82.163.142.137. You can check via the terminal (e.g. networksetup -getdnsservers Wi-Fi), or via the System Preferences app (Network pane). Also check for malicious cloudguard.me certifcate, which if installed, will appear in the System Keychain:
Q: How do I disinfect myself?
A: Often malware can install other malware, or allow an remote attacker to do what ever they want. Thus if you were/are infected it's suggested you fully re-install macOS. However, you can probably get away with simply resetting the DNS servers and deleting the malicious certifcate.
- Remove DNS Servers:
Open the System Preferences Application, click the 'Network' Icon, then the 'Advanced' button, and finally the 'DNS' button. If infected, you'll see the malicous DNS servers (82.163.143.135 and 82.163.142.137):
Selected each server, then click the '-' button to delete.
- Remove Certificate:
Open the Keychain Access Application, click on 'System' in the Keychains (top left). If infected you'll see the malicious certificate (cloudguard.me). Right click on the certifitcate and select 'Delete' to remove it:
Q: Will my AV product protect me?
A: Evenutally. But for now, it does not appear that any will. I'd recomment a 3rd-party tool such as firewall that can detect & block outgoing traffic. I'm currently working on a free open-source firewall named 'LuLu' that will detect OSX/MaMi's network traffic:
Q: Did I discover this malware?
A: No, a good friend brought it to my attention. I just happen to blog about things such as macOS malware!
Q: Why the name, OSX/MaMi
A: Since there are already several (IMHO unrelated) malware specimens that perform DNS hijackering (that are named 'DNSChanger', etc), I decided to call is OSX/MaMi due to a core class the malware named: 'SBMaMiSettings'
love these blog posts & tools? you can support them via patreon! Mahalo :)