白乐天

道阻且长,行则将至。

抓包

HTTP抓包

对于HTTP的包是可以通过抓包工具+配置手机代理直接抓取的。

demo测试

访问"http://www.httpbin.org/get"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class OkhttpTest {
public static void http_get(){
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
.url("http://www.httpbin.org/get")
.build();

new Thread(new Runnable() {
@Override
public void run() {
try {
Response response = client.newCall(request).execute();
if(response.isSuccessful()){
String responseBody = response.body().string();
Log.d("Response:",responseBody);
}else {
Log.d("Request failed",String.valueOf(response.code()));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
}
}

通过点击按钮进行访问

点击按钮,输出日志,如下,访问成功

通过Charles配置代理进行抓包,如下,成功抓取数据

HTTPS抓包

HTTPS是有系统证书校验的,需要安装证书之后通过抓包工具+配置手机代理来进行抓包。
在安卓上,Android8.0之后,浏览器默认信任用户目录下的证书,而APP默认不再信任用户目录下的证书了,所以需要手动把用户目录下的证书移动到系统目录下(通过面具移动或者手动移动)。

demo测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void https_get(){
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
.url("https://www.httpbin.org/get")
.build();

new Thread(new Runnable() {
@Override
public void run() {
try {
Response response = client.newCall(request).execute();
if(response.isSuccessful()){
String responseBody = response.body().string();
Log.d("Response:",responseBody);
}else {
Log.d("Request failed",String.valueOf(response.code()));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
}

通过点击按钮进行访问

点击按钮,输出日志,如下,访问成功

通过Charles配置证书和代理进行抓包,如下,成功抓取数据

检测代理

检测是否设置代理

APP在发起网络请求前会检测系统是否设置了代理,如果发现有代理,就不发起请求。

demo测试

1
2
3
4
5
6
7
public static boolean isProxySet(){
String proxyHost = System.getProperty("http.proxyHost");
String proxyPort = System.getProperty("http.proxyPort");
Log.d("Proxy","proxyHost:"+proxyHost);
Log.d("Proxy","proxyPort:"+proxyPort);
return proxyHost!=null || proxyPort!=null;
}

通过点击按钮进行访问

点击按钮,输出日志

未设置代理时如下

设置代理时如下

禁用代理

APP 用了NO_PROXY参数发起网络请求,指明不使用代理服务器,即使系统设置了代理,也会被直接绕过,APP依然能正常获取网络数据,但抓包工具无法抓到该APP的数据包。

demo测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public static void no_proxy(){
OkHttpClient client = new OkHttpClient.Builder()
.proxy(Proxy.NO_PROXY)
.build();

Request request = new Request.Builder()
.url("https://www.httpbin.org/get")

.build();

new Thread(new Runnable() {
@Override
public void run() {
try {
Response response = client.newCall(request).execute();
if(response.isSuccessful()){
String responseBody = response.body().string();
Log.d("Response:",responseBody);
}else {
Log.d("Request failed",String.valueOf(response.code()));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
}

配置一下抓包代理,然后点击按钮进行访问

日志里面可以正常输出内容,但是抓包看不到传输数据

这种情况下可以在Charles里配置SOCKS,然后关闭手机端的系统代理,使用第三方代理转发工具如SocksDroid来进行转发流量(通过VPN劫持流量)

就可以抓取数据了

VPN检测

介绍

VPN检测是指应用程序或系统检查用户是否正在使用虚拟专用网络(Virtual Private Network, VPN)的一种技术。当用户使用VPN时,他们的网络流量会被加密并通过一个远程服务器路由,这可以隐藏用户的实际IP地址和位置信息,同时保护数据的安全性和隐私。

原理

当客户端运行VPN虚拟隧道协议时,会在当前节点创建基于 eth 之上的 tun0 接口或 ppp0 接口。这些接口是用于建立虚拟网络连接的特殊网络接口。

demo测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public static boolean vpn_check() {
try {
// 获取所有网络接口的枚举对象
Enumeration<NetworkInterface> networkInterfaces =
NetworkInterface.getNetworkInterfaces();

// 如果没有可用的网络接口,则返回 false
if (networkInterfaces == null) {
return false;
}

// 将枚举类型转换为列表并通过迭代器遍历
Iterator it = Collections.list(networkInterfaces).iterator();
while (it.hasNext()) {
// 获取当前网络接口
NetworkInterface networkInterface = (NetworkInterface) it.next();

// 检查网络接口是否处于活动状态(isUp())且其绑定的接口地址不为空
if (networkInterface.isUp() &&
!networkInterface.getInterfaceAddresses().isEmpty()) {
// 打印网络接口名称用于调试
Log.d("GaGa===>",
"端口名称: " + networkInterface.getName());

// 检查网络接口名称是否为 VPN 特有的名称
// 常见的 VPN 接口名称包括 tun0, ppp0, p2p0, 和 ccmni0
if (Intrinsics.areEqual(networkInterface.getName(), "tun0")
|| Intrinsics.areEqual(networkInterface.getName(), "ppp0") ||
Intrinsics.areEqual(networkInterface.getName(), "p2p0") ||
Intrinsics.areEqual(networkInterface.getName(), "ccmni0")) {
// 如果找到匹配的接口名称,说明 VPN 处于活动状态,返回 true
return true;
}
}
}
// 如果遍历完所有网络接口,没有检测到 VPN,返回 false
return false;
} catch (Throwable th) {
// 捕获并打印任何可能的异常
th.printStackTrace();
return false;
}
}

通过点击按钮进行访问

点击按钮输出如下日志,说明检测到了vpn

通过安装证书实现抓包的原理

它的原理是基于HTTPS中间人攻击和证书信任链机制的。

HTTPS 使用 SSL/TLS 协议 对通信进行加密,确保数据在传输过程中不被窃听或篡改。其核心步骤如下:

  1. 证书验证:客户端(如安卓应用)与服务器建立连接时,服务器会发送其 数字证书,证书包含公钥和颁发机构(CA)的签名。
  2. 信任链校验:客户端检查证书是否由受信任的根证书颁发机构(CA)签发,并验证证书的有效性(如域名匹配、未过期等)。
  3. 密钥协商:验证通过后,客户端使用服务器的公钥加密一个随机生成的对称密钥(Session Key),双方后续使用该密钥加密通信数据。

中间人攻击的漏洞
若攻击者(如抓包工具)能伪造服务器的证书,并让客户端信任攻击者的根证书,即可拦截和解密 HTTPS 流量。

  • 抓包工具(如 Charles、Fiddler)会生成一个 伪造的服务器证书,并使用自己的根证书(CA)签名。
  • 若客户端信任攻击者的根证书,则会接受伪造的证书,攻击者即可解密流量。

中间人攻击的关键:伪造信任链

  • 抓包工具的角色
    抓包工具(如 Charles、Fiddler)会生成一个 ​自签名的根证书(Self-Signed Root CA)​,并手动将其安装到客户端(安卓系统)的信任存储中。
    此时,客户端会将抓包工具的根证书视为合法根 CA。
  • 伪造服务器证书
    当客户端发起 HTTPS 请求时,抓包工具会拦截请求,并动态生成一个 ​伪造的服务器证书,该证书由抓包工具的根证书签名。
    由于客户端信任抓包工具的根证书,因此会接受伪造的服务器证书。

单向证书校验

单向证书校验是指在客户端与服务器之间的通信中,只有服务器需要提供证书,客户端通过验证服务器的证书来确认服务器的身份。
原理

  • 客户端发起连接请求(如通过HTTPS)。
  • 服务器将其数字证书发送给客户端,数字证书中包含了服务器的公钥和其他信息(如证书的有效期、签发者等)。
  • 客户端收到证书后,通过信任的证书颁发机构(CA)的公钥来验证证书的有效性。如果证书有效,客户端就信任这个服务器,继续进行后续的加密通信。
  • 客户端不需要提供任何证书或身份验证。

双向证书校验

双向证书校验则要求客户端和服务器都提供证书,并且相互验证对方的身份。这样不仅服务器要验证客户端的身份,客户端也要验证服务器的身份。
原理

  • 客户端发起连接请求。
  • 服务器发送其数字证书给客户端,客户端用CA公钥验证服务器证书的合法性。
  • 服务器要求客户端也提供数字证书。客户端向服务器提供自己的证书,服务器同样使用CA公钥验证客户端证书的合法性。
  • 双方都确认对方的身份后,开始建立加密通道进行安全通信。

SSL pinning

SSL Pinning(SSL证书绑定)是为了增强应用程序对中间人攻击(MITM攻击)的防御的一种技术。它将特定的证书或公钥绑定到客户端应用程序中,使得客户端在建立SSL连接时,仅信任与该证书或公钥匹配的服务器证书,从而确保通信的安全性。

其核心原理是预先将服务器证书的特定信息嵌入客户端应用,并在建立连接时验证服务器证书是否与预设信息一致。

应用开发阶段,将服务器证书的 公钥哈希(Public Key Hash)、证书指纹(Certificate Fingerprint) 或完整证书 嵌入客户端代码或配置文件。

客户端与服务器建立 TLS 连接后,获取服务器证书链。

检查服务器证书的公钥哈希或指纹是否与预设值匹配。

Certificate Pinning

证书绑定是指将服务器的证书(通常是公钥)内置到客户端应用中。客户端在建立SSL连接时,会验证服务器的证书与客户端预定义的证书是否匹配。如果不匹配,连接会被拒绝,防止攻击者使用伪造的证书进行中间人攻击。

Public Key Pinning

公钥绑定是SSL Pinning的一种形式,客户端不直接绑定证书,而是绑定服务器证书中的公钥。这种方式可以避免证书过期或更新时造成的连接问题,因为即便证书发生变化,只要公钥保持不变,客户端仍然可以信任新的证书。

绕过方式

使用frida进行hook

frida官方提供的客户端校验绕过脚本如下
https://codeshare.frida.re/@akabe1/frida-multiple-unpinning/

JustTrustMe

利用面具刷入LSPosed框架,然后安装JustTrustMe插件。
在LSPosed的模块里打开JustTrustMe,在要选择绕过的App后面方框勾选上即可。

证书信息