[TOC]
## 1 Fragment注入漏洞CVE-2013-6271檢測 # 12001
系統版本小于Android 4.4(API level 19)存在該漏洞。
在API level < 19(即Android 4.4)的app,所有繼承了PreferenceActivity類的activity并將該類置為exported的應用都受到Fragment注入漏洞的威脅。因為PreferenceActivity.isValidFragment函數的默認返回值為*true*,開發者不對該方法進行重寫時不會報錯。
Google在 Android 4.4 KitKat 里面修正了該問題,PreferenceActivity.isValidFragment函數的默認返回值為*false*,且要求用戶重寫該函數驗證Fragment來源正確性,若不重寫則會報錯。
風險等級:`中危`
檢測方式:`靜態檢測`
問題示例:
檢測API Level小于19的app是否有導出activity繼承自PreferenceActivity,如果存在則有注入漏洞。
我們查看一下`isValidFragment`的方法體,我們可以看到在Android 4.4版本前該方法的返回值是*true*

反編譯成Smali代碼

即

建議:
* 當Android api >=19時,要重寫每一個PreferenceActivity類下的isValidFragment方法以避免異常拋出;
* 當Android api < 19時,如果在PreferenceActivity內沒有引用任何fragment,建議覆蓋isValidFragment并返回false
查閱更多:
* http://developer.android.google.cn/reference/android/os/Build.VERSION_CODES.html#KITKAT
* http://developer.android.google.cn/reference/android/preference/PreferenceActivity.html#isValidFragment(java.lang.String)
## 2 SQLite數據庫日志泄露漏洞(CVE-2011-3901)檢測 # 12002
Android2.3.7版本存在該漏洞,其他版本可能也受到影響,4.0.1不受影響。
Android SQLite數據庫journal文件可被所有應用程序讀取,所有目錄對應程序數據庫目錄擁有執行權限,意味著應用程序數據目錄全局訪問,`/data/data/<app package>/databases`目錄以`[rwxrwx--x]`權限創建,可導致全局讀寫。數據庫目錄下創建的journal文件以`[-rw-r--r--]`權限創建,可被所有app讀取。
風險等級:`低危`
檢測方式:`靜態檢測`
通過檢測app的AndroidManifest.xml文件中聲明的min SDK版本進行判斷。如果min sdk小于4.0.1(Android API Level 14),則判定有風險,否則安全。
建議:
升級到Android4.0.1以上版本或者使用SQLCipher或其他庫加密數據庫和日志信息。
## 3 隨機數生成漏洞 # 12003
SecureRandom的使用不當會導致生成的隨機數可被預測,該漏洞存在于Android系統隨機生成數字串安全密鑰的環節中。該漏洞的生成原因是對SecureRandom類的不正確使用方式導致生成的隨機數不隨機。
**該漏洞存在于Android 4.2之前(即API < 17)**,在Android API 17以后SecureRandom的默認實現方式從Cipher.RSA換到了OpenSSL。SecureRandom新的實現方式不能將自己的seed替換掉系統的seed。
風險等級:`高危`
檢測方式:`靜態檢測`
問題示例:
檢測是否調用了SecureRandom(byte[]seed)或者setSeed(long seed)和setSeed(byte[]seed)方法。
```
Ljava/security/SecureRandom;-><init>([B)V
Ljava/security/SecureRandom;->setSeed([B)V
Ljava/security/SecureRandom;->setSeed(J)V
```
例如:
```
SecureRandom secureRandom = new SecureRandom();
byte[] b = new byte[] { (byte) 1 };
secureRandom.setSeed(b);
// 對于Android 4.2版本Test1和Test2會返回相同的值
Log.v("wgc","-------------------------------");
Log.v("wgc","Test1:" + secureRandom.nextInt());
SecureRandom secureRandom2 = new SecureRandom(new byte[] { (byte) 1 });
Log.v("wgc","Test2:" + secureRandom2.nextInt());
SecureRandom secureRandom3 = new SecureRandom();
secureRandom3.setSeed(10L);
Log.v("wgc","Test3:" + secureRandom3.nextInt());
SecureRandom secureRandom4 = new SecureRandom();
secureRandom4.nextBytes(b);
secureRandom4.setSeed(10L);
Log.v("wgc","Test4:" + secureRandom4.nextInt());
SecureRandom secureRandom5 = new SecureRandom();
Log.v("wgc","Test5:" + secureRandom5.nextInt());
```
打印的日志信息見下圖:

可見,Test1和Test2使用了相同的自定義種子,替換掉了系統默認的種子,導致隨機數的產生結果相同,而Test3使用了自定義、固定的種子,則會產生固定的結果。只有方法4和方法5才真正做到了隨機值,Test4在調用setSeed()方法前先調用了一次nextBytes()方法,而Test5則使用默認的參數進行隨機數的生成。
建議:
* 不要使用自定義隨機源代替系統默認隨機源(推薦)除非有特殊需求,在使用SecureRandom類時,不要調用以下函數:SecureRandom類下SecureRandom(byte[]seed)、setSeed(long seed)和setSeed(byte[]seed)方法。
* 在調用setSeed方法前先調用任意nextXXX方法。具體做法是調用setSeed方法前先調用一次SecureRandom的nextBytes(byte[]bytes)方法,可以避免默認隨機源被替代,詳細見參考資料。
查閱更多:
* https://developer.android.google.cn/reference/java/security/SecureRandom.html