mfrister / pushproxy

A man-in-the-middle proxy for iOS and OS X device push connections
GNU General Public License v3.0
432 stars 65 forks source link

iOS 9 Incompatibility #28

Open jjjapj opened 8 years ago

jjjapj commented 8 years ago

Hi, I am unable to successfully get apsd to accept the proxy certificates. I tried adding com.apple.apsd to SSLKillSwitch2, but iOS is still rejecting the certificates for the push proxy. These same certificates and setup work great on iOS 7 and 8. iOS 9 is doing something else, presumably with App Transport Security (ATS). I did already verify that the generated certs are 2048 bit and are TLS 1.2, which is in compliance with ATS. I'm not sure about the 'Perfect forward secrecy cipher suites' requirement of ATS. Here is some log data:

Jan 16 21:06:57 x-iPhone apsd[265]: MS:Notice: Injecting: com.apple.apsd [apsd] (1240.10)
Jan 16 21:06:57 x-iPhone apsd[265]: MS:Notice: Loading:       /Library/MobileSubstrate/DynamicLibraries/SSLKillSwitch2.dylib
Jan 16 21:06:57 x-iPhone apsd[265]: === SSL Kill Switch 2: Preference set to 1.
Jan 16 21:06:57 x-iPhone apsd[265]: === SSL Kill Switch 2: Subtrate hook enabled.

and then when it tries to connect to push server:

Jan 16 21:07:33 x-iPhone apsd[265]: CFNetwork SSLHandshake failed (-9801)

When the device attempts connection, the push proxy server complains with an exception containing ssl handshake failure SSL3_READ_BYTES

jjjapj commented 8 years ago

I made some progress. Updated pyOpenSSL to employ perfect forward secrecy. The device will now handshake properly, but I have a new problem. The device factory closes right after it starts without any debug information - no exceptions, etc. Any idea how I can get more information about what is going on?

