📜 ⬆️ ⬇️

Bypassing the DPI provider on the OpenWrt router using only busybox

image
Hello everyone, in the light of the latest news from RosKomNadzor, I decided to take a look at how my ISP is blocking. It turned out that the Google DNS does not save, and the blocking works by allocating an HTTP request to a banned site and then dropping packets found by a TCP session. However, after a little tinkering, it turned out that a single busybox is enough to bypass it. To whom it is interesting - well under the cat.



At once I will make a reservation that the implementation of the lock depends on the provider and my method may not work for you. So, we will consider the example of the well-known site rutracker.ogr (the domain and IP address in the post is changed to avoid).
I started with a simple query to see how the provider responds in general.
')
Homepage Request
 wget -O / dev / null "rutracker.ogr"
 --2016-02-10 01: 21: 18-- http: //rutracker.ogr/
 Rutracker.ogr (rutracker.ogr) is recognized ... 195.82.147.214
 Connection to rutracker.ogr (rutracker.ogr) | 195.82.147.214 |: 80 ... connection established.
 HTTP request sent.  Waiting for an answer...
Package dump
 01: 25: 10.736021 IP 192.168.5.2.53724> 195.82.147.214.80: Flags [S], seq 778021515, win 29200, options [mss 1460, sackOK, TS val 40091571 ecr 0, nop, wscale 7], length 0
 01: 25: 10.771529 IP 195.82.147.214.80> 192.168.5.2.53724: Flags [S.], seq 866160985, ack 778021516, win 14600, options [mss 1400], length 0
 01: 25: 10.771562 IP 192.168.5.2.53724> 195.82.147.214.80: Flags [.], Ack 1, win 29200, length 0
 01: 25: 10.771701 IP 192.168.5.2.53724> 195.82.147.214.80: Flags [P.], seq 1: 141, ack 1, win 29200, length 140: HTTP: GET / HTTP / 1.1
 01: 25: 11.129078 IP 192.168.5.2.53724> 195.82.147.214.80: Flags [P.], seq 1: 141, ack 1, win 29200, length 140: HTTP: GET / HTTP / 1.1
 01: 25: 11.849176 IP 192.168.5.2.53724> 195.82.147.214.80: Flags [P.], seq 1: 141, ack 1, win 29200, length 140: HTTP: GET / HTTP / 1.1
 01: 25: 13.292495 IP 192.168.5.2.53724> 195.82.147.214.80: Flags [P.], seq 1: 141, ack 1, win 29200, length 140: HTTP: GET / HTTP / 1.1

The client successfully connects, sends the request and everything. A heap of TCP resends before timeout. The DPI recognized the session and dropped it as forbidden. And then for some reason I tried to try the same thing, but through telnet.

Request telnet page
 telnet rutracker.ogr 80
 Trying 195.82.147.214 ...
 Connected to rutracker.ogr.
 Escape character is '^]'.
 GET / HTTP / 1.1
 User-Agent: Wget / 1.16.3 (linux-gnu)
 Accept: * / *
 Accept-Encoding: identity
 Host: rutracker.ogr
 Connection: Keep-Alive

 HTTP / 1.1 301 Moved Permanently
 Server: nginx
 Date: Tue, 09 Feb 2016 22:29:50 GMT
 Content-Type: text / html
 Content-Length: 178
 Location: http: //rutracker.ogr/forum/index.php
 Connection: keep-alive

 <html>
 <head> <title> 301 Moved Permanently </ title> </ head>
 <body bgcolor = "white">
 <center> <h1> 301 Moved Permanently </ h1> </ center>
 <hr> <center> nginx </ center>
 </ body>
 </ html>
