如何在 Android 上优雅的进行 HTTPS 明文抓包

系统 Linux
以后在Android上抓HTTPS通讯包,再也不用安装CA证书了,再也不用下载一堆python依赖环境了,再也不用重打包ssl类库了,再也不用改一堆手机参数了,一键启用,简单明了。

前言

Android系统上抓包HTTPS是不是越来越难了?高版本无法添加CA证书,抓包软件依赖太多,VPN模式、或HOOK程序时,会被APP检测到。对抗成本愈加增高。有什么万能的工具吗?

是的,eCapture for Android[1]来了。以后在Android上抓HTTPS通讯包,再也不用安装CA证书了,再也不用下载一堆python依赖环境了,再也不用重打包ssl类库了,再也不用改一堆手机参数了,一键启用,简单明了。

eCapture简介

eCapture是一款无需CA证书即可抓获HTTPS明文的软件。支持pcapng格式,支持Wireshark直接查看。基于eBPF技术,仅需root权限,即可一键抓包。eCapture中文名旁观者,即 当局者迷,旁观者清。

2022年年初上海疫情期间,笔者开始编写并开源[2],至今已经半年,GitHub上已经 4200个星星。

eCapture是基于eBPF技术实现的抓包软件,依赖系统内核是否支持eBPF。目前支持在操作系统上,支持了X86_64\ARM64的Linux kernel 4.18以上内核,支持了ARM64 Android(Linux) kernel 5.4以上版本。最新版是在2022年9月9日发布的v0.4.3版本。

演示视频

下载后,一条命令启动,干净利索。./ecapture tls -w ecapture.pcapng

先看演示视频,演示环境为Ubuntu 21.04、Android 5.4 (Pixel 6)。

模块功能

eCapture支持tls、bash、mysqld、postgres等模块的信息提取与捕获。本文仅讨论tls这个HTTPS/TLS明文捕获模块。

加密通讯明文捕获--tls模块

tls模块在加密通讯类库上,支持了openssl、gnutls、nspr/nss、boringssl等类库。但在Android上,pcapng模式只支持boringssl,文本模式则都支持。

如何使用eCapture

环境依赖

  1.  操作系统 Linux kernel 4.18以上,Android kernel 5.4以上。
  2.  支持BPF,可选支持BTF(eCapture版本不同)
  3.  root权限

版本选择

BPF CO-RE[3]特性为BTF通用的格式,用于做跨内核版本兼容。有的Android手机是没开启BTF。可以查看系统配置确认,CONFIG_DEBUG_INFO_BTF=y为开启;CONFIG_DEBUG_INFO_BTF=n为关闭;其他为不支持BPF,无法使用eCapture。

cfc4n@vm-server:~$# cat /boot/config-`uname -r` | grep CONFIG_DEBUG_INFO_BTF
CONFIG_DEBUG_INFO_BTF=y

Android系统上,config是gzip压缩的,且配置文件目录也变了。可使用zcat /proc/config.gz命令代替。

eCapture默认发行了支持CO-RE的ELF程序。Android版会发行一个5.4内核不支持BTF(即没有CO-RE)的版本。下载后,可以通过./ecapture -v确认。非CO-RE版本的version信息中包含编译时的内核版本。

# no CO-RE
eCapture version: linux_aarch64:0.4.2-20220906-fb34467:5.4.0-104-generic
# CO-RE
eCapture version: linux_aarch64:0.4.2-20220906-fb34467:[CORE]

若版本不符合自己需求,可以自行编译,步骤见文末。

全局参数介绍

全局参数重点看如下几个:

root@vm-server:/home/cfc4n/# ecapture -h
--hex[=false] print byte strings as hex encoded strings
-l, --log-file="" -l save the packets to file
-p, --pid=0 if pid is 0 then we target all pids
-u, --uid=0 if uid is 0 then we target all users
  1.  --hex 用于stdout输出场景,展示结果的十六进制,用于查看非ASCII字符,在内容加密、编码的场景特别有必要。
  2.  -l, --log-file=  保存结果的文件路径。
  3.  -p, --pid=0 捕获的目标进程,默认为0,则捕获所有进程。
  4.  -u, --uid=0 捕获的目标用户,默认为0,则捕获所有用户,对Android来说,是很需要的参数。

模块参数

