iMessage Privacy (1)

本文是翻译自Quarklab’s blog的iMessage Privacy博文,如果想看原文的,请点击这里http://blog.quarkslab.com/imessage-privacy.html#id6。因为篇幅比较长,所以将会分成上下两篇,希望这两篇博文能够帮助大家更好地理解iMessage安全性相关知识。翻译不到之处,还请谅解。

iMessage或许目前最流行的即时通讯系统之一。苹果公司宣称iMessage是非常安全的,因为iMessage采用了高加密标准,包括点对点的加密,从而可以防止包括苹果公司在内的第三方的监听。然而,这是真的吗?

演示文稿

你可以通过以下的链接来下载我们在HITBSecConf2013的演示文稿的幻灯片 http://blog.quarkslab.com/static/resources/2013-10-17_imessage-privacy/slides/iMessage_privacy.pdf

快速的回答

  • 我们不是在说:苹果公司偷看了你的iMessages。
  • 我是是在说:苹果公司可以偷看你的iMessages,如果他们愿意的话,或者他们被政府要求这么做的话。

正如苹果公司所宣称的,iMessage的确采用的点对点的加密。但是问题就在于密钥的构造是由苹果公司来控制的:如果他们愿意的话,他们可以随时更改密钥,从而可以读到我们iMessages的内容。

另外,我们必须知道的是,跟消息的内容一样,元数据同样很重要。因为你是靠苹果公司来发送你的消息,所以他们会拥有你的元数据。

现在,你可以继续阅读下面的文章,或者直接跳到文章的结尾,我们将在文章的结束部分进行总结。


即时通讯的监听

多年来,每当出现一个新的即时通讯服务,就会有一大堆的人会很关心这些服务的安全性。还记得当年黑莓和Skype吗?它们在一开始的时候,都是宣称所有的信息都会被加密,而且信息是非常安全的,是不可能被监听的。但是几年之后,这被证明是虚假的[1][2]

对于那些在安全领域工作的人来说,这并不惊奇。至少有一个原因可以解释,那就是政府部门的存在。因为政府部门的一个很重要的职责就是确保人们的安全,所以政府部门需要监听那些危险分子。因此你的消息可能会被监视,也就不足为奇了。这个问题更多的是道德问题而不是合法性,因为那些情报机构被赋予了这些权利。

最近,斯诺登事件让人们意识到实际情况比人们想象的更为糟糕:加密标准的后门,与大公司的勾结,大量的数据收集,无处不在的入侵。。。我们先不管政府部门实行监听的背景和合法性,可以看到的是,那些涉及的公司无不试图降低在这件事上的角色,并一直用一个简单的借口来推脱:我们只是服从法律。但是,不管怎样,如果一家公司一旦宣称他们是不可能监听他们所管理的消息,那么即使是被要求和政府部门合作,他们也理应从技术上的角度真的不能够解密那些信息。

在斯诺登事件之后,苹果公司发布了一则声明,叫做Apple’s Commitment to Customer Privacy。由于那段时间内人们的问题都是关于iMessage,Siri和Facetime的安全性,因此他们清楚地回答说[3]

There are certain categories of information which we do not provide to law enforcement or any other group because we choose not to retain it. For example, conversations which take place over iMessage and FaceTime are protected by end-to-end encryption so no one but the sender and receiver can see or read them.Apple cannot decrypt that data.

(有若干信息我们并不提供给法律部门或者任何的其他组织,因为我们选择并不保留这些数据。比如说,在iMessage和Facetime上进行的对话,都是通过点对点的方式进行加密保护,所以只有发送者和接受者可以看到当中的内容。苹果公司并不能够解密这些数据。)

根据这则声明所说的,苹果公司的确可以向第三方提供一些元数据(比如说,谁发送消息,谁接受消息,消息发送时间),但是对话的内容是不包括在内的。但是,接下来,我们将会证明这不是真的。尽管是点对点的加密,苹果公司仍然可以获取到那些加密的信息。但,这是不是意味着苹果公司就真的监听了我们的消息呢?这个问题或许只有苹果公司和相关部门能够回答,而我们是无法回答的。

好的,接下来我们就来进行详细的分析。

缺少证书锁定:那又如何?

