基于Electron的应用程序安全测试基础 — 提取和分析.asar文件的案例研究

 目录:

    4.4. 案例研究

 4.4.2. 情况描述

 4.4.3. 信息收集

 4.4.3.2. 检查隐藏目录(点目录)的可能性

 4.4.3.3. 使用 DB Browser for SQLite 打开 .db 文件

 4.4.3.4. 寻找加密算法

 4.4.3.5. 找到加密算法

 4.4.3.6. 理解加密流程

 4.4.3.7. 找到“Key”存储位置

 4.4.4. 解密密钥值

 4.4.5. 其他信息

硬编码密钥(在SQLite中)和加密算法(在AesFormula.js文件中)信息泄露导致真实凭据被泄露

4.4. 案例研究

本节案例研究将讨论我们的一项测试结果,涉及基于Electron的应用程序中的客户端-服务器模型。

4.4.2. 情况描述

在首次运行相关桌面应用程序时,我们注意到该应用程序具有记住输入凭据的功能。这似乎是合理的,因为应用程序提供的默认凭据相当复杂且难以记住。

(为了维护程序所有者的隐私,在本案例研究中我们不会使用真实的图像和代码。然而,为了便于讨论,我们将尝试绘制示意图并重写代码,以大致代表我们提供的解释内容)。

图片

然而,在原生应用程序的概念中,有一个我们需要理解的原则。当我们使用应用程序提供的“记住我”功能时,本质上该应用程序会将我们的凭据存储在当前操作系统的本地环境中。尽管存储方法和形式有所不同,但为了清晰地理解流程,这一原则必须被牢牢遵守。

那么,这些数据存储在哪里呢?从技术角度来看,第三方应用程序数据的存储位置因操作系统而异。例如,macOS上的应用程序数据通常存储在用户“Library”目录中的“Application Support”文件夹中。而在Windows上,第三方应用程序数据通常存储在用户“AppData”目录中的一个隐藏文件夹中。在Linux系统中,应用程序数据通常存储在用户目录中的“.config”文件夹中。

由于此次测试是在适用于macOS的应用程序上进行的,因此接下来的说明将重点关注macOS的相关细节。

4.4.3. 信息收集

注意:为了分析该应用程序的行为,我们需要尝试先登录,并勾选“记住我的密钥”选项。

4.4.3.1. 检查 Application Support 和 Preferences 目录

在macOS环境中的初步实验中,我们检查了应用程序的目录,这些目录通常位于“Application Support”和“Preferences”中。

需要说明的是,“Application Support”目录主要用于macOS应用程序存储运行应用程序所需的数据,或者至少是与用户相关的应用程序数据。这些数据可能包括配置文件、本地数据库、缓存,或其他用于确保应用程序平稳运行的文件。例如,一个数据处理应用程序可能会在此存储文档模板,而一个游戏应用程序可能会在此存储用户的游戏进度数据。

图片

另一方面,“Preferences”目录主要用于存储用户自定义的应用程序配置文件。它包括用户偏好设置,例如显示设置、语言偏好、键盘设置等。在这种情况下,用户设置通常“存储”在.plist文件中。

图片

那么我们该如何操作呢? 在这种情况下,我们使用了一种相当传统的方法,即利用 grep 命令并结合针对我们用于登录应用程序的用户名的特定搜索。

以下是我们使用的命令:

grep -r username_of_the_apphere /Users/username/Library/Application\ Support/target_app/

以下是对该命令的简单解释:

grep:这是一个用于匹配给定输入中指定字符串模式的命令。

-r:这是一个选项,用于递归地搜索目录及其子目录中的内容。

username_of_the_apphere:这是我们要搜索的字符串,即我们在应用程序中使用的用户名。

/Users/username/Library/Application Support/target_app/:这是我们想要执行搜索的目录。在这种情况下,grep 将在目录 /Users/**username**/Library/Application\ Support/target_app/ 及其子目录中的所有文件内搜索该字符串。

图片

我们同样对首选项目录下的 “target_app” 文件进行了相同的操作。

grep -r username_of_the_apphere /Users/username/Library/Preferences/com.electron.target-app.plist

图片

那么结果如何? 简而言之,通过这次分析,我们没有发现任何与用户名相关的数据。随后,我们尝试转向另一个位置进行检查。

