Перейти к содержимому

 Друзья: Всё для вебмастера | [ Реклама на форуме ]


Rutor
Rutor


[ DDos Услуги. DDos атака. Заказать ДДос ]


Организация работы php скрипта через socks5 сервер


  • Авторизуйтесь для ответа в теме
В этой теме нет ответов

#1
Jinn

Jinn

    Байт

  • Members
  • Pip
  • 77 сообщений
====================================================
Организация работы php скрипта через socks5 сервер
====================================================

===== Вступление =====

Я думаю у многих возникало желание организовать работу php скрипта через socks, этим повысить безопасность, обойти ограничения (не буду уточнять какие;-) У меня тоже возникала подобная проблема, поэтому я попробовал ее решить. Порыл в рунете, ничего подобного не нашел -0. Это нужно исправлять!

В данной статье я попытаюсь изложить методы работы php-скрипта через socks5-сервер. Спецификация протокола socks5 дана в RFC1928.
Все что здесь написано, тестировалось мной на домашнем компе:
* Win XP SP2
* Frenzy-lite 1.0 установленая на VMware 4.5.1 =)
* Opera 8.52
* Денвер
Для организации socks5 сервера использовалась тулза boucer, которая меня устраивает по всем параметрам:
  win : bouncer-1.0.rc6-win32
  frenzy : bouncer-1.0.rc6-freebsd-intel
Для понимания статьи вы должны иметь начальное знание пхп.

===== Описание протокола =====

Те кто знаком с протоколом могут не читать данное описание,оно является перессказом RFC.

Координальным отличием от протоколов HTTP, POP3, SMTP является что данные socks-серверу должны передаваться в бинарном виде.
Для работы через сокс для начала нам нужно к нему подключиться(верх логики=))
После чего отправить пакет:
   *  VER	   версия протокола,для socks5 == 05, socks4 == 04
   *  NMETHODS  содержит число октетов в идентификаторах методов авторизации
   *  METHODS   метод авторизации(см.дальше)

На что сокс должен вам ответить:
   *  VER	   версия протокола,для socks5 == 05
   *  METHODS   метод авторизации:
	  *  00		аутентификация не требуется
	  *  01		GSS-API (см. RFC1961)
	  *  02		USERNAME/PASSWORD (см. RFC1929)
	  *  03 до 7F  зарезервировано IANA
	  *  80 до FE  предназначено для частных методов
	  *  FF		нет применимых методов
Если в поле метода выставлено FF, то соединение должно быть разорвано, ни один из методов не удовлетворяет сервер (вот такой он привередливый=)).
Т.к сокс отправляет свою версию, это можно использовать в чекерах проксей, на определение соксовых.

Далее следуют запросы к серверу. Они бывают трех видов:
* Connect
* Bind
* Udp associate
Мы рассмотрим Connect, как требующийся наиболее часто.

---- Запросы && Ответы ----

ЛЮБОЙ запрос должен состоять из данных полей:
	*  VER версия протокола: 05
	*  CMD
	   *  01 CONNECT - он нам и нужен
	   *  02 BIND
	   *  03 UDP ASSOCIATE
	*  RSV	зарезервировано
	*  ATYP   тип адреса, следующего вида:
	   *  01  IP v4 адрес
	   *  03  имя домена, мы будем использовать именно этот метод, т.к это более универсально, можно передавать и IPv4 (как выяснилось) и имя домена. При передаче пакета с полем ATYP равном 01 у меня возникали проблемы.
	   *  04  IP v6 адрес
	*  DST.ADDR требуемый адрес
	*  DST.PORT требуемый порт (в сетевом порядке октетов)
Значения зарезервированных (RSV) полей должны быть установлены в 00.
На что socks-сервер должен бут ответить:
	*  VER	  версия протокола: 05
	*  REP	  код ответа:
	   *  00	  успешный
	   *  01	  ошибка SOCKS-сервера
	   *  02	  соединение запрещено набором правил
	   *  03	  сеть недоступна
	   *  04	  хост недоступен
	   *  05	  отказ в соединении
	   *  06	  истечение TTL
	   *  07	  команда не поддерживается
	   *  08	  тип адреса не поддерживается
	   *  09 - FF не определены
	*  RSV	  зарезервирован
	*  ATYP	 тип последующего адреса
	   *  01	  IP v4 адрес
	   *  03	  имя домена
	   *  04	  IP v6 адрес
	*  BND.ADDR выданный сервером адрес
	*  BND.PORT выданный сервером порт (в сетевом порядке октетов)

При получении ответа с сообщением об удаче, клиент может начинать передавать данные. Если выбраная схема аутентификации требует особое формирование пакетов, то данные должны инкапсулироваться в пакет, формат которого определяется данным методом аутентификации. Socks-сервер, тоже, должен инкапсулировать данные для клиента согласно согласно тому, как этого требует выбранная схема аутентификации.

===== Кодим =====

Я ставил перед собой задачу не написать какой-то полезный всем скрипт, а просто рассмотреть работу с соксом, без авторизации (пока)
Вот алгоритм нашего скрипта:
  * подключиемся к соксу
  * проверяем версию сокса (05 в нашем случае) и метод авторизации(без нее - 00)
	* отправляем пакет для коннекта, я пробовал сначала все на локалхосте, после на www.yandex.ru
	* проверяем поле REP,что все прошло успешно....
	  * начинаем передавать данные..произвольные.Т.к в этой статье мы рассматриваем схему без аутентификации, то мы будем передавать данные в том формате, в котором они должны доставлены нашему HTTP-серверу.
	  * получаем ответ сервера (www.yandex.ru)
  * закрываем соединение

Как сказал наш первый космонавт.....Поехали -)

Т.к данные соксу должны передаваться в бинарном виде, то напишем небольшую функцию, которая берет по 2 символа и возвращает по ASCII коду его символ, для этого воспользуемся ф-цией chr & dechex. Некоторые скажут что можно было использовать pack('H*',строка), но сейчас при изучении протокола (а цель данной статьи именно это) будет полезнее передавать данные таким методом, потом же уже в готовом коде можно заменить данный код ф-цией php pack("H*",строка):
<?
 function hex2bin($dump)
 {
  $dump=str_replace(' ', '', $dump); // вырезаем пробелы 
  $res='';
  for ($i=0; $i<=strlen($dump); $i+=2)
  {
   $bt=$dump[$i].$dump[$i+1];
   $res=$res.chr(hexdec($bt)); // переводим в dec и возвращаем символ по ascii коду
  }
  return $res;
 }
?>
И функцию для перевода в hex,она будет использоваться при переводе в hex нецифровых данных(например доменного имени). Сначала мы должны получить ascii код каждого символа а после перевести его в dec. Для удобства я делаю с пробелами, т.к с ними удобнее при отладке и приятнее глазу, а они все равно вырезаются при переводе в бинарный режим. После же можно будет преобразовать ф-цию без пробелов => код сократится)
<?
 function hex($dump)
 {
  $res='';
  for($i=0; $i<strlen($dump); $i++)
  {
   if($i+1==strlen($dump)){$res=$res.dechex(ord($dump[$i]));} else {$res=$res.dechex(ord($dump[$i]))." ";}
  }
  return $res;
 }
?>
Мы должны передовать длину хоста, которому мы в последствии будем передавать данные, в шестнадцатиричной системе счисления. Переводить в шестнадцатиричный режим мы будем с помощью dechex(). Но как известно число 4 в десятиричной - 4 в шестнадцатиричной, но нам то нужно чтобы оно было 04, а dechex возвращает 4. Поэтому я написал  небольшую функцию для исправления таких случаев:
<?
 function len_test($dump)
 {
   if(strlen($dump)==1) {$dump="0".$dump;}
   return $dump;
 }
?>
Она проверяет длину переменной на кол-во символов, если она равно 1, то добавляется впереди 0. В принципе можно было не выносить это в функцию, но при постоянных экспериментах она сильно пригодится. Хотя можно сделать совершенно не так, но другой способ я покажу в своей следующей статье)
Для перевода ответа сокса в hex будет использоваться ф-ция php bin2hex().
Далее будет идти код с подробными коментариями:
<?
error_reporting(1);
echo '<meta http-equiv="Content-Language" content="ru"><meta http-equiv=Content-Type content="text/html; charset=windows-1251">';

$ip="192.168.177.1"; // ip socks5
$port=1080; // порт сокса

$connect_host='192.168.177.1'; // адрес или ip  которому мы будем посылать данные через сокс-сервер =)
$connect_port=80;  // порт 

$socks=fsockopen($ip,$port);
if ($socks)
{
  $h=hex2bin('05 01 00'); // передаем версию сокса , кол-во методов аутентификации и методы аутентификации
  fwrite($socks,$h);
  $list=bin2hex(fread($socks,2));// переводим ответ сокса в нормальный hex'овый вид
   // проверяем на версию и метод аутентификации, я не стал заморачивться,но можно сделать проверку без перевода в hex а примерно вот так:
	/*  пример проверки на соотвествие версии и методу авт-ции.
			   $bb=fread($socks,2);
			   if ( $bb==hex2bin( '0500' )  )
				{
				   .......................
				}
			 вариантов много :) 
		  */
// проверяем метод аутентификации
  if ($list == '0500')
   {
	 $list="";
	 $len=dechex(strlen($connect_host)); // длина адреса,переводится в шестнадцатиричный режим
	 $len=len_test($len);
	 $h=hex2bin("05 01 00 03 $len ".hex($connect_host)." 00 ".dechex($connect_port).""); //формируем запрос ,в принципе нужно было бы и длину портав шестнадцатиричной сисетме счисления проверить, но это нужно только от 1 до 9 порта, но на таких я думаю поднимать не будут сокс :-)
	 fwrite($socks,$h);

	 $l=bin2hex(fread($socks,1024));

	 if ($l[3] == '0')
	 {
	   // формируем запрос ,который будет отправлен, через сокс,  серверу (  в нашем случае http - www.yandex.ru)
		$head  = "GET / HTTP/1.0\r\n";
		$head .= "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 8.52\r\n";
		$head .= "Host: www.yandex.ru\r\n";
		$head .= "Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1\r\n";
		$head .= "Accept-Language: ru,en;q=0.9\r\n";
		$head .= "Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1\r\n";
		$head .= "Proxy-Connection: close\r\n\r\n";
		fwrite($socks,$head);
		// считываем ответ HTTP-сервера через SOCKS-сервер  до конца  =)
		while(!feof($socks))
		{
		  $l=fread($socks,1024);
		  echo $l;
		}
	 }
	 // определяем ошибку! данные коды ответа взяты из RFC
	 elseif ($l[3] == '1') {echo "<center><font color=red>Ошибка: SOCKS-сервера</font></center>";}
	 elseif ($l[3] == '2') {echo "<center><font color=red>Ошибка: соединение запрещено набором правил</font></center>";}
	 elseif ($l[3] == '3') {echo "<center><font color=red>Ошибка: сеть недоступна</font></center>";}
	 elseif ($l[3] == '4') {echo "<center><font color=red>Ошибка: хост недоступен</font></center>";}
	 elseif ($l[3] == '5') {echo "<center><font color=red>Ошибка: отказ в соединении</font></center>";}
	 elseif ($l[3] == '6') {echo "<center><font color=red>Ошибка: истечение TTL</font></center>";}
	 elseif ($l[3] == '7') {echo "<center><font color=red>Ошибка: команда не поддерживается</font></center>";}
	 elseif ($l[3] == '8') {echo "<center><font color=red>Ошибка: тип адреса не поддерживается</font></center>";}
	 else {echo "<center><font color=red>Ошибка: не определено!</font></center>";}
  }
  else
  {
	echo "<center><font color=red>Ошибка:возможно это не socks5 или он не поддерживает метод без аутентификации(!</font></center>";
  }
  fclose($socks);
}
else
{
  echo "<center><font color=red>SOCKS сервер недоступен!</font></center>";
}
echo "<br><br><center><font size=1 color='#292929'>c0ded by <b>Jinn</b> | Zaeb.us </font></center>"; //автора не забудьте указать =)
?>

В данном примере ответ HTTP-сервера (www.yandex.ru) выводится в браузер и не обрабатывается им. При желании написать разделение ответа и контента не сложно, нужно разделять по конструкции:"\r\n\r\n". После чего отправлять браузеру ответ HTTP сервера с помощью header(). Но все это я не стал делать, потому что данный скрипт написан только для демострации работы с соксами. И делать это смысла нет, потому что мало кто будет использовать этот скрипт(если вообще кто бут=)) все зависит от данных которые вы обрабатывате:-)

Возможное расширения скрипта:
- работа не только с 5 версией, но и с 4, но для этого нужно изучить этот протокол. RFC я думаю рулит=)
- работа не только без авторизации, но и с поддержкой ее, для этого нужно изучить эти методы, они описаны в RFC. Надеюсь в скором времени я этим займусь=) напишу статью, если все получится;-)

===== Заключение =====

Нельзя сказать что мы изучили протокол, до этого еще далеко. Но во всяком случае теперь мы(я точно) представляю себе как идет взаимодействие с соксами.
Надеюсь, что не один я узнал что-то новое, кому-то может даже помог:-)

:: Jinn :: 304227033 :: ZaeB.uS :: ]]>http://zaeb.us]]> ::



--[ ZaeB.uS, ]]>http://zaeb.us]]> ]---
ICQ: 304227033
Jabber: jinn@jabber.prologic.ws
OCC: 82623


Количество пользователей, читающих эту тему: 0

0 пользователей, 0 гостей, 0 анонимных