首先,我们注意到,几乎所有的通信都是加密的。这相当好呀。所有发送到苹果公司服务器的会话都是通过安全的SSL通道。我们不需要知道当中使用什么协议或者报文是如何包装的。我们想要尝试的第一件事就是添加一个证书来进行MITM[4]

实际上,我们非常惊讶地发现,这非常容易就成功了,这至少证明了iMessage并没有使用证书锁定[5]。我们创建了一个假的CA,然后加入到iPhone的keychain,并建立一个代理来监听通讯。当代理监听到一个SSL链接,我们就生成一个由刚刚添加的CA所签名的证书,然后,就没有然后了,所有的信息都已经解密了。

另一个让我们更加惊讶的发现是:通过这个SSL通讯,我们甚至可以清楚地看到我们的AppleID和密码。是的,真的是完全的明文密码。。。。。虽然有很多原因可以说明为什么会用明文的方式发送密码,比如ssh就是这样,但是在这里,我们想不到有任何的理由会让苹果需要知道我们的密码。

首先,这个意味着苹果公司可以在很多网站上,比如说我们的邮件,使用我们的密码。好的吧,苹果公司的确也没有理由这么做。但是,那些情报部门呢?第二,这个同样意味着任何人,只要他会添加证书以及建立代理来监听通讯,那他就可以获取用户的AppleID和密码,然后就可以畅通无阻的访问他们的iCloud账号,数据备份,购买的应用。。。。

以下是我们获得的一个例子:

