Работа с цепочкой Socks-проксей.

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by TaNkist, 19 Oct 2006.

  1. TaNkist

    TaNkist Elder - Старейшина

    Joined:
    6 Apr 2006
    Messages:
    147
    Likes Received:
    47
    Reputations:
    19
    Работа с цепочкой SOCKS-проксей.

    Не мне тебе объяснять, что значит анонимность для хакера. Ты, наверное, не раз задумывался о лучшем способе ее сохранения. Не самый лучший, но, безусловно, самый популярный – это использование цепочки SOCKS-серверов. Ведь если хотя бы одно звено-сервер из этой цепи не пишет логов, то у взломщика остаются неплохие шансы сохранить анонимность.
    Итак, как ты уже догадался сегодня мы познакомимся с работой по передаче данных в цепочке SOCKS-проксей. Для того чтобы Socks-сервер соединился с нужным нам сайтом необходимо указать адрес сайта и его порт. Но сначала придется поприветствовать сервер и пройти аутентификацию (она не обязательна, и на большинстве анонимных соксах отсутствует).
    [Приветствие] На этом этапе нужно отправить специальный пакет:
    • 1 байт – номер версии
    • 1 байт – количество методов (N)
    • N байт – перечисление методов

    Т.к. мы будем работать с соксами 5 версии, то нужно послать $05, следующий байт – число поддерживаемых методов соединения / аутенфикации. За ним последовательность байт, описывающих эти самые методы. Мы не будем заморачиваться с аутенфикацией, поэтому напишем тут 00.
    На это приветствие сокс отвечает двумя байтами: номером своей версии и выбранным методом. Если соксу ничего не понравилось, то второй байт будет равняться $FF, если мы получим $00, то можно смело продолжить работу.
    [Соединение] на следующем этапе мы должны указать серверу с кем соединиться. Для этого нужно отправить такой пакет.
    • 1 байт – номер версии
    • 1 байт – команда
    • 1 байт – зарезервировано до лучших времен
    • 1 байт – тип адреса
    • N байт – адрес
    • 2 байта – порт

    Для заполнения этого пакета я создал специальную структуру:
    PHP:
      request record  
        version
    :byte;
        
    cmd:byte;
        
    null:byte;
        
    typeofaddr:byte;
        
    addr:integer;
        
    port:word;
        
    end;
    Байт команды у нас будет равен $01, это значит, что мы просто хотим соединиться (о других значениях следует прочитать в RFC).
    Следующий байт всегда равен нулю.
    Типом адреса может быть:
    • $01 – ip v4 адрес, заданный 4 байтами
    • $03 – Нерезолвленное имя хоста (всегда лучше резолвить удаленно, т.к. иначе ты можешь пропалить свой DNS-сервер).
    • $04 –ip v6 адрес

    На это сокс-сервер вернет пакет той же структуры, но с другими значениями. Например. нерезолвленный хост станет ip-шником.
    Если все прошло нормально, то socks переходит в прозрачный режим и начинает передовать все данные по адресу.
    [Составляем цепочку] Теперь на практике разбирем, то о чем говорилось выше и реализуем минимальный функционал socks-клиента.
    Информацию о соксах будем хранить в следующей структуре.
    PHP:
    server record  
        ip
    :integer;
        
    port:word
        
    end
    Нужно заполнить структуру SockAddrIn, указав данные о первом соксе.
    PHP:
    SockAddrIn.sin_addr.S_addr:=socks[0].ip;
          
    SockAddrIn.sin_port:=Socks[0].port;
    Коннектимся к первому серверу
    PHP:
    connect(FSocket,SockAddrIn,SizeOf(SockAddrIn));
    Затем в цикле запускаем коннект к следующем соксам.
    PHP:
    For i:=1 to sockcount do
        
    begin
        send
    (Fsocket,hello,SizeOf(hello),0);
        
    recv(FSocket,ans,Sizeof(ans),0);
        if (
    ans[0]<>$05) or (ans[1]<>$FFthen halt;
        
    //Заполняем структуру req
        
    req.version:=$05;
        
    req.cmd:=$01;
        
    req.null:=0;
        
    req.typeofaddr:=$01;
        
    req.addr:=socks[i].ip;
        
    req.port:=socks[i].port;
        
    send(Fsocket,req,sizeof(req),0);
        
    recv(Fsocket,req,sizeof(req),0);
        
    end;
    Вот мы и написали в общем-то нехитрый код для работы с SOCKS-проксями. Для более подробного изучения рекомендую прочитать RFC 1928, в котором описан протокол SOCKS 5. Напоследок, я выложу полный исходный код со всеми подробными комментариями.
    PHP:
    program Sock5clinet;

    uses
      Windows
    ,
      
    WinSock;

    type server record   //Структура для описания адресов соксов
        
    ip:integer;//ip-адрес
        
    port:word//порт
        
    end;
        
    request record  // Пакет для соединения с сервером
        
    version:byte;     // номер версии
        
    cmd:byte;         // команда
        
    null:byte;        // зарезервировано до лучших времен
        
    typeofaddr:byte;  // тип адреса
        
    addr:integer;     // адрес
        
    port:word;        // порт
        
    end;



    var
        
    socks:array [0..4of server;
        
    FSocket:Tsocket;
        
    WSAData:TWSADATA;

    procedure connecttoSocks(sockcount:integer);
    var
        
    i:byte;
        
    ans:array[0..1of byte//Буфер для ответов сервера
        
    SockAddrInTSockAddrIn;
        
    hello:array [0..2]of char;//Буфер приветсвия
        
    req:request;  //Структура в которой содержиться запрос на соединение
    begin
      hello
    :=#050100;//Последовательность байт 05, 01, 00
      
    SockAddrIn.sin_addr.S_addr:=socks[0].ip;
      
    SockAddrIn.sin_port:=Socks[0].port;
      
    connect(FSocket,SockAddrIn,SizeOf(SockAddrIn));
      For 
    i:=1 to sockcount do
        
    begin
        send
    (Fsocket,hello,SizeOf(hello),0);
        
    recv(FSocket,ans,Sizeof(ans),0);
        if (
    ans[0]<>$05) or (ans[1]<>$FFthen halt;
        
    //Заполняем структуру req
        
    req.version:=$05;
        
    req.cmd:=$01;
        
    req.null:=0;
        
    req.typeofaddr:=$01;
        
    req.addr:=socks[i].ip;
        
    req.port:=socks[i].port;
        
    send(Fsocket,req,sizeof(req),0);
        
    recv(Fsocket,req,sizeof(req),0);
        
    end
    end;


    begin

    //Первый сокс
    socks[0].ip:=inet_addr('127.0.0.1');
    socks[0].port:=htons(80);
    //Второй сокс
    socks[1].ip:=inet_addr('127.0.0.1');
    socks[1].port:=htons(81);
    //Третий сокс
    socks[2].ip:=inet_addr('127.0.0.1');
    socks[2].port:=htons(82);
    //Четвертый сокс
    socks[3].ip:=inet_addr('127.0.0.1');
    socks[3].port:=htons(83);
    //Хост куда нужно подключиться
    socks[4].ip:=inet_addr('127.0.0.1');
    socks[4].port:=htons(110);
    //Инициализируем WinSock
    WSAStartUp($202,WSAData);
    //Подготавляиваем сокет
    FSocket:=socket(PF_INETSOCK_STREAMIPPROTO_TCP);
    //Соединяемся по цепочке соксов с нужным хостом
    connecttoSocks(4);

    end.
     
    1 person likes this.