运用三种途径对WhatsApp网络电话进行取证分析
运⽤三种途径对WhatsApp⽹络电话进⾏取证分析
随笔案例知识声⾳其他
为什么要研究WhatsApp?从全球⾓度上讲,这可是⽐⽤户还要⼤的⼀个社交软件,必要性⽆须多⾔。本⽂由国外取证达⼈进⾏详细分析,本号完成翻译和实证。
⽂中涉及代码均来⾃GitHub。字数:6556字,⽂章较长,可以视为教程。
打赏可获得中⽂译doc版(5元+留⾔邮箱)。
本⽂中,我们借助⼀部越狱的iOS设备和⼀套取证⼯具软件,对WhatsApp⽹络电话的部分协议进⾏分析。这么做有什么意义呢?我们通过官⽅声明了解到,WhatsApp的数据是加密的,但它的应⽤协议是未公开的(跟⼀个德性)。因此,针对该应⽤的电⼦数据取证操作,⼀般必须基于“猜测”和某种程度的实证。
我们的研究基于三个步骤:
1.⽹络流量分析
2.⼆进制⽂件的分析
3.运⾏时的⾏为分析
我们使⽤的⼯具软件:
思想汇报2011年9月⼆进制⽂件的解密:bfdecrypt
反汇编⼆进制⽂件:Hopper反汇编程序和radare2
鲅鱼的家常做法观察⽹络流量:Wireshark
分析运⾏时⾏为:Frida
⾄于如何对实验⽤的ios设备进⾏越狱?——本⽂就不赘述了。
⼀、⽹络流量分析
我们使⽤Wireshark抓取和记录WhatsApp⼀个运⾏区间。为了记录iOS设备的⽹络流量,我创建了远程虚拟⽹络接⼝。该操作的shell命令如下,其中<device UUID>必须替换为被检查的iOS的UUID:
rvictl-s<device UUID>
Wireshark检测到STUN的使⽤情况,STUN是⼀种信令协议,使⽤该协议⽤以在客户端之间建⽴点对点连接,换⼀个词可能更好理解:NAT穿透。
▲图Wireshark抓取的WhatsApp数据包
WhatsApp客户端与服务器之间通过TCP包进⾏数据交换。WhatsApp的主叫与被叫⽅之间,使⽤的是UDP包。
数百个UDP包在⼀分钟内被发送。⾃从WhatsApp⽩⽪书提到了安全实时协议(SRTP)的使⽤,这是有道理的,这些UDP数据包是包含SRTP协议内容的。SRTP协议提供加密、消息⾝份验证和完整性,同时可以防⽌对实时协议
UDP数据包是包含SRTP协议内容的。SRTP协议提供加密、消息⾝份验证和完整性,同时可以防⽌对实时协议(RTP)数据包的攻击。下图显⽰了⼀个⼗六进制表⽰的SRTP包,它是由呼叫者发送给被呼叫者。它包含来⾃RTP的头字段,RTP进⽽建⽴SRTP。
▲图SRTP数据包
前四个字节(红⾊)包含七个RTP协议头字段,其⼆进制形式如下:
▲图RTP数据包头字段(RFC3550)
前两位包含RTP版本(V),在本例中版本是2。第三位是padding字段(P),表⽰⼩包裹。第四位,扩展字段(X),表⽰后⾯没有其他头固定的RTP报头。在第五位到第⼋位是分信源计数,图⽰中显⽰没有分信源(CSRC)标识符跟随固定头。CSRCs是⼀个列表,表⽰哪些源SRTP包的有效内容起作⽤。位置9的标记位(M)设置为零。它可以⽤来标记数据包的框架边界。接下来的6位包含数据包类型,
在本例中为⼗进制值60。本例中的数据包类型并不是RTP或SRTP标准。它可能是WhatsApp选择的⾃定义值。最后17位包含给定数据包的顺序号(SEQ),按照RTP标准,顺序号的推荐初始值是随机的。但WhatsApp并没有使⽤这个推荐值,从Wireshark的⽹络流量中可以看出,这个顺序好是从零开始增加的。接下来的四个字节(蓝⾊)表⽰数据包的时间戳。后⾯的4个字节(绿⾊)
表⽰同步源(SSRC),它是⽤来区分并⾏运⾏的会话。其余字节表⽰有效负,这⾥可能包含呼叫的⾳频数据(注:通话内容哟)。
我们知道WhatsApp应⽤SRTP协议来保护通话,这⼀点,我们通过WhatsApp客户端之间交换的UDP数据包的结构,得到了印证。Wireshark抓取的⽹络流量显⽰,TCP数据包也从iOS客户端发送到WhatsApp服务器,这些数据包中的信息,使⽤噪声管道协议加密,后⾯的分析还会看到这个情况。
⼆、⼆进制分析
立川明日香
iOS的 WhatsApp客户端包含两个主要的⼆进制⽂件:WhatsApp应⽤程序、WhatsApp核⼼框架。这⼀部分,我将使⽤Hopper反汇编程序和radare2开展分析这些⼆进制⽂件。iOS应⽤程序的⼆进制⽂件在从应⽤程序商店下载时加密。在分析iOS的WhatsApp客户端时,避开了苹果的安全措施。除此之外,WhatsApp的⼆进制⽂件还使⽤bfdeccrypt⼯具进⾏了解密。
在这⾥,我将演⽰如何收集有关tsapp使⽤的底层协议、算法和开源库的信息。开源库特别有趣,因为它们很容易被分析。
Libsignal-protocol-c
WhatsApp使⽤libsrtp库来实现安全实时协议。库函数的标识在⼆进制⽂件中去掉了。尽管如此,⼆进制⽂件依然包含引⽤libsrtp的字符串:拜年的祝福语
Libsrtp
WhatsApp使⽤libsrtp库来实现安全实时协议。库函数的标识在⼆进制⽂件中去掉了。尽管如此,⼆进制⽂件依然包含引⽤libsrtp的字符串:
除此之外,⼆进制数据还包含字符串常量,这些常量也可以在源代码中到
libsrtp的代码,如“cloning stream(SSRC:0x%08x)”:
什么叫白皮书
PJSIP
WhatsApp使⽤PJSIP实现多媒体通信、信令和⾳频和视频数据的编码。除此之外,PJSIP还实现了STUN(就是那个所谓的NAT穿透),这在Wireshark中也能够记录和检测到。在该库的调试信息⼆进制数据中,可以看到其中的字符串常量:
mbed TLS
WhatsApp使⽤mbed TLS协议⽤来实现TLS协议。从⼆进制⽂件中的函数名,可以发现该库的标识:
XMPP
WhatsApp使⽤可扩展消息状态协议(XMPP),在客户端之间进⾏异步信息交换,数据交换的格式是XML。我们可以从⼆进制数据中到跟此协议有关的很多“类名”(class):
噪声协议框架(Noise Protocol Framework)
根据WhatsApp⽩⽪书披露的资料,噪声协议框架⽤于保护客户端和服务器之间的通信。噪声协议框架是为了从⼀组⼩的构造块中,构造易于使⽤的密码协议⽽开发的。更准确地说,WhatsApp应⽤了噪⾳管道协议,它派⽣⾃噪声协议框架。下⾯⼏个静态的字符串常量,可以在WhatsApp⼆进制⽂件中到:
“Noise_XX_25519_AESGCM_SHA256”,
“Noise_IK_25519_AESGCM_SHA256”,
“Noise_XXfallback_25519_AESGCM_SHA256”.
这些字符串常量描述了WhatsApp客户端实现的握⼿模式。第⼀个字符串在⼀个名为wanoisevelhandshake的类中被引⽤。第⼆个字符串在⼀个名为WANoiseResumeHandshake的类中被引⽤。最后⼀个字符串在名为WANoiseFallbackHandshake的类中引⽤。这些协议的详细⼯作⽅式超出了本⽂范围,不再赘述。
三、运⾏时分析
本部分将借助于Firda,对IOS环境下WhatsApp客户端的⾏为进⾏分析。Frida是⼀个命令⾏⼯具,它通过创建钩⼦脚本(hook),来观察或操作被调⽤函数的参数和返回值。
密钥传输
这⼀部分概述了WhatsApp VoIP协议的密钥传输是如何⼯作的。根据WhatsApp⽩⽪书披露的资料,对于加密VoIP呼叫,“发起者⽣成随机的32字节SRTP主密钥”。然后呼叫者“发送给收件⼈的加密消息,
该消息向传⼊呼叫发送信号,并包含SRTP主密钥”。这些信息⽤于重建密钥传输,即:将主叫秘密传输给被叫⽅。
作为起点,我跟踪了包含关键词“secret”的函数:
当WhatsApp呼叫时,WAHKDF类的⼀个函数(deriveSecretsFromInputKeyMaterial)被调⽤:
在这⾥,输⼊值(0x121e08a20 和 0x121e07840),是指向Objective-C对象的指针。Frida允许从Java中的指针创建代理 Objective-C对象。这个
deriveSecretsFromInputKeyMaterial的函数钩⼦⽤于打印对象的调试说明:
下图是这段脚本的输出:
第⼀个和第三个参数似乎是包含静态字节的NSData对象缓冲区。第⼀个参数的长度是32字节,就像WhatsApp⽩⽪书中描述的主密钥⼀样。第三个参数是⼀个ASCII字符串,表⽰打电话的⼈的JID。我们将在下⾯看到第⼀个参数实际上是主密钥。
主密钥的加密
根据WhatsApp⽩⽪书,主密钥对于保护通话会话⾄关重要。这就是为什么它必须安全地传输给被叫⽅。为了观察如何处理主密钥,我跟踪了包含与加密相关的关键字的函数调⽤:
当WhatsApp启动时,调⽤libsignal-protocol-c库的函数signal_encrypt。下⾯显⽰信号加密函数头:
Signal_encrypt的Frida钩⼦脚本会读取明⽂参数
▲图Signal_encrypt的明⽂参数值
前四个字节⽤于使⽤协议缓冲区序列化主密钥。以下字节(蓝⾊部分)表⽰主密钥。最后13个字节表⽰加密填充。我发现明⽂在CBC模式下是⽤AES-256加密的。加密密钥由信号协议中的双棘轮算法导出。本⽂不研究libsignal-protocol-c 和Signal协议的内部⼯作原理。信号加密的输出由以下字节表⽰:
▲图Signal_encrypt输出值
因为验证标记被附加到消息中,所以输出值携带更多字节,该消息由HMAC-SHA256计算。
这⼀部分揭⽰了WhatsApp⽹络电话协议的第⼀部分。主密钥在CBC模式下⽤256位AES密钥序列化、填充和加密。加密密钥、IV和⾝份验证密钥由实现信号协议的libsignal-protocol-c库得出。
准备主密钥
在下⾯,我将演⽰如何处理加密的主密钥。我跟踪了包含关键字“signal”的函数:
Frida命令显⽰,函数textsecure_signal_message_pack处理加密的主密钥。该函数创建包含加密主密钥和与信号协议相关的参数的信号消息:
▲图textsecure__signal_message__pack 输出值
灰⾊字节⽤于序列化信号消息。蓝⾊字节表⽰发送⽅棘轮键。红⾊字节表⽰上⼀个消息计数器。后⾯是消息计数器(橙⾊)。最后,加密的主密钥由以下字节(绿⾊)的信号消息表⽰。
当跟踪与XMPP相关的Objective-C函数时,我们可以看到调⽤了⼀个名为writenoiseframetosocketweetwithpayload的类的XMPPStream⽅法。此⽅法通过TCP向WhatsApp服务器发送XMPP消息,同时,消息经由管道噪声协议加密。下⾯是参数的内容:
▲图XMPPStream.writeNoiseFrameToSocketWithPayload函数的有效值
这是⼀个⼆进制XMPP消息,包含上⾯创建的信号消息。为了分解消息,我跟踪了⼀个名为XMPPBinaryCoder的类。这个类有⼀个名为serialize的函数,该函数创建XMPP段的⼆进制表⽰。当打印出它的参数时,可以看到添加到XMPP 消息中的各种键值对:
我可以在鲍勃的设备上伪造⼀个来⾃爱丽丝的未接电话的指⽰,即使这个电话是由马洛⾥发起的。这可以通过使⽤Alice 的JID覆盖callcreator和from参数来实现。不过,消息中显⽰了Mallory的名称(“with Mallory”)。当鲍勃对通知做出响应时,他开始与爱丽丝⽽不是马洛⾥通话。我认为需要进⼀步的研究来分析对初始调⽤消息的操作。
伪造未接来电通知
这⼀部分揭⽰了WhatsApp如何处理加密的主密钥。加密的主密钥被打包成⼀个信号消息,该消息被添加到⼆进制XMPP段中。XMPP段还包含调⽤ID以及调⽤⽅和被调⽤⽅的JID。
将主密钥传送给被叫⽅
根据WhatsApp⽩⽪书披露,“客户端使⽤噪声协议框架中的Curve25519、AESGCM和SHA256的噪声管道进⾏长时间的交互连接”。当跟踪包含与噪⾳协议框架有关关键字的函数时,我可以看到⼀个名为ANoiseStreamCipher的类,他被⽤于加密发送到WhatsApp服务器的流量。此类有⼀个名为encryptPlaintext的函数。发起调⽤后的明⽂值是上⾯的XMPP消息。消息再次被mbed TLS库的⼀个名为
mbedtls_gcm_crypt_and_tag加密。此外,以256位的密钥⼤⼩调⽤mbedtls_gcm_setkey,这意味着,
他可能使⽤了AES-256-GCM加密。加密密钥是由噪声管道协议得出的,本⽂对此没有进⼀步研究。加密的明⽂通过TCP发送到WhatsApp服务器,Wireshark抓取的⽹络流量显⽰了这⼀点。然后,服务器将消息转发给被叫⽅以启动调⽤。
▲图加密呼叫初始化消息
密钥派⽣
创维42寸液晶电视价格这⼀部分解释了密钥派⽣函数(KDF)如何创建⽤于加密WhatsApp调⽤的关键资料。在Frida的帮助下,通过跟踪⼀个名为WAHKDF的类和libcommonCrypto库来搜索这⼀部分的结果。WAHKDF类的⽤途是,创建(派⽣)初始化SRTP 流所需要的密钥、盐和随机数(nonce)。它的函数(deriveSecretsFromInputKeyMaterial)在WhatsApp呼叫发起前将被调⽤⼗次:
该⽅法基于主密钥和呼叫参与者的JID创建加密密钥、盐和nonce。结果值⽤于初始化六个SRTP流,每个调⽤⽅使⽤三个。
下⾯的代码⽚段显⽰了⽤Java编写的密钥派⽣函数的重建:
此代码段表⽰初始化单个SRTP流的密钥派⽣。输⼊参数和函数的输出由Frida记录。为了重建KDF算法,分析了libcommonCrypto库中散列函数的输⼊和输出。三个HMAC-SHA256计算被⽤于导出最终
密钥。可以发现KDF是基于RFC 5869的。
调⽤初始化
WhatsApp使⽤SRTP来加密客户端呼叫期间的⾳频数据,SRTP由libsrtp库实现。不幸的是,libsrtp库的符号从WhatsApp⼆进制⽂件中剥离出去。这就是为什么我们不能⽤符号名来搜索库函数。相反,我采⽤了不同的⽅法来分析libsrtp库的功能。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。