Packet dump on request via telnet
 01: 33: 15.354300 IP 192.168.5.2.53782> 195.82.147.214.80: Flags [S], seq 4112340002, win 29200, options [mss 1460, sackOK, TS val 40236956 ecr 0, nop, wscale 7], length 0
 01: 33: 15.389921 IP 195.82.147.214.80> 192.168.5.2.53782: Flags [S.], seq 3472440534, ack 4112340003, win 14600, options [mss 1400], length 0
 01: 33: 15.389967 IP 192.168.5.2.53782> 195.82.147.214.80: Flags [.], Ack 1, win 29200, length 0
 01: 33: 16.226472 IP 192.168.5.2.53782> 195.82.147.214.80: Flags [P.], seq 1:17, ack 1, win 29200, length 16: HTTP: GET / HTTP / 1.1
 01: 33: 16.263181 IP 195.82.147.214.80> 192.168.5.2.53782: Flags [.], Ack 17, win 14600, length 0
 01: 33: 16.263214 IP 192.168.5.2.53782> 195.82.147.214.80: Flags [P.], seq 17: 139, ack 1, win 29200, length 122: HTTP
 01: 33: 16.298317 IP 195.82.147.214.80> 192.168.5.2.53782: Flags [.], Ack 139, win 14600, length 0                                                                                                    
 01: 33: 16.789180 IP 192.168.5.2.53782> 195.82.147.214.80: Flags [P.], seq 139: 141, ack 1, win 29200, length 2: HTTP                                                                                  
 01: 33: 16.827756 IP 195.82.147.214.80> 192.168.5.2.53782: Flags [.], Ack 141, win 14600, length 0                                                                                                    
 01: 33: 16.828043 IP 195.82.147.214.80> 192.168.5.2.53782: Flags [P.], seq 1: 383, ack 141, win 14600, length 382: HTTP: HTTP / 1.1 301 Moved Permanently                                                
 01: 33: 16.828067 IP 192.168.5.2.53782> 195.82.147.214.80: Flags [.], Ack 383, win 30016, length 0                                                                                                    
 01: 33: 20.376119 IP 192.168.5.2.53782> 195.82.147.214.80: Flags [F.], seq 141, ack 383, win 30016, length 0                                                                                          
 01: 33: 20.412142 IP 195.82.147.214.80> 192.168.5.2.53782: Flags [F.], seq 383, ack 142, win 14600, length 0                                                                                          
 01: 33: 20.412177 IP 192.168.5.2.53782> 195.82.147.214.80: Flags [.], Ack 384, win 30016, length 0                                                                                                    
 01: 33: 30.299143 IP 192.168.5.2.53780> 195.82.147.214.80: Flags [FP.], Seq 1515330593: 1515330733, ack 3791059975, win 29200, length 140: HTTP: GET / HTTP / 1.1                                        


Actually at this moment it became clear that the DPI is not so terrible as it is painted. If you look at the dumps, you can see that telnet sends the first line of the request in a separate packet. That is, DPI does not analyze the TCP stream, but the first packet with data from the client to the server and tries to collect the Url from the path and Host fields in order to punch it through the database. If the first line of the request with the path and the line with the Host field are separated into different packets, then the DPI cannot process such a session correctly and skips it.

The case remained for small. It was necessary to make a certain proxy that would break the header of the first HTTP request in the TCP session (remember Connection: Keep-Alive) into two packets, and simply send the rest through. I also wanted this proxy to work on the OpenWrt router in order to provide the entire home network. You can make such a proxy in different ways, I chose the laziest, the fastest and the most naked one, since the goal was to make exactly proof of concept, and not a boxed solution.
As a proxy, I have a shell script that runs from under tcpsvd (by default, there is no tcpsvd applet in OpenWrt's busybox, so it must be rebuilt using standard buildroot). Just in case, let me remind you that tcpsvd is such a thing that listens to the port and, when the client connects, starts the child process, redirecting its input / output to the socket.

I’ve got such a script (please don’t beat with your feet, this is just a proof of concept)

#!/bin/sh #         appendLine() { if [[ ! -z "$1" ]] then echo -ne "$1\r\n$2" else echo -ne "$2" fi } header1="" header2="" host="" while [[ true ]] do #   read -r line #     0x0D line=`echo "$line" | tr -d "\r"` #   if [[ -z "$line" ]] then break fi # ,   Host:   header1,  -  header2 if [[ -z "$host" ]] then if [[ `echo "$line" | grep -c "Host:"` -eq "1" ]] then host=`echo "$line" | sed -re 's/^Host: (.*)\r?$/\1/'` header2=`appendLine "$header2" "$line"` else header1=`appendLine "$header1" "$line"` fi else header2=`appendLine "$header2" "$line"` fi done { #    echo -ne "$header1\r\n" #  ,  netcat  ,   ,     -   sleep 1 #    echo -ne "$header2\r\n\r\n" #  , DPI  ,  -   cat 2>/dev/null } | nc "$host" 80 


Just in case, I’ll clarify that we only wait a second at the beginning of a TCP session, and since browsers usually do not disconnect a session, but continue to send requests to it, there should be no obvious brakes.

This crutch proxy runs like this:
tcpsvd 0.0.0.0 3128 ./proxy.sh


It remains only to redirect traffic from the browser to the proxy in any way. You can do this, for example, as here , but you can generate a proxy auto-detection file from the list of prohibited sites. The second option is easier, laziness won again and it turned out like this:

 { echo -e "function FindProxyForURL(url, host)\n{\n\tif (" wget "http://api.antizapret.info/group.php?data=domain" -O- | sed -re 's/^(.*)$/localHostOrDomainIs(host,"\1") || /' echo -e "false)\n{ return \"PROXY 192.168.5.1:3128\"; }\nreturn \"DIRECT\";\n}"; } > ~/antidpi.pac 


After podsovyvaniya this file in the proxy settings, banned sites began to open without question.
I would be glad if someone less lazy would make a proxy in a normal way or, if I invented a bicycle, would point to a ready-made standard solution.
That's all, thank you for your attention.

Source: https://habr.com/ru/post/276915/


All Articles