3.12系统漏洞检测

文章目录
  1. 1. 1 Fragment注入漏洞CVE-2013-6271检测 # 12001
  2. 2. 2 SQLite数据库日志泄露漏洞(CVE-2011-3901)检测 # 12002
  3. 3. 3 随机数生成漏洞 # 12003

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

反编译成Smali代码

isValidFragment反编译代码

不知道啥的代码

建议:

  • 当Android api >=19时,要重写每一个PreferenceActivity类下的isValidFragment方法以避免异常抛出;
  • 当Android api < 19时,如果在PreferenceActivity内没有引用任何fragment,建议覆盖isValidFragment并返回false

查阅更多:

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)方法。

1
2
3
Ljava/security/SecureRandom;-><init>([B)V
Ljava/security/SecureRandom;->setSeed([B)V
Ljava/security/SecureRandom;->setSeed(J)V

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

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)方法,可以避免默认随机源被替代,详细见参考资料。

查阅更多: