[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*
![isValidFragment](https://wiki-1252789527.picsh.myqcloud.com/scan_model/image085.jpg?imageMogr2/thumbnail/500x)
反编译成Smali代码
![isValidFragment反编译代码](https://wiki-1252789527.picsh.myqcloud.com/scan_model/image087.jpg?imageMogr2/thumbnail/500x)
即
![不知道啥的代码](https://wiki-1252789527.picsh.myqcloud.com/scan_model/image089.jpg)
建议:
* 当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());
```
打印的日志信息见下图:
![随机数漏洞-代码示例运行的结果](https://wiki-1252789527.picsh.myqcloud.com/scan_model/image092.jpg?imageMogr2/thumbnail/400x)
可见,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