diva write-up

diva是一个移动安全测试app,专门给开发者和安全人员演示用的app,里面包含很多的安全问题。
地址:https://github.com/payatu/diva-android
通过它能比较好的测试一些常见的andrid安全案例。下面是记录的测试过程。

不安全的日志输出

1.adb logcat
2.输入用户凭证,观察日志输出。
3.源码中:Log.e()

C6C30B66-6507-42FB-99A0-F1956E8AB124
9CD7BC64-3886-4A41-8A59-008797810824

查看源码中代码
FDD45D31-08AD-4CAD-8615-5AECD78275AA

硬编码

硬编码是开发人员将一些密钥等重要信息保存到了代码中。

用jd查看HardcodeActivity.class
092F2920-A5B9-46A0-A60C-EA0B3A9C0257
攻击者只需要在app中输入秘钥vendorsecretkey就可以访问成功。

不安全的存储1(shared_prefs/xxx.xml)

不安全的数据存储也是App常见的安全问题之一,主要有三种方式:

1将敏感数据保存到配置文件中;
2将敏感数据保存在本地的sqlite3数据库中;
3将敏感数据保存在临时文件或者sd卡中。

SharedPreferences类存储的数据会以.xml的形式存储在:
/data/data/jakhar.aseem.diva/shared_prefs
3D95DF1E-F85E-4BAD-AF2C-8E19EEECC060

源代码
66265BFC-7321-43B4-BFEF-463170B8045

不安全的存储2(databases/xxx.db)

用户的敏感信息存储到本地的数据库中,一般app对应的数据库目录:/data/data/apppackagename/databases
本例中是:/data/data/jakhar.aseem.diva/databases

如图:
60DD3640-5641-4909-80C5-DBC589FEAE50

A8ECE47D-F927-452D-8C73-0DD7CB89F7D

源代码
0A79CABE-F40F-4007-B427-F19BBB4FFD

不安全的存储3(临时文件)

文件在 /data/data/jakhar.aseem.diva/
BCDC507D-CF33-47AF-94E1-AC04FEC06184

BEBCB15E-852D-4518-8D3D-ABB3C781C49D

源代码
CDA6AD44-0BEC-451D-82AA-05D9762C636F

不安全的存储4(SD卡)

存储在sd卡中,漏洞代码片段:
181A494C-6452-4A71-B23F-29EBF62A97EB

不安全的输入1(sqli)

打开日志:adb logcat
输入一个单引号,在日志中可以看到报错信息,存在sql注入。
输入’ or ‘1’=’1,可返回所有用户密码。
1D5958A5-2D0E-46C2-9FBF-F919275B6CC0

33BDFA9F-7D8D-404C-AF45-AB912EA8418

没有验证输入,直接带入sql语句查询

不安全的输入2(读取本地文件)

这个activity的功能是显示用户输入的网页。如图,当你输入www.baidu.com它会使用一个webview去加载这个页面。

9716BA5C-2002-46B4-BCB9-BB1E9C09F83D

ADDEEB3E-C323-4C0F-87E0-BE46BBFAE577

目标是使用此功能访问设备上的敏感信息。先来看看它的源代码,在InputValidation2URISchemeActivity.java中

A9A5CBFA-F20A-4C7D-98B5-0E67B0874872

用loadUrl方法加载用户输入的URL,这个方法也可以加载本地文件。
读取本地文件:file:///data/data/jakhar.aseem.diva/shared_prefs/jakhar.aseem.diva_preferences.xml

FF2BBE17-3DE3-4DF7-A11C-AB3312A8F19A

访问控制1(Activity 1)

目的是在不点击此按钮的情况下访问这些信息。看看AndroidManifest.XML文件中与Vendor API Credentials activity相关的信息。
247B1D1C-C673-4BD1-A18E-2D996FB8F53D

activity是通过intent filter“保护”的。intent filter不应该被作为一种保护机制。当intent filter和像activity这样的组件一起使用时,组件是被暴露在外的。这里的activity可以被其它应用从外部加载,这是非常不安全的。我们可以通过终端中下面的命令来验证。
利用am(Activity Manager tool)启动暴露的组件,来绕过权限控制:
adb shell am start jakhar.aseem.diva/.APICredsActivity
或者
adb shell am start -n jakhar.aseem.diva/.APICredsActivity -a jakhar.aseem.diva.action.VIEW_CREDS

755D57F6-4CCC-498C-B6E2-C20A7423BB19

使用drozer绕过权限
3D71A7C4-BFDE-492A-B438-029B37FFD30

访问控制2(Activity 2)

如果你是注册用户,你就能访问tweeter API的凭据。我们的目标是在不注册的情况下访问它。再次看看AndroidManifest.XML文件。

C64F68B2-3C90-4D05-A97A-7BCF8A7EAF3

尝试相同的命令发现并不能绕过,出现了pin码,看看源代码文件APICreds2Activity.java
03797199-3CEA-457A-8D31-2F1338293F99