可能有人会问,为什么我们如此确信该用户名是以明文(未保护的)形式存储的?实际上,我们并不确定该用户名的存储状态,但尝试搜索并无妨。

4.4.3.2. 检查隐藏目录(点目录)的可能性

我们需要注意的一点是,在 macOS(以及通用的 Unix 系统)中,有一些目录对用户是隐藏的。这些目录通常以一个点(.)开头,位于 /Users/username 路径下。

在实际应用中,第三方应用程序有时会利用这些类型的目录来存储与应用程序相关的信息,而这些信息从技术角度讲并不需要用户访问。

注意:有时也会有应用程序将其数据存放在 /Users/Username/.local/share 目录中。

基于这种情况,我们决定检查 /Users/Username 路径,看看是否存在这类目录。长话短说,我们找到了一个肯定的结果,也就是目标应用(target_app)确实拥有这样一个目录。

图片

图片

当我们首次发现.data.db文件的存在时,我们就已经相当确信该文件可能包含我们正在寻找的凭据。然而,为了确认这一点,我们按照之前提到的方法使用grep进行了传统搜索。果然,结果如我们所预料,这个用户名确实存在于相关的.db文件中。

图片

4.4.3.3. 使用 DB Browser for SQLite 打开 .db 文件

通常,一个应用程序(无论是移动端还是桌面端)都会使用轻量级的数据库管理系统(DBMS)在本地计算机上进行存储。一种常见的选择是 SQLite。

在确认该文件确实是 SQLite 格式后,我们使用了一个名为 DB Browser for SQLite 的简单工具将其打开(尽管也可以使用其他工具)。

图片

长话短说,我们找到了我们想要的内容,也就是存储用户名、URL 和密钥的列。

图片

图片

然而,在进一步检查我们使用的值后,发现密钥的值与预期的值不符。从它的格式来看,我们认为这是一种AES加密格式,这是常用的数据安全算法。​​​​​​​

Value: eLy2xThk+y7Rki4J13zvGVxrnqZbrOtznvNbhOKIgWo=

再次需要指出的是,为了简化讨论,同时隐藏任何加密值和代码,我们已经用其他样本替换了它们(是的,这是从ChatGPT重制的)。

4.4.3.4. 寻找加密算法

根据我们描述的情况,我们继续测试,探索用于“保护”密钥值的潜在算法和公式。简而言之,考虑到target_app应用程序是基于Electron构建的,我们尝试提取包内容中的app.asar文件。

请注意:

要了解如何检测基于Electron的应用程序以及提取过程,可以参考前几篇文章。

成功提取后,我们可以继续搜索应用程序使用的算法和公式,以保护前面提到的密钥值。

4.4.3.5. 找到加密算法

在仔细检查提取目录中的每个文件后,我们发现了一个引起我们注意的文件,即AesFormula.js:

图片

图片

4.4.3.6. 理解加密流程

在检查AesFormula.js文件中的代码流程时,我们发现了一个负责动态生成加密密钥和初始化向量(IV)的代码段。该代码段包含两个函数:generateEncryptionKey和generateIV。

在generateEncryptionKey函数中,使用crypto.randomBytes方法生成一个随机的密钥组件,长度由KEY_LENGTH指定。随后,使用generatePBKDF2Salt函数生成一个盐值(SALT)。

图片

这些随机密钥组件和默认密钥通过按位异或(XOR)操作结合,生成一个唯一的密钥。这个生成的密钥与生成的SALT一起,通过PBKDF2算法进行密钥派生,最终得到一个派生密钥(pbkdfKey)。最后,从这个派生密钥中选取前部分(等于KEY_LENGTH字节)作为AES加密的加密密钥。

类似地,在generateIV函数中,使用crypto.randomBytes方法生成一个随机的初始化向量(IV),其长度由IV_LENGTH指定。这个IV将在AES加密过程中作为唯一的初始化向量使用。

图片

这些动态生成过程确保每次加密操作使用不同的密钥和初始化向量(IV),从而增强了加密机制的安全性。

从技术上讲,AesFormula通过为每次加密操作动态生成加密密钥和IV,提供了安全的加密功能。

为了验证我们的假设,我们尝试多次登录和登出,并观察SQLite中密钥的变化。

那么,结果如何?结果是积极的。在三次有效的登录尝试中,我们发现SQLite中的密钥值确实发生了变化。以下是相同值的三次不同加密结果:

