net4people / bbs

Forum for discussing Internet censorship circumvention
3.26k stars 77 forks source link

ReQrypt is a free tool for bypassing a local adversary. #74

Open hamedsbt opened 3 years ago

hamedsbt commented 3 years ago

ReQrypt is a free tool for bypassing a local adversary. This includes:

ISP-level URL-filtering (a.k.a. censorship) systems; ISP or government data-logging/snooping systems; and ISP or local network forced transparent proxying. Unlike other anti-censorship tools, ReQrypt does not rely on a network of friendly proxy severs. Instead, ReQrypt works more like a user-controllable routing tool, that lets the user redirecting outbound packets through one or more encrypted tunnel(s) -- bypassing the local adversary. ReQrypt does not affect inbound traffic, which is sent via the normal route.

ReQrypt has the following advantages:

Since ReQrypt does not rely on proxy servers, your IP address will not be changed. To the remote web server, it appears as though your traffic was sent directly from your PC unchanged (save for TTL values and fragmentation). Since inbound packets are sent directly from the web server to your browser, and not via a proxy server, ReQrypt is fast. (For tunnel operators): running a ReQrypt server is cheaper than running a proxy server, since outbound traffic (web requests) is usually much smaller than inbound traffic (web responses). ReQrypt is effective against most lightweight filtering/logging systems that are popular in western countries, since such systems usually only intercept outbound traffic. Intercepting inbound traffic is generally more expensive and technically challenging, thus is usually ignored.

https://github.com/basil00/reqrypt

wkrp commented 3 years ago

It's an interesting design, where only outgoing traffic is tunnelled, and incoming traffic is unmodified. The home page has a table of the types of censors it can be expected to be effective against.

Here's a summary I posted in 2017:

ReQrypt, upstream-only IP-layer proxy

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.
*/ 

There's a discussion forum for ReQrypt at NTC.

hamedsbt commented 3 years ago

We need more free servers around the world to help many people who is blocked by their governments.

wkrp commented 3 years ago

We need more free servers around the world to help many people who is blocked by their governments.

Is there a guide to setting up a Reqrypt server? The INSTALL file says make server_install, but doesn't have details on how to configure a tunnel.

How do users discover servers to use? The client documentation shows a tunnel URL syntax like udp://example.org:58000?crypt=cipher.xxtea,cert.rQHEq2ky32DOaCopEMFVR0,sec.2888. How does a user get one of these URLs?

EDIT: I found a server guide at https://github.com/basil00/reqrypt/issues/38#issuecomment-473115272. In short:

reqryptd_tool aes gen
reqryptd --add udp://HOST:PORT?crypt=STRING,sec.2888

where STRING is the output of reqryptd_tool aes gen. Clients need to add the same URL as was added on the server.

hamedsbt commented 3 years ago

Unfortunately I don't have any proper environment to build it.

cnydw commented 3 years ago

The biggest challenge of this approach is actually finding a server that allows IP spoofing, almost all cloud server providers don't allow it anymore.

See: https://github.com/basil00/reqrypt/issues/7#issuecomment-327166155 https://www.mdpi.com/2073-431X/8/4/81/htm

fortuna commented 1 year ago

It's possible to achieve something similar to ReQrypt, but without the need for IP spoofing, using two TCP connections:

The connection could go like this:

  1. Client establishes a connection to IP R, and starts reading.
  2. Client establishes a connection to IP W, tells it the connection (4-tuple) where it's reading, and what the target server is.
  3. Server on IP W connects the client to the target, relaying all the stream from the client to the target. The response stream from the target is relayed over the connection on IP R

Of course this scheme wouldn't save the download bandwidth, but it may still be helpful for circumvention and mitigates issues like https://github.com/net4people/bbs/issues/129#issuecomment-1308102504.

It's also possible to make IP W and IP R be the same, but using different ports, which may be enough to fool the censor.