0x01 客户端攻击之静态分析技术
1.Activity
导出的activity是安卓应用组件在渗透测试中经常遇到的问题之一。导出的activity可以被同一设备上的其他应用调用。
导出属性默认值取决于activity是否包含Intent过滤器,如果不包含过滤器,那么只能通过指定准确的类名才能调用activity。这意味着这个activity只能在应用内部使用(因为其他应用不知道这个activity的类名)。在这种情况下,activity的默认导出属性是false。如果出现了多个过滤器,则意味着这个activity可以被外部使用,activity的默认导出属性为true。所以如果应用包含一个导出的activity,那么其他应用可以调用它。
adb shell am start -n [组件名]
- am: activity 管理工具
- start: 启动一个组件
- -n : 指定要启动的组件
但是,由于某些原因,开发人员想要导出这个activity,可以通过自定义权限来导出,只有拥有这些权限的应用才能调用这个组件。
还有另一种可能的方法能够导出activity,既Intent过滤器,Intent过滤器指定了哪一种Intent可以启动应用组件。我们可以通过使用Intent过滤器添加特殊条件来启动一个组件。Intent过滤器能够启动组件来接受制定类型的Intent,同时过滤掉对组件无意义的Intent。许多开发人员把Intent过滤器当作一种安全机制。事实上,Intent过滤器不应该被当作一种用来保护组件的安全机制,如果你使用了Intent过滤器,请记住组件的默认导出属性。
例如:在<Intent-filter>标签中声明了一个activity元素。要想顺利通过这个过滤器,Intent中用于启动应用的action需要与声明的action匹配。如果启动时不指定任何过滤器,它仍然可以运行。
2.服务
安卓应用中的服务通常用于在后台处理长时间运行的任务。虽然这是服务最常见的用法。而且大部分面向初学者的博客也是这样介绍的,但是还存在一些其他类型的服务,他们能为设备上的其他应用或同一应用的其他组件提供接口。所以,服务基本可以分为两种:启动和绑定
我们可以使用startService()来启动服务,服务启动后,会在后台不停地运行,即使启动该服务的组件已经销毁。
我们可以使用bindService()来绑定服务,绑定服务提供了一个从客户端到服务端的接口,能够让组件与服务进行交互、发送请求、获取结果,甚至可以通过进程间通信在不同的进程上实现这些功能。
可以使用下面的三种方法创建绑定服务:
2.1 扩展binder类
如果开发人员想要在同一个应用中调用某个服务,建议使用这种方法。这样,设备上的其他应用就不能调用这个服务。具体方法是,扩展Binder类来创建一个接口,并从onbind()返回一个关于他的实例。客户端接收到binder()后,可以通过它直接访问该服务中的公共方法。
2.2 使用Messenger
如果需要跨进程使用接口,可以使用Messenger为服务创建一个接口。通过这种方法创建的服务可以定义Handler,而且Handler能够响应不同类型的Message对象。这样客户端可以使用Message对象向服务发送命令。
2.3 使用AIDL
AIDL是一种允许一个应用调用另一个应用的方法,与activity相似,一个未受保护的服务也可以被设备上其他应用调用,使用startService()就可以调用第一种服务,我们使用adb命令也可以调用第一种服务。
adb shell am seartservice -n [服务名] -a [服务名]
3.广播接收器
广播接收器是安卓系统中最常见的组件之一,开发可以利用广播接收器来添加很多功能。导出的广播接收器容易受到攻击。
通过研究它的源码,发现应用可以接收广播,然后根据接收到的广播发送短信,同时,他还会受到短信和要发送的短信号码。要想实现该功能,需要在AndroidManifest.xml文件中注册了SEND_SMS权限,这个应用无法检测是谁发送了广播事件,攻击者可以根据这一点,并使用下面的命令来创建一个特殊的Intent
adb shell am broadcast -a [action元素] -n [组件名称] -es phoneNumber 5556 -es message CRACKED
- -a : 指定action元素
- -n : 指定组件名称
- -es : 指定字符串键值对的其他名称
4. 内容提供程序
导出的内容提供程序也能被滥用。如果应用的目标SDK版本号是API17,那么内容提供程序默认是导出的,这意味着如果不在AndroidManifest.xml文件中显式的指定exported=false,内容提供程序默认就是导出的。从API17开始,这个默认值就改变了,而且默认值变成了false,此外,如果应用导出了内容提供程序,我们可以像使用前面的其他组件一样来使用它。
4.1 查询内容提供程序
如果内容提供程序的导出的,我们可以对它进行查询并读取其中的内容,也可以插入或删除内容。但是,在此之前,我们需要首先找出内容提供程序的URL,使用Apktool分解APK文件时,它会在smali文件夹中生成一些.smali文件,我们可以使用grep命令进行递归搜索,查找包含“content://”的字符串。
/outputdir/smali/com/sonyericsson/notes/*.smali
$grep -lr "content://" *
在结果文件中搜索“content://”字段,找到导出的URL
读取URL的内容:adb shell content query --uri [URL]
安卓4.1.1系统开始使用了content命令,这实际上是存放在/system/bin/content下的一个脚本,可以利用它通过adb shell 直接读取内容提供程序
adb shell content query --uri [内容提供程序],可以直接读取内容提供程序数据库的内容
4.2 通过adb对内容提供程序进行SQL注入
- 内容提供程序通常是基于SQLite数据库的。如果输入数据库的命令没经过合适的处理,就会发生于web应用相同的SQL注入的情形
- 首先再一次查询内容提供程序的内容,adb shell content query --uri [URL]
- 编写一个where条件,adb shell content query --uri [URL] --where “_id=1",添加一个简单的where子句来过滤数据库,列名是—id,是通过查询的内容得到的
4.3 注入测试
如果你拥有传统web应用渗透测试的背景,可能会注意到,单引号是SQL注入测试中最常用的字符,我们尝试在where字句传递的字符串中添加一个单引号
adb shell content query --uri [URL] --where "_id=1' "
我们想要测试单引号是否会导致数据库执行sql语句时报语法错误,如果会,就意味着外部输入没有经过合适的验证,那么应用可能存在注入漏洞。
查找用于提取信息的所有列号,与web数据库注入类似,现在执行一条包含UNION操作符的SELECT语句,查看输出的所有列
adb shell content query --uri [URL] --where “_id=1 ) union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14-- ("
这十四列应该与现有的select语句中的列号相匹配,编写包含union操作符的select语句时,列号应该是相同的,这样前面的查询就会在句法上和现有查询语句匹配,而且不会报错
查找Sqlite版本号
运行sqlite_version()函数会显示SQLite的版本信息,将任意数字修改为sqlite_version()
adb shell content query --uri [URL] --where “_id=1 ) union select 1,2,3,4,sqlite_version(),6,7,8,9,10,11,12,13,14-- ("
查找表名
想要检索出表名,可以将前面查询语句中的sqlite_version()替换成tbl_name。此外,我们还需要从sqlite_master数据库中查询表名。sqlite_master类似于MySql数据库中的information_schema。它保存了数据库的元数据和结构。
adb shell content query --uri [URL] --where “_id=1 ) union select 1,2,3,4,tbl_name(),6,7,8,9,10,11,12,13,14 from sqlite_master-- ("
5.使用QARK进行自动化静态分析
5.1 介绍
Qark是一款静态代码分析工具,可以识别潜在的安全漏洞以及使用java开发安卓应用时的注意事项。Qark是基于社区设计的,并且人人都能免费使用。Qark能够将安卓应用潜在的安全风险告知开发者及信息安全人员,详细描述各种问题,并且提供权威参考资料链接。Qark还尝试提供动态生成的ADB命令来验证检测到的潜在漏洞。只要条件允许,它甚至会动态生成一个定制的测试应用,以现成的apk文件形式来演示它发现的潜在问题。
Qark对安全缺陷的分析范围包括:
- 不经意公开的组件
- 保护不当的公开组件
- 易被窃听或嗅探的Intent
- 不当的x.509格式的证书校验
- 不当地创建“全局可读”或者“全局可写”文件
- 可能泄露敏感数据的Activity组件
- 是否正确使用Sticky Intent
- 不安全地创建Pending Intent
- 发送未经安全保护的Broadcast Intent
- 源代码中嵌入了私钥
- 使用了弱或不当的加密解密算法
- 使用了有潜在安全问题的WebView配置项
- 对其他应用公开的Preference Activity
- 触屏劫持
- 允许备份的应用
- 允许调试模式的应用
- 应用中使用的过时的API,其中包含了已知的缺陷
当QARK指出一个潜在缺陷的时候,会针对该缺陷,提供概要解释和一条详细解释的链接。它还可以创建可测试的APK文件和若干ADB命令,这些文件和命令能让你知道该缺陷会产生怎样的危害。
QARK的脚本中是没有脱壳的脚本,所以是需要未加固的APK。
5.2 下载安装
环境:
5.3 使用方式
下载Qark文件,解压后使用python执行qark.py文件,有两种模式;qark安装最新版本要先安装setup.py和安装requirements.txt库然后才能运行。
python2 -m pip install -r requirements.txt
python2 qark.py
首次安装需要指定Android SDK的位置,可以先下载好,指定路径即可。
a. 以交互模式运行
交互模式允许用户逐一的选择交互选项
python qark.py

我们可以根据需要提供apk文件或源代码(选择1或者2)

如果选择提供apk文件,需要选择是提供APk文件路径还是从设备拉取apk

输入apk所在位置

将会提取AndroidManifest.xml文件,输入y就能提取文件

按回车继续,开始分析AndroidManifest.xml文件

从上图看出,Qark发现了几个问题,继续按回车之后,Qark开始反编译

如果反编译过程由于某些原因花费了比较长的实际,我们可以直接按下c键开始对反编译过程中已提取的代码进行分析。Qark使用多种工具来执行反编译。反编译结束之后,按回车开始分析代码

Qark启动了源代码分析功能来识别代码中的漏洞。最后生成了一段很长的输出,里面包含所有可能存在的漏洞,之后可以选择1,创建一个POC应用,这是他的特有功能之一,此外,它还提供了一些adb命令来利用识别出的问题。
测试报告,Qark在执行结束会生成repoet.html的报告文件,我们可以从上图中找到路径

报告中可以清晰的看到APK所存在的漏洞
我们可以使用报告中提供的adb命令来验证漏洞

b. 以无脑模式运行
无脑模式则允许用户使用一条单独的命令来完成全部工作:
python qark.py --source 1 --pathtoapk [apk路径] --exploit 1 --install 1
程序将会执行和前面相同的流程来查找漏洞,不过这种模式不需要用户干预
如果在构建POC应用时遇到错误,可以将--exploit的值设为0,如果不想它安装到设备上,可以将install的值设为0


5.4 问题
运行时出现
Traceback (most recent call last):
File "qark.py", line 625, in <module>
unpackAPK.decompile(common.pathToDEX)
File "/home/qark-0.9-alpha.1/modules/unpackAPK.py", line 123, in decompile
sp = subprocess.Popen([pathToDex2jar, common.pathToDEX], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
File "/usr/lib/python2.7/subprocess.py", line 711, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1343, in _execute_child
raise child_exception
OSError: [Errno 13] Permission denied
原因是权限不够,需要给当前文件夹写权限。
解决:进入上层目录,添加权限
chmod -R 777 qark-0.9-alpha.1/
在安装的过程会有一个问题就是python no module named curses的问题,这个问题最后解决了,经过对比python2.6 ,终于发现,原来 pythong2.7/lib-dynload 里没有相应的 curses 库,curses_panel.so,_curses.so。说到底就是去缺少文件,所以此时你将python2.6 的 这2个so文件拷贝到 pythong2.7 的lib-dynload 文件夹下, 就解决了问题。或者你可以下载ncurses文件,然后重新跑下python就可以了
本文仅做简单的工具使用说明,qark以及adb命令还有很多使用方法,继续学习中。。。
感兴趣的师傅可以关注公众号,感谢支持。