2016-01-21 23:07:59-0500 [#113] New connection from 98xxxxxx:50433
2016-01-21 23:08:00-0500 [#113] SSL handshake done: Device: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
2016-01-21 23:08:00-0500 [#113] Connecting to push server: 17.172.232.212:5223
2016-01-21 23:08:00-0500 Starting factory <icl0ud.push.intercept.InterceptClientFactory instance at 0x10c144950>
2016-01-21 23:08:00-0500 Stopping factory <icl0ud.push.intercept.InterceptClientFactory instance at 0x10c144950>
mfrister commented 8 years ago

Sorry for the late reply, I'm happy you got a step further.

It's been a while since I last touched the proxy code, but I can imaging Apple's servers don't allow SSL v3 connections, so the connection to their server fails. pushproxy might use SSLv3 (not exactly sure what the line does, would have to look into that later), see intercept.py:91.

For debugging, you might add a log statement/debugger in interceypt.py:79 - there's a reason parameter that might help.

If that doesn't help, you could look at the pushproxy - Apple server TLS handshake using Wireshark and see what happens there.

jjjapj commented 8 years ago

Thanks for the input!

Hmm.. I tried changing the method to TLSv1_2_METHOD but that did not work on my other devices (wasn't able to test the iOS9 one since it didn't even work on the older iOS versions) - it produced the same instant-disconnect.

Adding debugging printout to InterceptClientFactory.clientConnectionFailed had no effect - it appears it is never called. However I also added clientConnectionLost to the InterceptClientFactory and received no useful info but an indicator of the connection being lost:

 2016-01-23 00:00:30-0500 [#16] New connection from 9xxxxxxxx:49563
 2016-01-23 00:00:30-0500 [#16] SSL handshake done: Device: xxxxx
 2016-01-23 00:00:30-0500 [#16] Connecting to push server: 17.172.232.212:5223
 2016-01-23 00:00:30-0500 Starting factory <icl0ud.push.intercept.InterceptClientFactory instance at 0x10a899908>
 2016-01-23 00:00:30-0500 Building protocol
 2016-01-23 00:00:30-0500 Client connection lost: %s [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionDone'>: Connection was closed cleanly.
]
 2016-01-23 00:00:30-0500 Stopping factory <icl0ud.push.intercept.InterceptClientFactory instance at 0x10a899908>

Unfortunately Wireshark was not very revealing - I just see a cert from Entrust being transmitted from the Apple push server back to the push proxy server, but otherwise I don't know how to read or interpret the handshake. I'm a bit leery of posting it here since it contains my IP.

Sasiaani commented 8 years ago

Hi!

Any new information related to this? I have the same problem with iOS9, disconnecting immediately after the handshake with a device and connecting to the push server.

The setup works fine with iOS8.

Edit: I added logging to def connectionLost and it seems that the connection is not closed cleanly due to a handshake failure: 2016-05-12 15:07:18+0300 [#2] New connection from 192.168.150.9:49174 2016-05-12 15:07:18+0300 [#2] SSL handshake done: Device: XXXXXXX 2016-05-12 15:07:18+0300 [#2] Connecting to push server: 17.172.232.145:5223 2016-05-12 15:07:18+0300 Starting factory <icl0ud.push.intercept.InterceptClientFactory instance at 0x7f5f4f2db878> 2016-05-12 15:07:18+0300 Connection lost: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionLost'>: Connection to the other side was lost in a non-clean fashion: Connection lost. ] 2016-05-12 15:07:18+0300 Connection lost: [Failure instance: Traceback: <class 'OpenSSL.SSL.Error'>: [('SSL routines', 'SSL23_READ', 'ssl handshake failure')] /usr/lib/python2.7/dist-packages/twisted/internet/posixbase.py:260:_disconnectSelectable /usr/lib/python2.7/dist-packages/twisted/internet/tcp.py:484:connectionLost /usr/lib/python2.7/dist-packages/twisted/internet/tcp.py:298:connectionLost /usr/lib/python2.7/dist-packages/twisted/protocols/tls.py:473:connectionLost --- --- /usr/lib/python2.7/dist-packages/twisted/protocols/tls.py:360:_flushReceiveBIO /usr/lib/python2.7/dist-packages/OpenSSL/SSL.py:1320:recv /usr/lib/python2.7/dist-packages/OpenSSL/SSL.py:1187:_raise_ssl_error /usr/lib/python2.7/dist-packages/OpenSSL/_util.py:48:exception_from_error_queue ] 2016-05-12 15:07:18+0300 Stopping factory <icl0ud.push.intercept.InterceptClientFactory instance at 0x7f5f4f2db878>

I changed SSLv23_METHOD to SSLv2_METHOD but that resulted in an error, maybe I'll try other constants as well. I don't know if I'll be able to get anything out of the handshake either but maybe I still need to check that with Wireshark.

mfrister commented 8 years ago

Hi,

I'm pretty sure this is an issue with either openssl being too old or being wrongly configured, so the Apple Push Servers reject the TLS connection due to an outdated cipher or TLS version.

I tried to connect using two different openssl versions, the first one is the default installed on OS X 10.11, the other one is one I had lying around (probably outdated as well).

$ openssl version
OpenSSL 0.9.8zh 14 Jan 2016
$ openssl  s_client -connect 17.172.232.212:5223
[...]
write:errno=54
$ openssl version
OpenSSL 1.0.2e 3 Dec 2015
$ openssl  s_client -connect 17.172.232.212:5223
[...]
SSL-Session:
    Protocol  : TLSv1
    Cipher    : ECDHE-ECDSA-AES128-SHA
[...]

So the openssl version included with OS X 10.11 can't connect to Apple's servers (at least with default settings), but a newer version can.

You might try a newer openssl version, I wouldn't be surprised if 0.9.8zh doesn't support ECDHE or ECDSA ciphers although Apple requires one.

Sasiaani commented 8 years ago

Thank for the reply!

I am using Kali with openssl 1.01k and the connection to the Apple's server works the same way as in your example with 1.0.2e.

I tried changing the script to use SSL.TLSv1_METHOD as the "openssl s_client -connect 17.172.232.212:5223" started session seems to use that but the only difference was that

Connection lost: [Failure instance: Traceback: <class 'OpenSSL.SSL.Error'>: [('SSL routines', 'SSL23_READ', 'ssl handshake failure')]

was changed to

Connection lost: [Failure instance: Traceback: <class 'OpenSSL.SSL.Error'>: [('SSL routines', 'SSL3_READ_BYTES', 'ssl handshake failure')].

In apsd logs the failure can be seen as failed certificate chain validation:

2016-05-13 14:11:06 +0300 apsd[262]: <APSCourier: 0x12660ce10>: Connected to courier 25-courier.pus.huuhaa.com (192.168.150.1) connection: <APSCourierConnection: 0x126616850> onInterface: NonCellular
2016-05-13 14:11:06 +0300 apsd[262]: copyTokenForDomain push.apple.com (null)
2016-05-13 14:11:06 +0300 apsd[262]: <APSCourier: 0x12660ce10>: Sending connect message with token '<XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX>' onInterface: NonCellular with activeInterval 5
2016-05-13 14:11:06 +0300 apsd[262]: Failed to validate certificate chain for courier.pus.huuhaa.com.
2016-05-13 14:11:06 +0300 apsd[262]: Untrusted peer, closing connection immediately
2016-05-13 14:11:06 +0300 apsd[262]: Closing <APSTCPStream: 0x1265c00a0> with environment <APSEnvironment: 0x126521540: production>[production]

Wireshark captures are the next step.

onsails commented 7 years ago

@Sasiaani you probably need to change CN from courier.pus.huuhaa.com to something like 22-courier.push.apple.com.