翻译:houjingyi233
预估稿费:200RMB
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
传送门
【技术分享】Android App常见安全问题演练分析系统-DIVA-Part1
APK下载:http://payatu.com/wp-content/uploads/2016/01/diva-beta.tar.gz
源代码下载:https://github.com/payatu/diva-android
前一部分我们讨论了不安全的日志输出、硬编码问题和不安全的数据存储。这一部分我们继续讨论android app中其它的常见安全问题。
VII. 问题4 :输入验证问题
在APP中点击“7. INPUT VALIDATION ISSUES – PART 1”。如果你知道用户名,你就能取得与之相关的数据。我们的目标是在不知道用户名的情况下获取所有的数据。点击之后你会看到下面的activity页面。
由于它具有搜索功能,我的第一个假设是应用程序可能会根据用户输入从数据库中搜索某些内容。会存在SQL注入漏洞么???我们需要测试一下。这次我们来做一个黑盒测试而不是先看代码。让我们输入一个单引号,看看应用程序的响应。
看起来没有什么反应,但是在logcat中我找到了下面的条目。
好消息!可能存在SQL注入。从上面的错误可以看出,程序使用SQL查询从SQLite数据库中获取信息,而我们输入的单引号造成语句中单引号没有配对,从而出错。我们再加一个单引号,看看app有什么反应。
看起来程序正在搜索输入的数据,没有产生SQL错误。为了进一步确认,我们再加一个单引号,看看是否会引发SQL错误。
logcat中再次看到了下面的结果。
完美!现在确认了SQL注入,奇数个单引号会导致SQL错误,当引号刚好匹配时SQL查询正好会执行。下一步呢?我们使用一个总是返回true的字符串来得到数据库中的数据。
1’ or ‘1’ != ‘2
如图所示,通过执行恶意的SQL查询我们能够得到应用数据库中的所有数据。下面是导致问题的SQLInjectionActivity.class中的一部分代码。
下面这句代码正是导致问题的罪魁祸首,app接收了用户的输入,没有经过验证就直接加入到SQL查询语句中。
cr = mDB.rawQuery("SELECT * FROM sqliuser WHERE user = '" + srchtxt.getText().toString() + "'", null);
在app中点击“8. INPUT VALIDATION ISSUES – PART 2”。这个activity的功能是显示用户输入的网页。如图,当你输入www.baidu.com它会使用一个webview去加载这个页面。
我们的目标是使用此功能访问设备上的敏感信息。先来看看它的源代码,在InputValidation2URISchemeActivity.java中。
程序使用loadUrl方法加载用户输入的URL,这个方法也可以加载本地文件。我们创建一个1.txt,在里面写上123。
把这个文件传到sdcard上。
使用file:///格式来读取文件。
成功读取了文件内容。
在app中点击“13. INPUT VALIDATION ISSUES – PART 3”。这个程序要求输入一个密码,我们的目标是在不知道密码的情况下让程序崩溃。
我们一次性多输入一些字符串,程序就会崩溃并退出。我输入了一串a,现在让我们用adb logcat命令查看在logcat中是否有对我们有用的信息。
从上面logcat中可以看出,很显然崩溃是因为CPU试图跳转到61616160地址处发生的,a的ASCII值就是0x61。我们来看看InputValidation3Activity.java中的源代码。
这个校验是在native层做的,来看看divajni.c。
Buffer的大小是20,由于strcpy函数缺少边界检查导致缓冲区溢出,程序崩溃。理论上来讲这个漏洞还可以继续进一步利用,如果大家有兴趣深入研究的话可以参考这篇文章ARM栈溢出攻击实践:从虚拟环境搭建到ROP利用。
VIII 问题 5:访问控制问题
在APP中点击“9.ACCESS CONTROL ISSUES – PART 1”。你会看到下面的界面。
我们可以通过点击上述活动中显示的“VIEW API CREDENTIALS”按钮访问API凭据。
我们的目标是在不点击此按钮的情况下访问这些信息。看看AndroidManifest.XML文件中与Vendor API Credentials activity相关的信息。
如果你注意到以上的信息,你就会发现activity是通过intent filter“保护”的。intent filter不应该被作为一种保护机制。当intent filter和像activity这样的组件一起使用时,组件是被暴露在外的。这里的activity可以被其它应用从外部加载,这是非常不安全的。我们可以通过终端中下面的命令来验证。
上面的命令通过-a参数指定intent。虽然adb shell am start jakhar.aseem.diva/.APICredsActivity命令也能起到同样的作用,但是这是一种更普遍的方式。
在APP中点击“10.ACCESS CONTROL ISSUES – PART 2”。你会看到下面的界面。
如果你是注册用户,你就能访问tweeter API的凭据。我们的目标是在不注册的情况下访问它。再次看看AndroidManifest.XML文件。
看起来和前面并没有什么区别。我们试试下面的命令看看能否成功。
当我们运行上述命令之后会看到下面的界面。
看来程序还有一些额外的检查。让我们看看源代码文件APICreds2Activity.java。
可以看出,当我们用ADB命令启动intent时需要一个额外的布尔类型参数。下面这一行解析字符串chk_pin。
boolean bcheck=i.getBooleanExtra(getString(R.string.chk_pin),true);
我们可以在strings.xml中查找它实际对应的值。
下一行是检查check_pin值是否为false。这个条件是用来验证用户是否已经注册的,可以从AccessControl2Activity.java的以下代码中看出。
如果用户已经注册,check_pin会被设置为false,否则被设置为true。当check_pin被设置为false时,应用程序没有进行其它检查。所以,让我们尝试将这个额外的参数传递给intent,看看它是否有效。
-ez参数传递一个类型为boolean的键值对。运行上述命令将显示以下内容。
和前面一样,adb shell am start -n jakhar.aseem.diva/.APICreds2Activity -ez check_pin false也是可以的。
在APP中点击“11.ACCESS CONTROL ISSUES – PART 3”。你会看到下面的界面。
我们输入一个新的PIN码。一旦你这样做,将出现一个新的按钮,如下所示。
点击这个按钮,它将启动一个新的activity,如下所示。
我们可以通过输入之前设置的PIN来访问私人笔记。
我们的目标是在不输入PIN码的情况下访问这些内容。AndroidManifest.XML文件显示程序注册了一个content provider,并且android:exported属性为true。
Content Providers使用以content://开头的URI来表示。我们需要找到访问数据的URI。首先使用apktool反编译apk得到smail代码。
在smail代码目录下搜索包含content://字符串的所有文件。
正如我们在AndroidManifest.XML文件中看到的那样,content provider被导出,因此我们可以在没有任何明确许可的情况下查询它。
IX问题 6:硬编码
前面我们已经研究过一个硬编码问题了。在APP中点击“12. HARDCODING ISSUES – PART 2”。你会看到下面的界面。
我们的目标是找到vendor key并提交给程序。下面是Hardcode2Activity. class中和这个activity相关的反编译代码。有许多工具可以直接得到反编译apk得到java代码,常用的有jadx、JEB、GDA等等。这里我用的是JEB。
看起来这个activity在加载时创建了DivaJni class的一个对象。查看其它文件发现有一个叫做DivaJni.class的文件。
程序加载了一个名为divajni的库,解压apk进入lib目录。对于每种架构,都有一个libdivajni.so的实例。随便找一个运行strings命令,看看我们是否可以找到什么有趣的东西。
在windows系统下运行这个命令可以使用SysinternalsSuite中的strings.exe。
olsdfgad;lh这个字符串看起来很有趣,我们来试试。
我们找到了这个key。很显然,将字符串硬编码在so文件中也同样是不安全的。
这个APP中的全部漏洞就讲解完了,希望能为大家学习android应用程序漏洞带来帮助。
传送门