实验目的
重打包(repackaging)攻击是 Android 设备上一种非常常见的攻击类型。在此类攻击中,攻击者修改从应用市场下载的流行 app,对该 app 进行逆向工程,添加一些恶意负载,然后将修改后的 app 上传到应用市场。用户很容易被欺骗,因为很难注意到修改后的 app 和原始 app 之间的区别。一旦安装了修改后的app,里面的恶意代码就可以进行攻击,通常是在后台。例如,2011 年 3 月,发现 DroidDream 木马已被嵌入 Android 官方市场的 50 多个 app 中,并感染了众多用户。DroidDream 木马利用 Android 中的漏洞获取设备的 root 访问权限。
实验步骤与结果
实验环境
Android 虚拟机:
本次实验需要部署 Android 虚拟机,来测试我们的重新打包攻击。
Ubuntu 16.04 VM:
本次实验的实验需基于 SEED Labs 的 Ubuntu 16.04 VM。
Ubuntu 16.04 VM
在 SEED 2.0 平台(Ubuntu 20.04 VM)上安装所需要的工具包,部分需安装工具包括:
$ sudo apt install android-tools-adb
$ sudo apt install apktool
说明
Task 6 中的位置显示页面是基于 Google Map API 实现的,由于众所周知的原因,Google 旗下服务在国内无法正常使用,并且 API Key 可能已经失效,无法显示最终效果。可以使用变通方案(2 选 1):
1. 通过 Wireshark 抓包的方式查看从 Android 端发送的包含位置信息(GPS 数据)的数据包。
2. 将服务器端代码更改为国内地图软件提供的 API(如高德地图 API、百度地图 API 等),实现位置显示页面。代码路径:/var/www/RepackagingAttack。使用此种方式,将提供 Bonus 10 分,需在报告中展示修改后的代码。
Task 1:获得APK文件并安装
为发动重打包攻击,我们需要一个宿主APP,对于本次实验,可以自己编写APP或下载一个已有的APP,可以从很多地方下载到各类APP,例如 https://apkpure.com/ . 我们这次使用实验平台提供的APK文件。 (文件名为 RepackagingLab.apk)
我们通过Ubuntu VM的adb工具来安装宿主APP:首先需要通过Android VM的ifconfig命令找到Android VM的IP地址,
随后通过以下命令安装APP:
Task 2:APP反汇编
为了在该APP中实现重打包攻击,我们需要对APP做一些修改,由于APK文件中包含人类不易读的Dalvik 字节码 (dex 格式),因此直接修改APK文件虽然可行但并不容易。我们需要将字节码转换为可读的形式。对于Dalvik字节码,最普遍的可读格式是Smali。
本次实验,我们需要使用APKtool来反汇编dex码至Smali码。APKtool是一个在解构和重构APP时非常有用的工具。我们通过一下命令实现:
APK文件其实就是个包含class.dex (编译的java源码, 叫做 Dalvik字节码) resources.arsc (源文件), AndroidManifest.xml等文件的ZIP文件。APKtools首先对APK文件解压缩,并对内容进行解码,对于源文件,没有大量修改的地方. 对于Dalvik字节码classes.dex, 它会被解码成smali code, APKTool 会把处理过的文件放置到一个和APK文件同名的文件夹中(它会自己创建)经过反汇编后的APK文件大体框架如图:
文件夹包含 XML源文件, AndroidManifest, 源代码等。XML文件和AndroidManifest 文件通常可读且与原先真正的源文件相似。反汇编的smali代码被放置在smali文件夹. 通常,一个smali 文件包含给一个java类提供的代码。
Task 3:注入恶意代码
在这个例子中,我们在宿主app的smali文件中注入恶意代码。虽然有很多种,但通常由两种方法:在原有的smali文件中修改,这需要修改smali文件的执行逻辑;或者更简单地,直接向app文件中加入新组件。该组件是和源app独立的,因此不会影响app执行逻辑。
在Android文件中,有四种组件:activity,service,broadcast receiver,content provider。前两种在app种最常用。我们可以向app中添加任意组件,但最关键的问题是应当找到一种方法使得用户不会察觉。最简单的方法是使用broadcast receiver,这种方式通过系统发送broadcast来触发。我们可以写一个 broadcast receiver 来监听这些broadcast, 使得攻击代码能在这些事件发生并发送broadcast时自动触发。
写一个broadcast receiver非常简单。实验也提供了现成的smali代码。Java代码如图所示:
上述恶意代码如果被触发,将会删除联系人。代码通过broadcast receiver实现。当被broadcast触发时,会调用onReceive()方法,里面包含了恶意代码。上述代码主要过程是通过与联系人app交互,通过content provider来删除所有联系人。在代码里, ContentResolver用于接触到手机中的联系人。 为了获得联系人列表, 一个查询请求被发送到联系人APP的content provider. 所有的联系人记录都将通过Cursor object 来返回。 随后app会将联系人逐个删除。
我们需要将攻击代码放置在smali/com文件夹中:
但是还没完,因为我们尚未告知系统何时调用broadcast receiver。我们需要将broadcast receiver注册至系统中。这通过在AndroidManifest.xml添加几行代码实现。为了能读写联系人,我们需要在该文件中请求两个权限:
在第2行和第3行,我们添加了两个权限的请求,分别是允许应用读取联系人,允许应用修改联系人。注意,这两行需要添加在<application>外,在<manifest>内。同时我们需要将broadcast receiver和TIME_SET绑定,这样每次修改时间,恶意代码就会触发。这一段需要写在<activity>标签内。
Task 4:将带有恶意代码的app文件重打包
在代码注入完成之后,我们需要做的就是将各种文件打包至一起,组合成一个新的apk文件。包含两步:
Step1 重构APK: 通过APKtool重新生成APK文件,新的文件将会保存至文件夹下的\dist目录下:
Step2 对APK文件签名: Android需要所有的app在发布之前必须经过数字签名和证书,签名和证书用于帮助Android检测app文件编写者。为保证安全,证书需要由签发机构(CA)提供。通常由CA获取证书非常麻烦,因此Android允许开发者使用自己的私钥对证书签名。这种自签名的目的是为了能让app在android上运行,而非保证安全性。本次实验我们使用自签名证书:
- 通过keytool指令生成公钥和私钥:
- 使用jarsigner,利用第一步生成的私钥来为apk签名:
jarsigner 会让用户输入口令来让用户访问生成的keystore。随后会利用密钥(由名称”mykeys”来识别)来对APK签名。
Task 5:安装重打包APP并执行恶意代码
如果我们在之前已经安装过APP,我们需要先卸载,否则我们无法安装:
卸载完毕再安装新的app,如果不卸载会导致新app与旧app签名不符:
卸载干净后可以成功安装
在攻击前,我们需要给予应用相应的权限:
Settings -> Apps -> Repackaging Lab -> Permissions -> toggle contacts on
我们只需要运行依次恶意程序,并添加几个联系人:
然后我们修改时间:
Settings -> Date and Time -> Set time
接下来就会发现联系人被清空,攻击成功:
Task 6:使用重打包攻击定位用户位置
Step 1. 安装 mock locations 在安卓设备上,我们可以通过GPS硬件获得位置信息. 但是我们的虚拟机没有安卓硬件,Android OS提供了模拟位置供应用使用。 我们需要做的是写一个模拟位置应用,并让Android VM使用该APP的位置而不是GPS硬件。我们已经在 Android VM 上安装了这个APP, 这个APP模拟了6个位置,随机选一个位置,默认情况下是在巴黎:
Step 2: Configuring DNS 恶意代码会发送用户的位置信息至SEED虚拟机服务器的 www.repackagingattacklab.com.我们使用 SEEDUbuntu VM 作为服务器。因此我们需要对虚拟机IP地址和URL做映射。最简单的办法是在Android VM的/system/etc/hosts 文件添加映射关系:
Step 3: Repackaging and installing the victim app. 我们重复1到5步来构建新的APK文件。唯一不同的是,我们这次使用一套新的Smali代码。一共三个代码:MaliciousCode.smali, SendData$1.smali和SendData.smali. 将他们放置在smali/com/mobiseed/repackaging路径下:
我们还需要修改 AndroidManifest.xml, 因为这次的恶意代码需要不同的权限。为了获取位置信息并访问互联网,我们需要三个权限:
随后我们重打包apk文件、生成自签名证书并重新安装,首先是重打包生成apk:
再进行自签名:
最后安装至Android VM中。
Step 4: Enabling the permission on the Android VM 因为通过应用商店安装app时,会主动询问是否开启位置信息权限,但由于我们使用adb安装,因此默认不会开启权限。我们需要手动开启:
Step 5: Triggering the attacking code. 现在我们已经准备好攻击。但是国内无法使用Google地图API以及Google提供的jquery CDN。因此我们选择使用百度提供的地图API和jQuery CDN。
首先注册成为百度地图开发者:
然后查看/var/www/RepackagingAttack下的文件,包含index.html, location.php和map.json:
Location.php利用GET请求来获取应用发送的位置信息,并写入map.json。请求格式:http://www.repackagingattacklab.com/location.php?lat=xxx&lng=xxx
以及index.html用于展示位置:
第一个js是调用的Google的jquery CDN,国内无法使用,第二个为Google地图API以及返回时执行initmap函数。同样无法使用。在initmap函数内,首先从map.json利用jquery的getJSON读取经纬度并保存。随后生成地图并将地图中心定位至经纬度位置。下方test函数用于划线,在用户经过其他位置后,其利用jquery将经纬度信息保存至数组,并会在地图上画出折线。
我们要做的工作是把jQuery CDN、GoogleMap API以及API下属的诸如Google.maps.map、Google.maps.marker、Google.maps.polyline改成百度的CDN和API,如BMapGL.Map、BMapGL.Marker和BMapGL.Polyline。
如图所示,首先我们替换API和CDN,这是一切的基础:
其中key是注册百度地图开发者后获得:
随后修改initmap函数:
首先获取坐标部分无需改动:
随后下方我们生成地图,但与Google地图不一样的是,它需要另外的函数来展示地图,以下是生成一个map对象,但不展示:
再次,由于国内使用的坐标系统是GCJ-02坐标系统,这种系统对经纬度进行加密,因此和直接获得的GPS坐标不同,尤其是百度,在GCJ-02的基础上再次加密形成BD09坐标系统,因此我们需要先转换读取的坐标:
转换完毕之后,用marker标记出用户的位置,并展示地图(centerandzoom)
最后在test函数内修改百度地图坐标的API,并时刻使其位于视野中心:
总体代码展示:
我们首先查看地图,其位置在巴黎:
运行模拟位置应用,选择一个地点,这里选上海:
然后修改系统时间,次数应该会发送get请求,让php修改json文件。
查看地图,发现位置转移到上海,且在上海和巴黎直接有一条直线:
可以发现重打包攻击成功,我们成功获取了用户的实时位置,并且获得了其移动的过程。