к.т.н., доцент Пархоменко И.И., Остапчук А.В.,

Национальный авиационный университет, Украина

HTTP туннелирование - взгляд изнутри

          На данный момент, защищенная и анонимная передача информации играет важную  роль в жизни не только пользователей интернета, но и в особенности, крупных компаний.

Web server - превосходная мишень для атаки. Именно с такого сервера можно начать свое путешествие вглубь сети, даже не взирая на то, если он защищен файрволом. Тут нам на помощь и приходит HTTP туннелирование.

HTTP туннелирование позволяет клиенту инкапсулировать трафик в HTTP заголовки. Затем трафик направляется к серверу на другом конце канала и там пакеты программой обрабатываются обратно, извлекаются данные из заголовков, и только потом уже редактируются к своей конечной цели. По такой схеме можно передавать как UDP, так и ТСР данные, это обусловлено самой природой туннелирования.

          В RFC 2616 (HTTP 1.1) описаны следующие методы: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT.

О методе CONNECT можно сказать следующее: "Спецификация резервирует имя метода CONNECT для использования с прокси, которые могут динамически переключаться на работу в качестве туннеля (например, туннелирование SSL)".                    Теперь собственно о том, как это работает.

1. Клиент соединяется с HTTP Proxy, поддерживающим метод CONNECT.
2. Клиент посылает серверу строку вида "CONNECT target_host:target_port HTTP/1.x\r\nUser-Agent: User Agent\r\n"
3. В ответ на эту строку сервер может либо потребовать авторизацию, либо вернуть состояние удачного соединения либо ошибку.
          Открытый тунель может использоваться не только как клиент-прокси канал, но и как прокси-прокси канал.

Код будет иметь следующий вид:
int len;
char buff[BUFF_SIZE];
bzero (buff,sizeof(buff));
sprintf(buff, "CONNECT %s:%d HTTP/1.0\r\nUser-Agent: ProxyChains 1.8\r\n", inet_ntoa( * (struct in_addr *) &ip), ntohs(port));
len = strlen (buff);
if(len!=send(sock,buff,len,0))
return SOCKET_ERROR;
//
bzero(buff,sizeof(buff));
len=0 ;
while(len<BUFF_SIZE)
{
if(1==read_n_bytes(sock,buff+len,1))
len++;
else
return SOCKET_ERROR;
if ( len > 4 &&
buff[len-1]=='\n' &&
buff[len-2]=='\r' &&
buff[len-3]=='\n' &&
buff[len-4]=='\r' ) break;
}
// если ответ не 200, значит либо порт закрыт, либо хост мертв
if ( (len==BUFF_SIZE) ||
! ( buff[9] =='2' &&
buff[10]=='0' &&
buff[11]=='0' )) return BLOCKED;
return SUCCESS;
          В конечном результате получаем туннель, который можно интерпретировать как обычное соединение с target_host:target_port.