可以看出,当我们用ADB命令启动intent时需要一个额外的布尔类型参数。下面这一行解析字符串chk_pin。

boolean bcheck=i.getBooleanExtra(getString(R.string.chk_pin),true);
我们可以在strings.xml中查找它实际对应的值。
52032F75-F1A1-4B77-BC36-0B398B1B1BFD

这个条件是用来验证用户是否已经注册的,可以从AccessControl2Activity.java的以下代码中看出。
16D90B4C-2F8C-43B1-A977-372F92A0787A

如果 chk_pin = true 说明需要现在注册,跳转到注册页面;如果 chk_pin = false 说明不需要注册,或者说已经完成注册,就会跳到认证后的界面
据此我们需要设置 chk_pin = false 来控制页面跳转完成破解
使用adb下面命令绕过
adb shell am start -a jakhar.aseem.diva.action.VIEW_CREDS2 -n jakhar.aseem.diva/.APICreds2Activity --ez check_pin false
或者drozer命令
run app.activity.start --component jakhar.aseem.diva jakhar.aseem.diva.APICreds2Activity --extra boolean check_pin false
B6431D4D-521D-4FE1-BA5E-C6D0A9FB78A6

访问控制3(Content Providers)

笔记pin码保护,发现注册笔记生成一个pin码,必须通过pin码才能绕过,查看AndroidManifest.xml中关于此案例的描述
A8A43289-1855-4043-95BC-19EADB4F7F04

发现有个 exported = true 的 provider 注册。content providers 使用URI,通常开头是 content://
使用搜索功能查找关键字:content://
找到 NotesProvider.smali 中重要信息
89459067-61B0-49C3-A09D-40B228793879

根据以上smail代码,找到路径
content://jakhar.aseem.diva.provider.notesprovider/notes
根据xml中属性信息,这个content 是exported = true 的,也就意味着可以直接外部访问
输入命令
adb shell content query --uri content://jakhar.aseem.diva.provider.notesprovider/notes
就可以查询到认证后的私有笔记信息
EF0E3906-D9B2-4BD6-BC0F-414D71DA3D10

使用drozer
run scanner.provider.finduris -a jakhar.aseem.diva run app.provider.query content://jakhar.aseem.diva.provider.notesprovider/notes/
36C8BF5A-6474-44C8-B9AA-AE9A482D

硬编码

144FE9A1-AACE-4A59-9C1A-0F4DB246E6BB

在Hardcode2Activity. class中
BF617522-2C2F-48F9-B65A-2B4675665085

activity在加载时创建了DivaJni class的一个对象。查看其它文件发现有一个叫做DivaJni.class的文件

44DDB38B-926E-4337-834B-EC1F12E

程序加载了一个名为divajni的库,解压apk进入lib目录。对于每种架构,都有一个libdivajni.so的实例。随便找一个运行strings命令
21E2A8E6-1750-48BA-9864-B5DD6323669D

olsdfgad;lh找到了这个key。这个写法是 java调用c/cpp程序常用的jni接口。可以ida反编译so文件
A60735F3-14DE-40EF-90C9-404C1F2815F6

发现是在比较olsdfgad;lh这个字符串
或者有源代码,查看源码发现确实存在jni文件夹以及 divajni.c程序
034C7DF3-A8B0-42EA-9731-615F81CFA023

2E668F5C-8C6E-4848-816D-18B16D738EF5

很显然,将字符串硬编码在so文件中也同样是不安全的
39C0EDD2-7CBA-491F-B1B5-AC72F161A8

输入验证问题

CB50C2C4-E553-40FC-987A-7545C15457
翻译一下是:
目标:这是一个导弹发射程序,我们应当传播爱与和平而不是战争0.0。让此程序失效,你的任务不是找到代码发射导弹,而是让应用崩溃(并找到崩溃原因)。
提示:不正确或不存在的输入验证会导致应用漏洞。外部的输入必须得进行验证。这是一个经典的缓冲区溢出漏洞。如果你可以实现代码执行,那就太nb了。

然提示是缓冲区溢出类漏洞,那主要工作就是要确定缓冲区的长度。
查看反编译代码 InputValidation3Activity.class 发现验证需要 djni.initiateLaunchSequence() 来确定
89038230-757E-4D9B-89F0-C52D82AF97CE

分析代码,仍然需要System.loadLibrary(“divajni”)中jni接口调用的 divajni.c程序,查看 divajni.c 源码,找到 initiateLaunchSequence()的定义

查看 divajni.c 源码,找到 initiateLaunchSequence()的定义

分析代码,问题出在strcpy(code,pcode),没有对pcode的长度做判断就直接给了code,而code的长度之前定义的为20,所以这里就会出现很明显的缓冲区溢出。

也可以通过ida查看so文件
931DE608-B973-4912-960F-D1F577128F9B

测试时发现,当输入字符 大于32 时,才可以引发程序崩溃。可以使用 adb logcat查看崩溃时堆栈数据
CDE5464E-7752-44B4-8B46-72C6BF1D9E79