Android LocalSocket 安全风险探讨

点击蓝字 关注我们

Android LocalSocket 安全风险探讨

Android LocalSocket 

安全风险探讨

Android LocalSocket 安全风险探讨



Android LocalSocket 安全风险探讨



简介

在Android系统中,进行进程间通信(IPC)时,我们经常使用AIDL。然而,由于Binder机制的限制,AIDL无法传输大量数据。为了解决这一问题,我们需要寻求其他方法来传输大数据。LocalSocket为我们提供了一个可行的解决方案。

Android LocalSocket基于UNIX-domain Socket(UDS),这是一种在Socket基础上衍生出来的IPC通信机制。因此,LocalSocket解决了同一台主机上不同进程间的通信问题。与网络通信使用的socket相比,LocalSocket不需要经过网络协议栈,不需要进行打包和拆包,也不需要进行校验计算,这使得LocalSocket的执行效率更高。

本文主要简单介绍Android LocalSocket技术原理以及其在实际应用可能存在的潜在风险,通过实践的案例展示其潜在的攻击场景。




基本概念


Socket通信模型

通过之前的简介我们知道UDS并非基于网络协议,所有通信过程均在内核中完成。使用LocalSocket进行数据传输的简单步骤如下:

1. 在服务端应用程序中创建一个ServerSocket对象,并指定要监听的端口号。

2. 在客户端应用程序中创建一个Socket对象,并连接到服务端应用程序的IP地址和端口号。

3. 通过输入流和输出流在客户端和服务端之间传输数据。

4. 关闭连接。

Android LocalSocket 的TCP通信基本流程参考下图:

Android LocalSocket 安全风险探讨

数据流参考图:

Android LocalSocket 安全风险探讨


Android LocalSocket实现类

LocalSocket

       在Unix域名空间创建一个套接字(非服务端)。是对Linux中Socket进行了封装,采用JNI方式调用,实现进程间通信。具体就是Native层Server和Framework层Client之间进行通信,或在各层次中能使用Client/Server模式实现通信。


LocalServerSocket

  创建服务器端Unix域套接字,与LocalSocket对应。


LocalSocketImpl

       Framework层Socket的实现,通过JNI调用系统socket API。


LocalSocketAddress

       Unix域socket的地址以及所处的空间。


JNI访问接口:

frameworksbasecorejniandroid_net_LocalSocketImpl.cpp

  socket_create

  socket_connect_local

  socket_bind_local

  socket_listen

  ……

通过关系类图发现,使用Android的LocalSocket建立socket通信,是基于网络socket过程一致的:

Android LocalSocket 安全风险探讨


Socket类型和命名空间

UDS有3种Socket类型,分别为SOCK_STREAM、SOCK_DGRAM和SOCK_SEQPACKET。其中SOCK_STREAM是面向数据流的类型,类似于管道。SOCK_DGRAM是面向数据包的类型,类似于消息队列。SOCK_SEQPACKET是面向连接的类型,保留了消息边界。

每个UDS都拥有一个名称。既可以使用FILESYSTEM命名空间,将名称绑定到一个文件系统路径,也可以使用与文件系统的无关的ABSTRACT命名空间。

Android LocalSocket 安全风险探讨



LocalSocket的安全性


使用说明

我们可以尝试编写一个简单的模拟程序,模拟基于Android LocalSocket的APP:

//客户端private void demoClient() throws IOException {    LocalSocket client = new LocalSocket();    client.connect(new LocalSocketAddress("@secret"));    client.getOutputStream().write(520);    int read = client.getInputStream().read();    Log.d(TAG, "response from server : " + read);    client.close();}
//服务端,不安全的代码,缺乏有效的鉴权机制private void demoServer() throws IOException { LocalServerSocket server = new LocalServerSocket("@secret"); LocalSocket client = server.accept(); int read = client.getInputStream().read(); Log.d(TAG, "request from client :" + read); client.getOutputStream().write(read + 1314); client.getOutputStream().flush(); client.close();}
// 打印// request from client :520// response from server : 5201314


安全风险探讨

常用的Binder的跨进程安全性由系统实现的鉴权机制来保证,LocalSocket作为Unix domain socket的封装,我们必须考虑它的安全性问题。

从上述代码实例中我们明显看出由于LocalSocket本身缺乏鉴权机制,任意一个应用都可以进行连接,从而截取到数据或是向接收端传递非法数据引发异常。针对这个特点,常见防御方法有两种:

1. 随机化LocalSocket的命名,例如使用当前程序的AppId和用户uin等信息计算md5作为LocalSocket的名字,使得攻击者无法通过固定或穷举名字的方法尝试建立连接。

2. 引入鉴权机制,在连接成功后发送特定的随机信息来验证对方的真实性,然后才启动真正的数据传输。

为了防止攻击者通过固定或穷举名字的方法尝试建立连接,可以使用当前程序的AppId、用户uin等信息计算md5作为LocalSocket的名字:

private static String generateRandomSocketName(String appId, String uin) {      String randomString = appId + uin;      MessageDigest md = null;      try {          md = MessageDigest.getInstance("MD5");      } catch (NoSuchAlgorithmException e) {          e.printStackTrace();      }      md.update(randomString.getBytes());      byte[] digest = md.digest();      StringBuilder sb = new StringBuilder();      for (byte b : digest) {          sb.append(String.format("%02x", b & 0xff));      }      return sb.toString();  

在连接成功后,可以发送一个随机的字符串(比如一个随机数或者一个随机的token)来验证对方的真实性。然后,只有当这个随机字符串被正确地返回时,才启动真正的数据传输:

在客户端:

private void demoClient() throws IOException {      LocalSocket client = new LocalSocket();      client.connect(new LocalSocketAddress(generateRandomSocketName(getPackageName(), uin), LocalSocketAddress.Namespace.RESERVED));      OutputStream outputStream = client.getOutputStream();      outputStream.write(520); //假设520是一个预定义的命令或标识符    outputStream.write(generateRandomString().getBytes()); // 发送随机字符串作为鉴权信息      InputStream inputStream = client.getInputStream();      int read = inputStream.read();       if (read == -1) {          Log.d(TAG, "Connection closed by server");          client.close();          return;      } else if (read != generateRandomString().hashCode()) {         Log.d(TAG, "Invalid authentication response from server");          client.close();          return;      } else {          Log.d(TAG, "Authentication successful"); // 如果鉴权成功,可以继续正常的数据传输。        // ... 数据传输代码 ...          client.close();      }  }

在服务端:

private void demoServer() throws IOException {      LocalServerSocket server = new LocalServerSocket(generateRandomSocketName(getPackageName(), uin), LocalSocketAddress.Namespace.RESERVED);      LocalSocket client = server.accept();      InputStream inputStream = client.getInputStream();      int command = inputStream.read();      if (command != 520) {  // 假设520是一个预定义的命令或标识符,表示需要进行鉴权。        Log.d(TAG, "Invalid command from client");          client.close();          return;      } else {          String randomString = generateRandomString();  // 生成一个随机字符串作为鉴权信息。        OutputStream outputStream = client.getOutputStream();          outputStream.write(randomString.getBytes());          outputStream.flush();          int response = inputStream.read();          if (response == -1) {              Log.d(TAG, "Connection closed by client");              client.close();              return;          } else if (response != randomString.hashCode()) {              Log.d(TAG, "Invalid authentication response from client");              client.close();              return;          } else {              Log.d(TAG, "Authentication successful");              // 如果鉴权成功,可以继续正常的数据传输。            // ... 数据传输代码 ...              client.close();          }      }  }




参考资料


https://zhuanlan.zhihu.com/p/620136976?utm_id=0


https://www.cnblogs.com/bastard/archive/2012/10/09/2717052.html


https://blog.csdn.net/weixin_39173183/article/details/108377681


https://blog.51cto.com/u_13657808/5658169


https://www.jianshu.com/p/dc87aceabc4c


https://jiayunhan.github.io/material/misuse_ccs16.pdf


https://developer.baidu.com/article/detail.html?id=295123


END


往期精彩合集



● 企业漏洞管理实践分享

● 从OS到BIOS SMM

● A Day in the Life of a Cyber Threat Analyst 网络威胁分析员的一天

● LLM Prompt 安全

● 在没有ROOT的手机上抓HTTPS

● 项目管理中的高效会议秘籍

● 开源安全:构建数字未来的坚固堡垒

● Deepfake人工智能时代的挑战与机遇

● DPAPI机制解析

● 移动APP隐私安全,做到这些就够了


联想GIC全球安全实验室(中国)

[email protected]


Android LocalSocket 安全风险探讨


原文始发于微信公众号(联想全球安全实验室):Android LocalSocket 安全风险探讨

版权声明:admin 发表于 2024年2月1日 下午3:38。
转载请注明:Android LocalSocket 安全风险探讨 | CTF导航

相关文章