图片

图片

图片

接下来是什么呢?当然是要找到由这段代码生成的salt、key和IV的值。至于过程,我们继续研究现有代码的流程,直到最终遇到了以下这段代码:

图片

这段代码显示,所有密钥生成过程的结果将存储在一个名为“encryptionMaterial”的部分中。

4.4.3.7. 找到“Key”存储位置

在这种情况下,我们需要查找存储在encryptionMaterial中的值。长话短说,在尝试分析SQLite数据库的内容后,我们最终发现encryptionMaterial的值硬编码存储在同一张表中,即t_user表的some_secret_name列中。

图片

图片

4.4.4. 解密密钥值

我们已经得到了密钥的加密值,并且我们也有用来加密的密钥值(iv、keyComponentBuf和salt),接下来我们将尝试解密现有的密钥值。

要执行此解密操作,最简单的方法之一是利用程序本身(在本例中,是AesFormula.js文件中可用的函数)。

以下是一个简单的代码,可以用来解密密钥值:​​​​​​​

const AesFormula = require('./AesFormula');
const encryptedValue = 'VQwSxZiICNhGjzLpcLSz1CDP11bEib26LFw+4av6VmE=';const encryptionMaterial = { iv: Buffer.from([0xb0, 0xe3, 0x88, 0x26, 0x7c, 0xe3, 0xc3, 0x91, 0x5d, 0x95, 0xec, 0x72, 0xa7, 0x67, 0xd5, 0x20]), keyComponentBuf: Buffer.from([0xb8, 0x02, 0x63, 0x02, 0xe6, 0xcf, 0x1e, 0x61, 0xa9, 0x56, 0x1f, 0x49, 0xb1, 0x74, 0x77, 0x23, 0xb0, 0x59, 0xca, 0xa3, 0xa2, 0x8b, 0x34, 0x71, 0x23, 0x6c, 0xa5, 0x4d, 0x34, 0x85, 0x78, 0xeb]), pbkdf2SaltBuf: Buffer.from([0x4e, 0xc4, 0x6f, 0x21, 0x4b, 0x55, 0xc7, 0x58, 0x38, 0x9d, 0x6e, 0x31, 0xc0, 0x37, 0xaa, 0x68])};
const decryptValue = async () => { try { const decryptedResult = await AesFormula.decryptWithAES(encryptedValue, encryptionMaterial); console.log('Decrypted value:', decryptedResult); } catch (error) { console.error('Error while decrypting:', error); }};
decryptValue();

我们需要做的就是将来自encryptionMaterial的值(iv、keyComponentBuf和salt)输入到其中。将这段代码保存(例如命名为:decrypt.js)。然后,将AesFormula.js文件放在与此代码相同的目录中。

要执行这段代码,我们需要借助node.js。以下是运行程序后的最终结果:

图片

总之,PoC(概念验证)过程包括:

1.从data.db文件中的t_user表的key列获取key值。

2.从data.db文件中的t_user表的some_secret_name列获取encryptionMaterial值。

3.将key值复制到我们之前创建的decrypt.js代码中。

4.将encryptionMaterial值(逐个为iv、keyComponentBuf和salt)复制到我们创建的decrypt.js代码中。

5.将AesFormula.js文件放置在与decrypt.js文件相同的目录中。

6.使用node.js运行decrypt.js代码,命令为**node decrypt.js**

4.4.5. 其他信息

4.4.5.1. 观点

从这个案例中,我们也可以认识到,应用程序实施的加密相当稳健,例如使用动态密钥,这无疑使得攻击者猜测变得困难。然而,关键问题最终集中在密钥公式和密钥本身的存储方式。

这个问题的执行可能引发一个问题:“获得本地访问权限的攻击者是否能够直接通过启用‘记住我的密钥’功能的target_app登录?”

本质上,这是一个有效的问题。然而,我们需要更深入地思考,因为攻击者在本地目标上的存在通常是有时间限制的。攻击者要想探索target_app中的每一条数据,无疑会受到限制,并且对于攻击者来说并不理想。

因此,通过利用本报告中描述的问题,攻击者将不再受时间限制,从用户的target_app中窃取数据。因为攻击者可以快速执行窃取操作,通过访问存储在SQLite数据库中的硬编码用户名、URL、key和encryptionMaterial。随后,攻击者可以从本地目标之外的各种位置进行探索。

