ReQrypt, upstream-only IP-layer proxy

96 views
Skip to first unread message

David Fifield

unread,
Jul 25, 2017, 6:49:50 PM7/25/17
to traff...@googlegroups.com
My buddy Marek Majkowski referred me to this project:
https://reqrypt.org/reqrypt.html

I didn't find a lot of technical detail, but I gather it works something
like this: The client sends upstream packets through some kind of
obfuscated tunnel to a proxy. The proxy decapsulates the packets and
forwards them *unmodified* (including the client's original source
address) to the destination address in the IP header. When the remote
server receives the packets and sends its reply, it sends them directly
back to the client (because the client's true IP address is in the
source address of the packets); i.e., the proxy is not used in the
downstream direction. Some mechanism on the client side links up what
would otherwise be distinct 4-tuples.

Here you can see the proxy receiving an encapsulated packet and simply
forwarding it to the given destination address:
https://github.com/basil00/reqrypt/blob/7000ca11a16dac78532d2978c7d965c943259dd1/src/cktp_server.c#L539

There are similarities to TriangleBoy, with the difference that in
TriangleBoy, downstream packets have their source address spoofed to
appear to come from the proxy, instead of from the destination server.
http://www.webrant.com/safeweb_site/html/www/tboy_whitepaper.html

Since the obfuscation is only in one direction, ReQrypt will be good
against some forms of detection and not others. It will work against
HTTP request filtering, but not HTTP response filtering. It will work
against IP blocking when the firewall blocks SYNs *to* forbidden IPs,
but not when it blocks SYN/ACKs *from* forbidden IPs (as the GFW does,
last time I checked).

The GitHub page brands ReQrypt as "A HTTP request tunneling tool," but I
don't see what is specific to HTTP. Because it's tunneling IP packets,
it should be more general than just HTTP, unless it's doing some other
manipulations that I haven't found out about yet. It might be because
their default tunnel capture firewall rules only capture ports 80, 443,
and 53.
https://github.com/basil00/reqrypt/blob/7000ca11a16dac78532d2978c7d965c943259dd1/src/linux/capture.c#L81

There's some documentation on their tunnel obfuscation algorithm in a
block comment here:
https://github.com/basil00/reqrypt/blob/77054496a165f78bc8066080319f556f4f05a55d/src/encodings/crypt.c

/*
* PROTOCOL SUMMARY:
*
* HANDSHAKE:
* (0) Server publishes the URL(RSACertificateHash), where
* - RSACertificateHash is a cryptographic hash function of an RSA
* certificate.
* (1) Client sends a GET_COOKIE request.
* (2) Server responds with a COOKIE(Cookie) reply.
* (3) [OPTIONAL] Client sends a GET_CERTIFICATE(Cookie) request, where:
* - Cookie is the same as message (2).
* - This is OPTIONAL if the client has a cached copy of the
* RSACertificate corresponding to RSACertificateHash from message (0).
* (4) [OPTIONAL] Server responds with a CERTIFICATE(RSACertificate) message.
* The client verifies that hash(RSACertificate) == RSACertificateHash
* (5) Client sends a GET_KEY(Cookie, ClientDHPublicKey) request, where:
* - Cookie is the same as message (2).
* - ClientDHPublicKey is the client's DH public key
* (6) Server responds with a
* KEY(ServerDHPublicKey, encrypt_DHSharedKey(
* sign_RSAPrivateKey(SessionKey, SessionKeyId)))
* reply, where:
* - ServerDHPublicKey is the server's DH public key.
* - DHSharedKey is the DH shared secret key.
* - RSAPrivateKey is the RSA private key corresponding to
* RSACertificate.
* - SessionKey is the private key to use for the rest of the tunneling
* session.
* - SessionKeyId is the key identifier associated to SessionKey.
* Note: SessionKey is secret, SessionKeyId may be public.
*
* Note: portions of messages (1) - (6) are additionally encrypted using
* RSACertificateHash as the key. This makes it necessary for an
* eavesdropper to know the URL in order to read some protocol fields.
* This is a cheap way of adding more work for any attacker.
*
* TUNNELING:
*
* All encryption is done using a block cipher is CTR mode.
*
* (*) Client prepends a CLIENT_HEADER(IV, SessionKeyId, MAC) header and
* encrypts the packet using SessionKey, where
* - IV is a randomly generated Initialisation Vector.
* - SessionKeyId is the same as message (4) from the handshake.
* - MAC is the Message Authentication Code.
* (*) Server prepends a SERVER_HEADER(IV, MAC) header and encrypts the packet
* using SessionKey, as per above.
*
* Note: The Client additionally encrypts the SessionKeyId with the same IV
* and RSACertificateHash as the key.
*
* NOTES:
* (1) The server is stateless. The server derives the SessionKey from the
* SessionKeyId using a cryptographically secure secret hash function.
*
* POSSIBLE (NON-STANDARD) ATTACKS:
* - A man-in-the-middle could modify message (0) to insert their own
* certificate hash and message (3) to insert their own matching
* certificate. Then a standard man-in-the-middle attack can be executed.
* To counter this message (0) may be sent using some other secure protocol
* (e.g. SSL), or simply published widely.
* - A man-in-the-middle could observe a protocol handshake, then send forged
* GET_KEY requests to the server. If the server returns the same
* (SessionKey, SessionKeyId) as the one returned to the client, the session
* is compromised. To counter this the SessionKeyId is at least 39 bits
* (effective), meaning an average of 2^38 forged GET_KEY requests are
* required. As each GET_KEY is 100+ bytes, this is attack requires
* multiple terabytes of GET_KEY messages to be sent. Hopefully this is
* impractical for some time. The SessionKeyId may be up to 63 bits long.
* - The protocol has no built-in protection against replay attacks. This is
* because (1) the server is stateless, and (2) the tunneled protocols such
* as CKTP, TCP, and UDP have their own sequence numbers.
*
* IMPLEMENTATION BUGS:
* - This code has not been scrutinised/tested nearly enough to be considered
* secure. Rely on it at your own risk.
*/
Reply all
Reply to author
Forward
0 new messages