shell
1
2
3
4
5
6
7
8
9
10
11
12
POST /WebObjects/VCProfileService.woa/wa/authenticateUser
'content-length': 223,
'accept-language': en-us,
'accept-encoding': gzip,
'content-encoding': gzip,
'host': service.ess.apple.com,
'accept': */*,
'user-agent': com.apple.invitation-registration [Mac OS X,10.8.3,12D78,Macmini4,1],
'connection': keep-alive,
'x-protocol-version': 7,
'content-type': application/x-apple-plist,
'x-ds-client-id': t:3A5DC02C47249FC50EF0FF1B8CF3073C9EBD0668

然后下面的是post的数据内容

xml
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>password</key>
<string>Icandoaproperkeynote</string>
<key>username</key>
<string>tim_c@icloud.com</string>
</dict>
</plist>

在进行下一个话题前,我们再和证书玩一会。关于证书的问题,我们想到了iPhone Configuration Utility这个应用。这个应用是苹果公司为企业提供的管理iPhone的解决方案。在第一次运行这个应用的时候,当设备插入之后,CA就会添加到设备当中。MDM管理人员可以通过这个应用来轻松地纳入新的设备。

证书验证

为什么会有这个应用呢?这是因为对于那些由企业的IT部门管理的iPhone,他们希望能够创建一个代理,然后默默地监听iPhone发送出去的和接收到的所有通讯,然后就查看到可以非常隐私的信息。值得留意的是,不管是PUSH或者iMessage,证书绑定并不在任何特定的一层,因此任何地方都可能发生各种问题。

3. 协议:客户端,PUSH & ESS服务器

在这部分内容,我们将会描述一般的过程,包括所有相关的协议和加密步骤。

3.1 设备上的客户端

每一台设备都会有各自的证书,1024RSA和CN= (显然,GUID需要用设备的GUID来代替)。客户端是MobileSMS/Message.app,但是客户端需要依赖于其他的服务。最主要的两项是:

  • apsd:苹果公司的PUSH服务守护进程,负责从苹果公司的服务器获取消息,并下载到设备中。
  • imagent:iMessage任务的后台进程,比如说当设备关闭的时候保持连接。

苹果公司转发某条消息的过程,包括以下两个方面:

  • 给定一个目标地址(即URI,可以是电话号码或者邮件地址),苹果公司通过某种方法获得所有跟这个URI相关联的设备(包括iPhones,iPads或者OS X系统)。
  • 一旦苹果公司获得相关设备,苹果公司就可以将消息发送给这些设备。

首先,让我们从第二个方面开始,也即传输协议(PUSH协议)。

3.2 PUSH协议

当应用需要通知一个事件的时候,比如iMessage,Facetime,GameCenter和具有部分发送功能的应用,都会使用到PUSH协议,一个网络远程通知协议。在日常使用当中,你经常会收到Facebook,Whatsapp或者新闻类的应用发来的通知,告诉你一些刚刚才发生的事情。其实,所有的这些都是基于PUSH协议的。

下面是苹果公司对PUSH协议的定义:

Local and push notifications are great for keeping users informed with timely and relevant content, whether your app is running in the background or inactive. Notifications can display a message, play a distinctive sound, or update a badge on your app icon.

(本地和推送通知都可以帮助用户获取及时相关的内容,不管你的应用是否是在后台运行或者已经被关闭。通知可以展示信息,发送特定的声音,或者更新你的应用图标上的标记。)

PUSH协议作为一个传输协议,主要负责向一组设备发送payload(先不用管这是什么)。因此,在传输协议看来,iMessage本身其实就是一个payload。

对于iMessage,所有的PUSH通信都在服务器端口5223的安全传输层协议上进行:

  • Hostname由[0,…,255]-courier.push.apple.com组成
  • 客户端的证书,对于某个特定的设备(接下来会说到这点)

客户端证书

当一台设备在苹果公司上注册和激活后,都会生成PUSH协议证书。在第一次与苹果公司的服务器通信的时候,会向albert.apple.com服务器发送一个证书请求。这个服务器运行着证书授权服务,被称作Apple iPhone Device CA,负责签署每一个请求。

这个证书信息是非常敏感的,因为设备发起的所有PUSH通信都是又它来负责:包括客户端和服务器端的身份验证,都是根据它来保证PUSH通信的安全性。

正因为如此,所以这个证书并不会直接包含在iMessage中。虽然如此,因为iMessage在PUSH协议上运行,所以它还是可以发挥作用的。

PUSH密钥

从PUSH协议层的角度来说,关于它是如何工作的,还是一个只有苹果公司才知道的秘密。因此我们从客户端的角度来观察。通常,我们会先编写了一条消息,然后点击发送按钮。这样操作之后,客户端就会向苹果的ESS服务器请求发送这条消息所需要的信息。ESS服务器则会返回下面这三样信息:

  • 一个PUSH密钥,也即一对iDevice的唯一标记。
  • 两个加密的密钥

PUSH密钥是在当设备在苹果服务器注册通讯服务的时候就会生成。因为它是在服务器端生成的,所以它的生成方法是不公开的,同样对于对于它真正的用途也是。目前来说,我们把它看作是供应商的登记和路由信息。

由于实际上很多的苹果用户经常拥有多个苹果设备,一条iMessage消息需要发送到多台设备上,因此供应商需要将自己注册为iMessage供应商以及提供路由信息,以便让苹果公司知道该往哪里发送消息。

因此客户端发送一条消息的时候,它其实是向所有拥有Push-Tokens的设备都发送了消息,以便这条消息能够发到所有的设备。这些消息通过端口5223的网关发送到苹果公司的网络推送服务(Apple Push Network Service)。

比如说,在OS X系统,你可以看到:

shell
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
root@joker:~>> ps aux |grep apsd
root 90 0.0 0.1 2467868 8052 ?? Ss Thu09AM 0:06.06 /System/Library/PrivateFrameworks/ApplePushService.framework/apsd
root 20295 0.0 0.0 2432768 588 s003 S+ 3:08PM 0:00.00 grep apsd

root@joker:~>> lsof -p 90 |grep TCP
apsd 90 root 9u IPv4 0x667b30bc14a94f93 0t0 TCP joker.lan:65158->17.172.232.179:5223 (ESTABLISHED)

root@joker:~>> whois 17.172.232.179
NetRange: 17.0.0.0 - 17.255.255.255
CIDR: 17.0.0.0/8
OriginAS:
NetName: APPLE-WWNET
NetHandle: NET-17-0-0-0-1
Parent:
NetType: Direct Assignment
RegDate: 1990-04-16
Updated: 2012-04-02
Ref: http://whois.arin.net/rest/net/NET-17-0-0-0-1
OrgName: Apple Inc.
OrgId: APPLEC-1-Z
Address: 20400 Stevens Creek Blvd., City Center Bldg 3
City: Cupertino
StateProv: CA
PostalCode: 95014
Country: US
RegDate: 2009-12-14
Updated: 2011-03-08
Ref: http://whois.arin.net/rest/org/APPLEC-1-Z
...

当APNS服务器接收到这些信息后,PUSH协议就开始发挥作用。虽然这方面的信息没有在文档中说明,但是我们可以根据[6]来猜测,苹果公司主要是依赖于APNS和设备间的连接。根据每一条消息中的Push密钥,苹果公司能够知道哪台设备应该接收这条消息。

PUSH协议层上的MITM

怎么攻击PUSH协议层呢?攻击它,意味着在客户端和苹果服务器之间来监听消息。但是,因为通信是在TLS协议上的,所以需要花费一些精力来提供证书。

有一个非常方便的工具,叫做PushProxy。这个工具提供了一些简单的API来处理接受的和发送的消息。因为在要在真实的通信中进行监听需要很多事先的准备,为了简化,我们目前只在本地的设备上进行演示。

首先,我们需要在系统的keychain中添加一个root CA,让代理的证书被信任。通过这种方法,客户端就会相信代理发送过去的信息。这很简单,但是我们还是得需要跟苹果的服务器进行通信。正如我们之前说的,验证是双向的,所以我们需要网albert.apple.com插入一个新的证书,或者用一个已经签名的证书。

我们选择了第二个选项:我们从设备的PUSH证书中抽取部分私有信息,然后加到代理中。最后,我们需要修改设备的/etc/hosts文件,来重定向所有的通信到代理上。

现在,我们就可以看到有什么包含在PUSH消息中了。一个iMessage payload的PUSH协议层,跟下面的相类似(XX字节没有设置,因为它们依赖于消息的内容):

shell
1
2
3
4
5
6
0a                    >> Message Type
XX XX XX XX >> Next Length
04 00 04 XX XX XX XX >> Identifier (4 bytes)
01 00 14 XX .. .. XX >> Topic Hash (20 bytes)
02 00 20 XX .. .. XX >> Push-Token (32 bytes)
03 XX XX ... >> iMessage payload

在我们深入了解iMessage的payload之前,我们需要先了解下iMessage ID。

3.3 iMessage ID

往下,为了简单点,我们把iMessage称为IM。在IM层,包含了很多信息,其中包括:

  • AppleID: 正如之前所说,苹果账号的核心内容。
  • URI: 跟AppleID的格式一样,是一个邮件地址或者电话号码。一个AppleID可以对应多个URI。当它是邮箱地址的时候,需要通过点击一个连接来验证。当它是电话号码的时候,就只能通过SIM卡来验证。
  • Push-Token: 之前已经介绍过,是iMessage用来确定每个URI所注册的设备。因此,每台设备上的URI都是对应一个唯一的Push-Token。

3.4 发送一条iMessage

当一个用户想要发送一条iMessage,他首先需要提供一个或者多个目标URI。因为通讯是端对端地加密,所以通讯的设备相互之间直接交换所需的密钥,或者某个地方存放着一个密钥目录。

实际上,的确是有这么一个密钥目录,叫做ESS服务器(我们也不知道为啥叫做ESS,问苹果公司吧)。为了获得密钥,iDevice会向服务器发送这么一条请求:

shell
1
2
3
4
5
6
GET /WebObjects/QueryService.woa/wa/query?uri=tel:+33123456789
'Host': service1.ess.apple.com
'Content-Type': application/x-apple-plist
'x-id-cert': [Provision Certificate]
'x-id-nonce': [Random Nonce with Timestamp]
'x-id-sig': [Query Signed with Provision Cert.]

在这个例子中,这台iDevice想要获得URI为“+33123456789”的密钥。

我们需要注意的是,这个请求是用另外的一份证书来签名的,这份证书叫做Provision。这份证书是在客户端中生成的,在iMessage验证过程中,由一个叫做Apple IDS DS-ID Realm CA的授权来签名的。它的有效期只有一个月。

服务器返回的响应跟下面的相似:

shell
1
2
3
4
5
6
7
8
9
{
'push-token': [PushToken]
'client-data':
{
'show-peer-errors': True,
'public-message-identity-version': 1.0,
'public-message-identity-key': [Public Keys Buffer]
}
}

实际上,这是一个XML plist。我们将它转化成JSON格式,好让它更好理解。在我们的例子中,只返回了一个身份标记。要是目标URI对应了多台设备和多个注册的账号,则会返回他们每一个对应的身份标记。

除了包含了Push-Token,服务器返回的响应中还包含了一堆公开的密钥:

  • 一个ECDSA(256-bit),用来验证目标URI发送过来的消息的签名。
  • 一个RSA(1280-bit),用来加密发送给目标URI的iMessage。

通过这些密钥,我们就可以跟目标URI对应的设备建立一个安全的(真的?)通讯。

3.5 iMessage Payload

在结束对PUSH协议的介绍之前,我们先来看看什么是iMessage payload。现在,我们就来看看payload是由什么组成的。

payload的格式是由苹果公司来规定的,称为bplist(binary-plist),将序列化的数据组装成一个字典。它定义了多种类型的数据,包括常见的那些类型:NSString,NSNumber,NSDate,NSArray,NSData,NSDictionary。

下面是bplist的一个例子:

shell
1
2
3
4
5
6
7
8
9
10
11
D:   True
E: 'pair'
P: <variable length binary data> (iMessage payload, deflate compressed)
U: <128bit binary data> (iMessage UID)
c: 100
i: <32bit integer> (messageId, same as in PUSH header)
sP: mailto:tim_c@icloud.com (sender URI)
t: <256bit binary data> (sender Push-Token)
tP: mailto:mark_z@facebook.com (receiver URI)
ua: [Mac OS X,10.8.5,12F37,MacBookPro10,2] (sender OS and hardware version)
v: 1

其中,ua字段基本上是没有什么用处的,但是却会包含在每一个请求中。难道是苹果公司为了统计吗?

不管怎样,P字段就是IM payload。它在压缩的时候就被加密了(先加密,然后在压缩)。它是由下面这些关键字组成:

shell
1
2
3
4
5
(byte)     0x02          version?
(short) ciphertext length
(data) ciphertext RSA / AES-CTR data : ciphered with the RSA public key of the recipient
(byte) signature length
(data) signature ECDSA signature of <ciphertext> : computed with the ECDSA private key of the emitter

在明文中,这个数据也是bplist,我们姑且把它称作inner bplist:

shell
1
2
3
4
p: array of URIs in the discussion group
t: iMessage text (for iOS)
v: version (1)
x: iMessage html (attachments, and style - for OS X)

这个数据是真正发送给目标的信息(URI,信息,附件)。我们来看一下,它创建的步骤:

  1. 生成一个16字节的随机字符,作为AES key。
  2. 在CTR模式下,用AES来加密那些明文数据,加密后的数据称为AES(ibplist)。
  3. 然后在输出流的开头加上一个128-bit的密钥
    aes2
  4. 这个由128-bit的密钥和808-bit的AES(ibplist),使用65537公开指数和PKCS1 OAEP填充,与RSA-1280进行加密。组成1280-bit的输出流。
    aes1
  5. 最后用ECDSA密钥来签名。

这里所使用的RSA密钥是从ESS服务器那里获得的。

发送带附件的iMessage

跟大多数的即时通讯服务一样,iMessage提供了发送带附件的消息。虽然通常人们都只是用他们的iPhone发送图片,但其实iMessage支持任何格式的文件。

发送一个附件的时候,这个附件其实是保存在iCloud服务器上的一个专用资料库中。这个附件用AES来加密,而加密的密钥,与文件的链接一起,包含在iMessage的payload中发送给目标地址。因为消息用目标的RSA密钥来加密,所以附件加密的密钥同样被加密了。

这些都是包含在HTML消息中的字段:

shell
1
2
3
4
5
6
7
8
9
10
11
12
13
<file
name="<name>"
width="<width>"
height="<height>"
datasize="<size>"
mime-type="<mime type>"
uti-type="<uti type>"
mmcs-owner="<identifier>"
mmcs-url="<URL>"
mmcs-signature-hex="<signature>"
file-size="<size>"
decryption-key="<key>"
/>

未完待续~

引用

[1]
http://www.wired.co.uk/news/archive/2013-07/11/blackberry-inda

[2]
http://www.washingtonpost.com/business/economy/skype-makes-chats-and-user-data-more-available-to-police/2012/07/25/gJQAobI39W_story.html

[3]
https://www.apple.com/apples-commitment-to-customer-privacy/

[4]
Man-in-the-Middle Attack,中间人攻击,通过窃取或窜改两方通信内容间接完成攻击行为的网络攻击方法。这种攻击模式通过各种攻击手段入侵控制或者直接以物理接入方式操控两台通信计算机之间的主机并通过这台主机达到攻击两台通信计算机中任意一方的目的。详情请查看MITM攻击简介

[5]
https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning

[6]
https://github.com/meeee/pushproxy