尽管关于某些程序中这个问题的有效性的争论仍然存在,但在红队演习中无疑是有益的。

4.4.5.2. SafeStorage模块

需要注意的是,Electron框架提供了一个名为SafeStorage[1]的模块,用于保护存储在磁盘上的数据,以免被其他应用程序或具有完全磁盘访问权限的用户访问。从技术上讲,Electron中的safeStorage利用操作系统本地的安全存储API,以加密形式存储数据(因此,这可能是一个不错的替代方案)。

References

[1] SafeStorage: https://www.electronjs.org/docs/latest/api/safe-storage

申明:本账号所分享内容仅用于网络安全技术讨论,切勿用于违法途径,所有渗透都需获取授权,违者后果自行承担,与本号及作者无关   

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/71213.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Delphi】如何解决使用webView2时主界面置顶,而导致网页选择文件对话框被覆盖问题

一、问题描述&#xff1a; 在Delphi 中使用WebView2控件&#xff0c;如果预先把主界面置顶&#xff08;Self.FormStyle : fsStayOnTop;&#xff09;&#xff0c;此时&#xff0c;如果在Web页面中有使用&#xff08;<input type"file" id"fileInput" acc…

ASP.NET Core 3.1 修改个别API返回JSON序列化格式

ASP.NET Core 3.0及之后的版本中&#xff0c;默认的JSON格式化器是基于System.Text.Json的。返回json格式采用camelCase&#xff08;第一个单词首字母小写&#xff0c;后面单词首字母大写&#xff09;。如果想改为PascalCase&#xff0c;可以全局设置PropertyNamingPolicy nul…

有关Java中的集合(2):Map<T>(底层源码分析)

学习目标 核心掌握Map集合 1.Map<K,V> ● 实现了Map接口的集合对象的集合元素&#xff1a; 成对的值 key-value 键值对 ● key对象是不能重复的. value可以重复。 ● 核心: 根据key获得value。 1.1 层级 public interface Map<K, V> {}1.2 常用方法 1.3 使用方法…

windows电脑上安装llama-factory实现大模型微调

一、安装环境准备 这是官方给的llama-factory安装教程&#xff0c;安装 - LLaMA Factory&#xff0c;上面介绍了linux系统上以及windows系统上如何正确安装。大家依照安装步骤基本能够完成安装&#xff0c;但是可能由于缺少经验或者相关的知识导致启动webUi界面运行相应内容时…

每日一题——接雨水

接雨水问题详解 问题描述 给定一个非负整数数组 height&#xff0c;表示每个宽度为 1 的柱子的高度图。计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#…

Ubuntu 创建新用户及设置权限

1、新建用户 sudo adduser username 其中username是你要创建的用户的用户名&#xff0c;然后设置密码和相关信息就可以了 2、给新用户sudo权限 新创建的用户没有root权限&#xff0c;我们执行以下命令给用户sudo权限 sudo usermod -a -G adm username sudo usermod -a -G s…

商米科技前端工程师(base上海)内推

1.根据原型或高保真设计&#xff0c;开发web、H5、小程序等类型的前端应用&#xff1b; 2.在指导下&#xff0c;高质量完成功能模块的开发&#xff0c;并负责各功能模块接口设计工作&#xff1b; 3.负责产品及相关支撑系统的开发及维护工作&#xff0c;不断的优化升级&#x…

HTTP四次挥手是什么?

四次挥手&#xff0c;这是TCP协议用来关闭连接的过程。四次挥手是确保两个主机之间能够安全、可靠地关闭连接的重要机制。我会用简单易懂的方式来讲解&#xff0c;帮助你理解它的原理和过程。 1. 什么是四次挥手&#xff1f; 定义 四次挥手是TCP协议用来关闭连接的过程。它通…

使用 REINFORCE 算法强化梯度策略

一、整体概述 此代码利用 REINFORCE 算法&#xff08;一种基于策略梯度的强化学习算法&#xff09;来解决 OpenAI Gym 中的 CartPole-v1 环境问题。CartPole-v1 环境的任务是控制一个小车&#xff0c;使连接在小车上的杆子保持平衡。代码通过构建一个神经网络作为策略网络&…

使用Python自动生成图文并茂的网页分析报告

