NokitaKaze icon

Проксик для для заворачивания пакетов в HTTP-connect запросы

NokitaKaze | PRO | 04/30/16 10:46:46 AM UTC | 0 ⭐ | 326 👁️ | Never ⏰ | []
PHP |

8.89 KB

|

None

|

0 👍

/

0 👎

#!/usr/bin/php
<?php
    /**
     * Штука для перехвата HTTP/HTTPS-пакетов на линух-сервере и отправки их
     * на какой-нибудь MITM-прокси типа mitmproxy или Fiddler
     *
     * Запускать так
     *
     * На хост-машине
     * echo 1 > /proc/sys/net/ipv4/ip_forward
     * iptables -F -t nat
     * iptables -t nat -A PREROUTING -i eth0 -p tcp -j REDIRECT --dport 443 --to-ports 8443
     * iptables -t nat -A PREROUTING -i eth0 -j ACCEPT
     *
     * Потом
     * ./proxy_to_api.php -p 8443
     * ./proxy_to_api.php -p 8080 --no-ssl
     *
     * На windows-клиенте
     * route add 93.184.216.34 mask 255.255.255.255 192.168.1.14 metric 1
     *
     * Не забудьте включить на Fiddler'е "принимать подключения из вне", а на клиенте — импортнуть рутовый сертификат
     */
    $options = getopt('d:p:', array(
        'no-ssl'
    ));
    $domain = array_key_exists('d', $options) ? $options['d'] : 'example.com';
    $port = array_key_exists('p', $options) ? (int) $options['p'] : 8443;
    $ssl_enabled = !array_key_exists('no-ssl', $options);
 
    $input_server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    if ($input_server === false) {
        echo "can not spawn socket\n";
 
        return;
    }
 
    if (@socket_bind($input_server, '0.0.0.0', $port) === false) {
        echo "can not bind socket: ".socket_strerror(socket_last_error($input_server))."\n";
 
        return;
    }
 
    if (@socket_listen($input_server, 5) === false) {
        echo "can not listen socket: ".socket_strerror(socket_last_error($input_server))."\n";
 
        return;
    }
 
    $our_proxy = gethostbyname('192.168.1.16');
    $real_api_ip = gethostbyname($domain);
    socket_set_nonblock($input_server);
    /**
     * @var resource[][] $socket_pairs
     */
    $socket_pairs = array();
    $start_session_time = time();
 
    while (true) {
        // Принимаем подключения
        $input_socket = @socket_accept($input_server);
        if ($input_socket !== false) {
            echo "CONNEСT\n";
            $output_socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
            $result = socket_connect($output_socket, $our_proxy, 8888);// Порт поменять, это до Фиддлера
            if ($result === false) {
                socket_shutdown($output_socket);
                socket_close($output_socket);
                socket_shutdown($input_socket);
                socket_close($input_socket);
                continue;
            }
            if ($ssl_enabled) {
                $first_packet_bytes = @socket_recv($input_socket, $first_packet_buf, 2048, 0);
                if (!preg_match('_([a-z0-9.-]{5,})_i', $first_packet_buf, $a)) {
                    echo "First input ssl packet malformed\n";
                    continue;
                }
                $real_domain = $a[1];
 
                $init_string = "CONNECT {$real_domain}:443 HTTP/1.1\n".
                               "HOST: {$real_domain}\n\n";
                socket_write($output_socket, $init_string, strlen($init_string));
                $full_buf = '';
                while (!preg_match('_\\r\\n\\r\\n_', $full_buf)) {
                    $bytes = @socket_recv($output_socket, $buf, 1000, 0);
                    $full_buf .= $buf;
                    if ($bytes == 0) {
                        echo "Connect-proxy malformed answer\n";
                        socket_shutdown($output_socket);
                        socket_close($output_socket);
                        socket_shutdown($input_socket);
                        socket_close($input_socket);
                        continue 2;
                    }
                }
                $a = explode("\r\n\r\n", $full_buf, 2);
                if (!preg_match('_^HTTP/1\\.[01] ([0-9]+) _', $a[0], $b)) {
                    echo "Can not establish properly proxy connect\n";
                    socket_shutdown($output_socket);
                    socket_close($output_socket);
                    socket_shutdown($input_socket);
                    socket_close($input_socket);
                    continue;
                } elseif ($b[1] != 200) {
                    echo "Can not establish properly proxy connect. HTTP Status {$b[1]}\n";
                    socket_shutdown($output_socket);
                    socket_close($output_socket);
                    socket_shutdown($input_socket);
                    socket_close($input_socket);
                    continue;
                }
 
                if ($first_packet_bytes > 0) {// Что очевидно, иначе бы сюда код не пришёл
                    socket_write($output_socket, $first_packet_buf, $first_packet_bytes);
                }
                if (strlen($a[1]) > 0) {
                    socket_write($input_socket, $a[1], strlen($a[1]));
                }
 
                echo "CONNEСT #".count($socket_pairs)." ESTABLISHED TO {$real_domain}\n";
                unset($first_packet_buf, $first_packet_bytes, $a, $full_buf, $bytes);
                $socket_pairs[] = array($input_socket, $output_socket, $real_domain);
            } else {
                $socket_pairs[] = array($input_socket, $output_socket);
            }
            unset($input_socket, $output_socket);
        }
 
        // Обрабатываем подключения (кидаем пакеты)
        foreach ($socket_pairs as $pair_id => &$pair) {
            if ($pair === null) {
                continue;
            }
 
            $r = array($pair[0]);
            $count = socket_select($r, $write = null, $except = null, 0);
            if ($count === false) {
                socket_shutdown($pair[1], 2);
                socket_close($pair[1]);
                socket_shutdown($pair[0], 2);
                socket_close($pair[0]);
                $pair = null;
                echo "!{$pair_id}\tclose, I, count=false\n";
                continue;
            } elseif ($count > 0) {
                $bytes = @socket_recv($pair[0], $buf, 2048, 0);
                if ($bytes == 0) {
                    socket_shutdown($pair[1], 2);
                    socket_close($pair[1]);
                    socket_shutdown($pair[0], 2);
                    socket_close($pair[0]);
                    $pair = null;
                    echo "!{$pair_id}\tclose, I, bytes=0\n";
                    continue;
                }
                echo "!I{$pair_id}\t{$bytes}\n";
                file_put_contents("/root/pta-{$start_session_time}-{$pair_id}-".microtime(true).'-i.dat', $buf);
                socket_write($pair[1], $buf, $bytes);
            }
 
            $r = array($pair[1]);
            $count = socket_select($r, $write = null, $except = null, 0);
            if ($count === false) {
                socket_shutdown($pair[1], 2);
                socket_close($pair[1]);
                socket_shutdown($pair[0], 2);
                socket_close($pair[0]);
                $pair = null;
                echo "!{$pair_id}\tclose, O, count=false\n";
                continue;
            } elseif ($count > 0) {
                $bytes = @socket_recv($pair[1], $buf, 2048, 0);
                if ($bytes == 0) {
                    socket_shutdown($pair[1], 2);
                    socket_close($pair[1]);
                    socket_shutdown($pair[0], 2);
                    socket_close($pair[0]);
                    $pair = null;
                    echo "!{$pair_id}\tclose, O, bytes=0\n";
                    continue;
                }
                echo "!O{$pair_id}\t{$bytes}\n";
                file_put_contents("/root/pta-{$start_session_time}-{$pair_id}-".microtime(true).'-o.dat', $buf);
                socket_write($pair[0], $buf, $bytes);
            }
 
            $except = array($pair[1], $pair[0]);
            $count = socket_select($read = null, $write = null, $except, 0);
            if ($count === false) {
                socket_shutdown($pair[1], 2);
                socket_close($pair[1]);
                socket_shutdown($pair[0], 2);
                socket_close($pair[0]);
                $pair = null;
                echo "!{$pair_id}\tclose, E, count=false\n";
                continue;
            } elseif ($count > 0) {
                echo "!E{$pair_id}\n";
                socket_shutdown($pair[1], 2);
                socket_close($pair[1]);
                socket_shutdown($pair[0], 2);
                socket_close($pair[0]);
                $pair = null;
                echo "!{$pair_id}\tclose, E, count>0\n";
                continue;
            }
        }
    };
 
    socket_shutdown($input_server, 2);
    socket_close($input_server);
 
?>

Comments