root@vm-server:/home/cfc4n/project/ssldump# bin/ecapture tls -h
OPTIONS:
--curl="" curl or wget file path, use to dectet openssl.so path, default:/usr/bin/curl
--firefox="" firefox file path, default: /usr/lib/firefox/firefox.
--gnutls="" libgnutls.so file path, will automatically find it from curl default.
--gobin="" path to binary built with Go toolchain.
-h, --help[=false] help for tls
-i, --ifname="" (TC Classifier) Interface name on which the probe will be attached.
--libssl="" libssl.so file path, will automatically find it from curl default.
--nspr="" libnspr44.so file path, will automatically find it from curl default.
--port=443 port number to capture, default:443.
--pthread="" libpthread.so file path, use to hook connect to capture socket FD.will automatically find it from curl.
--wget="" wget file path, default: /usr/bin/wget.
-w, --write="" write the raw packets to file as pcapng format.

-i参数

-i参数为网卡的名字,Linux上默认为eth0,Android上默认为wlan0,你可以用这个参数自行指定。

输出模式

输出格式支持两种格式,文本跟pcapng文件。有三个参数,

   默认,全局参数,输出文本结果到stdout

   -l 全局参数,保存文本结果的文件路径

   -w 仅tls模块参数,保存pcapng结果的文件路径

类库路径

Linux上支持多种类库,不同类库的路径也不一样。

类库

参数路径

默认值

openssl/boringssl

--libssl

Linux自动查找,Android为/apex/com.android.conscrypt/lib64/libssl.so

gnutls

--gnutls

Linux自动查找,Android pcapng模式暂未支持

nspr/nss

--nspr

Linux自动查找,Android pcapng模式暂未支持

文本模式

-l 或者不加 -w 参数将启用该模式。

支持openssl、boringssl、gnutls、nspr/nss等多种TLS加密类库。支持DTLS、TLS1.0至TLS1.3等所有版本的加密协议。支持-p、-u等所有全局过滤参数。

pcapng模式

-w 参数启用该模式,并用-i选择网卡名,Linux系统默认为eth0,Android系统默认为wlan0,

仅支持openssl、boringssl两个类库的数据捕获。暂不支持TLS 1.3协议。

类库与参数支持

在Linux系统上,大部分类库与参数都是可以支持的。但在Android系统上,因为内核与ARM架构的原因,支持的参数上,有一定的差异。

不同模式的参数支持

-p、-u两个全局参数,支持文本模式,不支持pcapng模式。这是因为pcapng模式是使用eBPF TC技术实现。

模式

-p

-u

--libssl

--port

文本

pcapng

不同模式的类库以协议支持

模式

openssl(类库)

boringssl(类库)

TLS 1.0/1.1/1.2(协议)

TLS 1.3(协议)

文本

pcapng

pcapng模式暂时不支持TLS 1.3,TLS 1.3密钥捕获功能[4]已经开发完成,只是遇到一些BUG,还在解决中。笔者不是openssl的专家,对TLS 协议也不太熟。需要补充这两块的知识,解决起来成本比较高,也欢迎对这块擅长的朋友一起来解决。

与tcpdump联合使用

eCapture基于eBPF TC,实现了流量捕获,并保存到pcapng文件中。基于eBPF Uprobe实现了TLS Master Secret的捕获。并基于Wireshark的Decryption Secrets Block (DSB)[5]标准,实现了gopacket的DSB功能[6],合并网络包与密钥,保存到pcapng中。

eCapture在网络包捕获上,没有tcpdump强大,不支持丰富的参数。你可以用eCapture捕获master secrets,用tcpdump捕获网络包,然后使用wiresahrk自定义设置密钥文件,配合使用。

网络包捕获

tcpdump 的常规用法,不再赘述。

密钥捕获

同时启用ecapture ,模式可以选文本或者pcapng,都会保存TLS的master secrets密钥数据到ecapture_masterkey.log中。

网络包查看

用Wireshark打开网络包文件,设置这个master key文件,之后就可以看到TLS解密后的明文了。

配置路径:Wireshark --> Preferences --> Protocols --> TLS --> (Pre)-Master-Secret log filename

参数

指定路径

默认路径

在Android上,Google使用了boring ssl类库,也就是C++语言在libssl基础上的包装。默认情况下,会使用/apex/com.android.conscrypt/lib64/libssl.so路径。

APP的类库确认

你可以使用lsof -p {APP PID}|grep libssl来确认。若不是默认路径,则可以使用--libssl参数来指定。

高级用法

如果你需要查看的APP是自定义SSL类库,那么你可以自助修改eCapture来实现。

自定义函数名与offset

首先,需要确定HOOK函数的函数名或者符号表地址。

没有源码

如果你没有目标类库的源码,可以通过IDA等软件静态分析、动态调试,确定SSL Write的地址offset。在配置填写在user/module/probe_openssl.go文件中,对应的probe配置部分。

{
Section: "uprobe/SSL_write",
EbpfFuncName: "probe_entry_SSL_write",
AttachToFuncName: "SSL_write",
UprobeOffset: 0xFFFF00, // TODO
BinaryPath: binaryPath,
},

offset自动计算

如果你有源码,则可以自行阅读源码确定函数名或者符号表的地址。对于结构体的成员属性读取,则可以通过offsetof宏来自动计算。通过偏移量的方式,读取内容。

//  g++ -I include/ -I src/ ./src/offset.c -o off
#include <stdio.h>
#include <stddef.h>
#include <ssl/internal.h>
#include <openssl/base.h>
#include <openssl/crypto.h>
#define SSL_STRUCT_OFFSETS \
X(ssl_st, session) \
X(ssl_st, s3) \
X(ssl_session_st, secret) \
X(ssl_session_st, secret_length) \
X(bssl::SSL3_STATE, client_random) \
X(bssl::SSL_HANDSHAKE, new_session) \
X(bssl::SSL_HANDSHAKE, early_session) \
X(bssl::SSL3_STATE, hs) \
X(bssl::SSL3_STATE, established_session) \
X(bssl::SSL_HANDSHAKE, expected_client_finished_)
struct offset_test
{
/* data */
int t1;
bssl::UniquePtr<SSL_SESSION> session;
};
int main() {
printf("typedef struct ssl_offsets { // DEF \n");
#define X(struct_name, field_name) \
printf(" int " #struct_name "_" #field_name "; // DEF\n");
SSL_STRUCT_OFFSETS
#undef X
printf("} ssl_offsets; // DEF\n\n");
printf("/* %s */\nssl_offsets openssl_offset_%d = { \n",
OPENSSL_VERSION_TEXT, OPENSSL_VERSION_NUMBER);
#define X(struct_name, field_name) \
printf(" ." #struct_name "_" #field_name " = %ld,\n", \
offsetof(struct struct_name, field_name));
SSL_STRUCT_OFFSETS
#undef X
printf("};\n");
return 0;
}

参数提取

对于参数,你需要确认被HOOK函数的参数类型,以便确认读取方式,可以参考kern/openssl_kern.c内的SSL_write函数实现。

编译

ARM Linux 编译

公有云厂商大部分都提供了ARM64 CPU服务器,笔者选择了腾讯云的。在广州六区中,名字叫标准型SR1(SR1即ARM 64CPU),最低配的SR1.MEDIUM2 2核2G即满足编译环境。可以按照按量计费方式购买,随时释放,比较划算。

操作系统选择ubuntu 20.04 arm64。

ubuntu@VM-0-5-ubuntu:~$sudo apt-get update
ubuntu@VM-0-5-ubuntu:~$sudo apt-get install --yes wget git golang build-essential pkgconf libelf-dev llvm-12 clang-12 linux-tools-generic linux-tools-common
ubuntu@VM-0-5-ubuntu:~$wget https://golang.google.cn/dl/go1.18.linux-arm64.tar.gz
ubuntu@VM-0-5-ubuntu:~$sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.18.linux-arm64.tar.gz
ubuntu@VM-0-5-ubuntu:~$for tool in "clang" "llc" "llvm-strip"
do
sudo rm -f /usr/bin/$tool
sudo ln -s /usr/bin/$tool-12 /usr/bin/$tool
done
ubuntu@VM-0-5-ubuntu:~$export GOPROXY=https://goproxy.cn
ubuntu@VM-0-5-ubuntu:~$export PATH=$PATH:/usr/local/go/bin

编译方法

  1.  ANDROID=1 make 命令编译支持core版本的二进制程序。
  2.  ANDROID=1 make nocore命令编译仅支持当前内核版本的二进制程序。
责任编辑:庞桂玉 来源: 奇妙的Linux世界
相关推荐

2020-10-16 08:02:00

Android系统

2020-10-13 16:02:03

HTTPS浅析与抓包分

2020-11-17 15:19:51

AndroidGoogle 移动系统

2021-06-07 08:10:40

Https协议抓包

2020-07-22 14:30:29

JavaHTTPS加密

2014-08-08 09:39:40

httpClient

2021-01-19 05:27:44

HTTPSECDHE算法

2021-02-06 10:06:44

Https开发人员客户端

2019-03-11 15:26:26

HTTPSHTTP密钥

2019-10-25 09:35:58

HTTPSHTTP通信

2019-11-13 09:08:50

HTTPS安全加密算法

2020-09-24 06:44:54

HTTPS网站 HTTP

2019-09-15 17:35:28

Wireshark解密HTTPS

2020-11-27 10:34:01

HTTPHTTPS模型

2020-10-09 09:49:18

HTTPS网络 HTTP
点赞
收藏

51CTO技术栈公众号