在数据分析中&#xff0c;不管是市场研究还是科学分析&#xff0c;经常需要使用Python进行数据分析并生成图表报告。一般使用Python生成和展示图表时都是使用matplotlib 库生成静态图片文件&#xff0c;这种方式不便之处是不方便跟动态文字段落结合在一起&#xff0c;也不方便分…

【iOS】小蓝书学习(七)

小蓝书学习&#xff08;七&#xff09; 前言第47条&#xff1a;熟悉系统框架第48条&#xff1a;多用枚举块&#xff0c;少用for循环第50条&#xff1a;构建缓存使选用NSCache而非NSDictionary第51条&#xff1a;精简initialize与load的实现代码第52条&#xff1a;别忘了NSTimer…

C语言复习4:有关数组的基础常见算法

# 数组的常见算法 - 查找算法 1. 基本查找/顺序查找 2. 二分查找/折半查找 3. 插值查找 4. 分块查找 5. 哈希查找 6. 树表查找 7. 斐波那契查找 - 排序算法&#xff08;顾名思义&#xff0c;就是把没有顺序的…

Ollama 的庐山真面目

Ollama 运行方式分析 本地推理条件&#xff08;GPU/CPU/RAM&#xff09;&#xff1a;Ollama 支持在本地电脑进行大模型推理&#xff0c;但需要满足一定的硬件条件。一般来说&#xff0c;GPU 有助于加速推理&#xff0c;特别是显存较大的 GPU 能够加载更大的模型&#xff1b;如果…

SyntaxError: positional argument follows keyword argument

命令行里面日常练手爬虫不注意遇到的问题&#xff0c;报错说参数位置不正确 修改代码后&#xff0c;运行如下图&#xff1a; 结果&#xff1a; 希望各位也能顺利解决问题&#xff0c;祝你好运&#xff01;

drawDB:一款免费数据库设计工具

drawDB 是一款基于 Web 的免费数据库设计工具&#xff0c;通过拖拽、复制、粘贴等方式进行数据库建模设计&#xff0c;同时可以生成相应的 SQL 脚本。 功能特性 drawDB 目前可以支持 MySQL、MariaDB、PostgreSQL、SQL Server 以及 SQLite 数据库&#xff0c;核心功能包括&…

使用SPI总线与外部传感器通信,使用ECU抽象

MCAL SPI驱动示例 首先,MCAL层提供了针对特定微控制器的SPI驱动实现。以下是一个简化的MCAL SPI驱动API的例子: // MCAL SPI driver interface void Spi_Init(const Spi_ConfigType* Config); Std_ReturnType Spi_Transmit(uint8 *DataBufferPtr, uint8 Length); Std_Retur…

FPGA开发,使用Deepseek V3还是R1(9):FPGA的全流程(详细版)

以下都是Deepseek生成的答案 FPGA开发&#xff0c;使用Deepseek V3还是R1&#xff08;1&#xff09;&#xff1a;应用场景 FPGA开发&#xff0c;使用Deepseek V3还是R1&#xff08;2&#xff09;&#xff1a;V3和R1的区别 FPGA开发&#xff0c;使用Deepseek V3还是R1&#x…

Conda 环境搭建实战:从基础到进阶

在当今复杂多变的软件开发与数据科学领域&#xff0c;拥有一个稳定、可复现且易于管理的开发环境是项目成功的基石。Conda 作为一款强大的跨平台环境管理与包管理工具&#xff0c;为开发者提供了便捷高效的环境搭建与依赖管理解决方案。本文将深入探讨 Conda 环境搭建的实战技巧…

Hive-05之查询 分组、排序、case when、 什么情况下Hive可以避免进行MapReduce

一、目标 掌握hive中select查询语句中的基本语法掌握hive中select查询语句的分组掌握hive中select查询语句中的join掌握hive中select查询语句中的排序 二、要点 1. 基本查询 注意 SQL 语言大小写不敏感SQL 可以写在一行或者多行关键字不能被缩写也不能分行各子句一般要分行…

leetcode_34 在排序数组中查找元素的第一个和最后一个位置

1. 题意 给定一个非递减的数组&#xff0c;找出给定元素的开始位置和 结束位置。 2. 题解 题目要求复杂度为 log ⁡ ( n ) \log (n) log(n), 因此不能用双指针了。 这个题目练习二分挺好的。 2.1 双指针 还是把双指针的写下来吧。 class Solution { public:vector<i…