------------------------------------------------
#!/usr/share/doc/defaced/3/tandp/phpportscan.txt
------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
//
// Тема.......PHP и сокеты. Пишем сканер портов на PHP
// Автор......black c0de
// Группа.....[the nobodies] //[tN] 
// [email protected]
// HTTP.......http://nteam.ru/
// DATE.......11.10.03
//
// 
// # Все права принадлежат [the nobodies]
// # любое распространение возможно только с сохранением копирайтов и т.д. и т.п.
//
//
////////////////////////////////////////////////////////////////////////////////


//===( 0x0 :: Содержание )=====================================================


[0x0] Содержание
[0x1] Предисловие
[0x2] Механизм сокетов и PHP
[0x3] Функций для работы с сокетами
[0x4] Преопределенные константы
[0x5] Принцип написания сканера портов. Начнем с алгоритма.
[0x6] Пишем портскан
[0x7] Полезные советы и хинты
[0x8] Исходник
[0x9] Линки на полезные ресурсы
[0xA] greetZ


//===( 0x1 :: Предисловие )=====================================================

В  данной  статье  будет  продемонстрирована  работа с сокетами в PHP. PHP имеет
очень  мощный  набор  функций, который позволяет проделывать уникальные вещи. Но
как  показывает практика - при работе используют только 80% мощности этого языка
кодинга.  Одна из причин такой фигни - мало кто знаком со всеми прелестями языка
в  полной  мере, то есть человек знает что можно делать А, Б и В - остальное ему
пох.  Конечно,  для того чтобы заработать денег или наполнить штаны радостью ему
этого может хватать. Но мы же не из таких, верно? ;)
Как говориться - карта не территория, потому если за что-то беремся - делаем это
максимально  эффективно,  это  залог успешности по жизни вообще. Так вот, в этой
статье  я  опишу  работу  с механизмом сокетов на примере написания продвинутого
сканера портов с гибким конфигурированием.


//===( 0x2 :: Механизм сокетов и PHP )==========================================

Механизм  работы с сокетами в PHP основывается на всем известных Berkley sockets
Это  наилучшая реализация сокетного движка, совместимая как с unix так и с win32
Единственное  серьезное  отличие  - более высокий уровень доступа к ресурсам для
программиста.  То  есть все намного проще нежели в реализации для того же C/C++.
Вам не нужно заботиться о заполнении разных структур, вызывать некоторые функции
для  промежуточных  шагов.  При всем этом PHP предоставляет очень! широкий набор
функций для работы непосредственно с сокетами.


//===( 0x3 :: Функций для работы с сокетами )===================================

Многие из этих функций не документированы и известны лишь параметры. Потому если
вас  что-то из этого заинтересует - вперед на php.net и читайте последнюю версию
мануала на тему Socket functions

socket_accept -- Accepts a connection on a socket
resource socket_accept ( resource socket)

socket_bind -- Binds a name to a socket
bool socket_bind ( resource socket, string address [, int port])

socket_clear_error -- Clears the error on the socket or the last error code
void socket_clear_error ( [resource socket])

socket_close -- Closes a socket resource
void socket_close ( resource socket)

socket_connect -- Initiates a connection on a socket
bool socket_connect ( resource socket, string address [, int port])

socket_create_listen -- Opens a socket on port to accept connections 
resource socket_create_listen ( int port [, int backlog])

socket_create_pair  --  Creates  a  pair of indistinguishable sockets and stores
them in fds.
bool socket_create_pair ( int domain, int type, int protocol, array &fd)

socket_create -- Create a socket (endpoint for communication)
resource socket_create ( int domain, int type, int protocol)

socket_get_option -- Gets socket options for the socket 
mixed socket_get_option ( resource socket, int level, int optname)

socket_getpeername  --  Queries  the  remote  side of the given socket which may
either result in host/port or in a UNIX filesystem path, dependent on its type.
bool socket_getpeername ( resource socket, string &addr [, int &port])

socket_getsockname  --  Queries  the  local  side  of the given socket which may
either result in host/port or in a UNIX filesystem path, dependent on its type.
bool socket_getsockname ( resource socket, string &addr [, int &port])

socket_iovec_add -- Adds a new vector to the scatter/gather array 
bool socket_iovec_add ( resource iovec, int iov_len)

socket_iovec_alloc  --  ...])  Builds  a  'struct  iovec'  for use with sendmsg,
recvmsg, writev, and readv
resource socket_iovec_alloc ( int num_vectors [, int ])

socket_iovec_delete -- Deletes a vector from an array of vectors 
bool socket_iovec_delete ( resource iovec, int iov_pos)

socket_iovec_fetch   --  Returns  the  data  held  in  the  iovec  specified  by
iovec_id[iovec_position]
string socket_iovec_fetch ( resource iovec, int iovec_position)

socket_iovec_free -- Frees the iovec specified by iovec_id 
bool socket_iovec_free ( resource iovec)

socket_iovec_set -- Sets the data held in iovec_id[iovec_position] to new_val 
bool socket_iovec_set ( resource iovec, int iovec_position, string new_val)

socket_last_error -- Returns the last error on the socket 
int socket_last_error ( [resource socket])

socket_listen -- Listens for a connection on a socket
bool socket_listen ( resource socket [, int backlog])

socket_read -- Reads a maximum of length bytes from a socket
string socket_read ( resource socket, int length [, int type])

socket_readv  --  Reads  from  an  fd, using the scatter-gather array defined by
iovec_id
bool socket_readv ( resource socket, resource iovec_id)

socket_recv -- Receives data from a connected socket 
int socket_recv ( resource socket, string &buf, int len, int flags)

socket_recvfrom -- Receives data from a socket, connected or not 
int  socket_recvfrom  ( resource socket, string &buf, int len, int flags, string
&name [, int &port])

socket_recvmsg   --   Used   to   receive   messages   on   a   socket,  whether
connection-oriented or not
bool  socket_recvmsg  (  resource  socket,  resource  iovec, array &control, int
&controllen, int &flags, string &addr [, int &port])

socket_select  --  Runs  the select() system call on the given arrays of sockets
with a timeout specified by tv_sec and tv_usec
int  socket_select  (  resource  &read,  resource  &write, resource &except, int
tv_sec [, int tv_usec])

socket_send -- Sends data to a connected socket 
int socket_send ( resource socket, string buf, int len, int flags)

socket_sendmsg  --  Sends  a  message  to  a socket, regardless of whether it is
connection-oriented or not
bool socket_sendmsg ( resource socket, resource iovec, int flags, string addr [,
int port])

socket_sendto -- Sends a message to a socket, whether it is connected or not 
int socket_sendto ( resource socket, string buf, int len, int flags, string addr
[, int port])

socket_set_nonblock -- Sets nonblocking mode for file descriptor fd 
bool socket_set_nonblock ( resource socket)

socket_set_option -- Sets socket options for the socket
bool socket_set_option ( resource socket, int level, int optname, mixed optval)

socket_shutdown -- Shuts down a socket for receiving, sending, or both. 
bool socket_shutdown ( resource socket [, int how])

socket_strerror -- Return a string describing a socket error
string socket_strerror ( int errno)

socket_write -- Write to a socket
int socket_write ( resource socket, string buffer [, int length])

socket_writev -- Writes to a file descriptor, fd, using the scatter-gather array
defined by iovec_id
bool socket_writev ( resource socket, resource iovec_id)


//===( 0x4 :: Преопределенные константы )=======================================

Иногда  сигнатуре  функций  встречается  параметр type, вот там и пользуются эти
константы зачастую.

AF_UNIX (integer)
AF_INET (integer)
AF_INET6 (integer)
SOCK_STREAM (integer)
SOCK_DGRAM (integer)
SOCK_RAW (integer)
SOCK_SEQPACKET (integer)
SOCK_RDM (integer)
MSG_OOB (integer)
MSG_WAITALL (integer)
MSG_PEEK (integer)
MSG_DONTROUTE (integer)
SO_DEBUG (integer)
SO_REUSEADDR (integer)
SO_KEEPALIVE (integer)
SO_DONTROUTE (integer)
SO_LINGER (integer)
SO_BROADCAST (integer)
SO_OOBINLINE (integer)
SO_SNDBUF (integer)
SO_RCVBUF (integer)
SO_SNDLOWAT (integer)
SO_RCVLOWAT (integer)
SO_SNDTIMEO (integer)
SO_RCVTIMEO (integer)
SO_TYPE (integer)
SO_ERROR (integer)
SOL_SOCKET (integer)
PHP_NORMAL_READ (integer)
PHP_BINARY_READ (integer)
SOL_TCP (integer)
SOL_UDP (integer)


//===( 0x5 :: Принцип написания сканера портов. Начнем с алгоритма )============

Принцип работы сканера портов простой как двери: пробуем соединиться с удаленным
портом, если соединение не удалось - порт закрыт Ж8)

Более детально, с учетом сокетов: создаем сокет, привязываем его к определенному
target host и target port, инициализируем соединение. Если удалось соединиться -
закрываем  сокет  и  запоминаем  порт как открытый, если соединение не удалось -
порт закрытый.


//===( 0x6 :: Пишем портскан )=================================================


портсканер  выводит  все в красивую табличку, которую строит сам. вам стоит лишь
все это вставить в HTML страницу. минимум <html>[сюда 8)]</html> 8)

<?php
error_reporting (E_ALL); // вывод сообщений для всех ошибок

// так как мы пишем продвинутый портскан, сделаем все красиво и удобно ;)

$portz = array("20","21","23","25","39","43","69","79","80","88","107","109","110",
	       "111","137","138","139","143","161","464","512","513","514","530",
	       "544","636","749","1433","1434");

// в данном массиве будут храниться номера портов, которые необходимо сканировать.
// это сделано для эффективного использования ресурсов сервера, зачастую провайдер
// выставляет небольшой таймаут для php скриптов и получится что сканируя все
// 65тысяч портов мы поступаем очень нерационально так как реально полезные из них
// всего пару процентов ;)

$descr = array("FTP data", "FTP control", "Telnet","Simple Mail Transfer Protocol",
	       "rlp: Resource Location Protocol", "whois", "tftp","finger","http",
  	       "kerberos","rtelnet","pop2","pop3","sunrpc:SUN Remote Procedure Call",
	       "Netbios name service","Netbios name service", "Netbios datagram service",
	       "imap4","snmp","kpasswd: kerberos v5","Remote Process Execution",
	       "remote login","cmd shell","courier rpc","kshell: Kerberos remote shell",
	       "ldaps","LDAP over TLS/SSL","kerberos-adm","ms-sql-s: Microsoft-SQL-Server",
	       "ms-sql-m: Microsoft-SQL-Monitor");

// а в этом массиве задаем описания для сервисов, обслуживающих на соответствующих портах
// главное чтобы смещение в массиве порта соответствовало смещению в массиве его описания
// то есть если смещение (индекс) порта с номером 23 == 2 (считаем с 0), значит описание
// для этого порта должно быть расположено так же с индексом 2 в массиве описаний.


$white_power = array("nteam.ru", "localhost");
$white_powerIP = array("194.186.45.233", "127.0.0.1", "1.0.0.1");
// при попытке сканировать данные хосты-адреса
// чел будет направлен на сеанс мануальной терапии к гинекологу, это сделано для случаев,
// когда необходимо запретить скан вашего хоста. ну представте что разместили вы этот
// портскан у себя на сайте и предоставили уеб-интерфейс для посетителей, а они все
// метанулись сканировать вас ;))

$log_path = "pscan.log";
$who = $HTTP_SERVER_VARS['REMOTE_ADDR'];
// объявляем переменные для лога. как это продвинутый сканер и без лога? ;)
// в лог будем писать все, даже адрес того кто сканит. мы же любопытные ;)

$err_path = "pscan.err";


$white_power_cnt = count($white_power);
$white_powerIP_cnt = count($white_powerIP);
// определяем колличество заданых портов-описаний, далее нам это пригодиться в циклах

$cnt=0; //счетчик

$timeout = 10; // таймаут для инициализации сокета, максимум - 15

if($timeout>15)  // а тут можете изменить максимум 8)
	$timeout=15;


$inputz = $hostname;
$chost = strip_tags($hostname); //загоняем сюда значение параметра $hostname,
// этот параметр необходимо передавать из html-формы, етц с именем hostname

$ITS_FUCKING_LAMOZ = 0;
// если 0 - услугами сканера пользуется законопослушный чел, все нормал 8)
// если 1 - этого засранца следует проучить
// эта переменная нам также пригодиться в дальнейшем, так как если кто-то захочет
// посканить хосты из black-листа - его нужно проучить, нельзя же просто так ламеров
// отпускать без ничего ;) по-дэфолту считаем что это нормальный чел, а дальше будет
// видно, эт смотря что за хост он захочет сканить... (см. дальше)

// если обнаружен засранец - имитируем сканирование, пишем мол все порты кроме
// 31337 закрыты и советуем засранцу проконсультироваться у врача 8)
// это все условно и вы можете изменить это по-вашему усмотрению.


if($chost==""){ // если запустили наш скрипт без параметра $hostname - громко ругаемся
echo "необходимо задать ip-адрес или имя хоста!\n";
	exit;
	}

$ch = $chost[0];
$new_chost="";

if( ord($ch)>=48 && ord($ch)<=57 ){ // IP -> DNS	
	$new_chost = gethostbyaddr($chost);
	for($cnt=0; $cnt<$white_powerIP_cnt; $cnt++)
// проверяем наличие ламера в онлайне 8)
		if( strstr($chost, $white_powerIP[$cnt])  )// ...
			$ITS_FUCKING_LAMOZ = 1;	 // вот он ламер!
	}
else{
		$new_chost = gethostbyname($chost); // DNS -> IP
		for($cnt=0; $cnt<$white_power_cnt; $cnt++)
			if( strstr($chost, $white_power[$cnt]) ){
				$ITS_FUCKING_LAMOZ = 1; // вот он ламер!
				break;
		}
			$chost = $white_power[$cnt];
	}


if( $chost == $new_chost){
	printf("ошибка в процессе соединения\n");	
	exit;
}


// вот это ухо @ в начале строки значит следующее - если при выполнении данной строки кода
// возникнет ошибка - ее выводить не нужно. это придумано для того, чтобы исключить 
// возможный баг раскрытия пути, вдруг хостер что-то изменит или что-то глюкнет при работе
// с файловой системой - ошибку НЕ выводим, так как в сообщении об ошибке будет путь к файлу
// спасибо за данную идею [R00T]'у!


@$LOGF = fopen($log_path, "a");
if($LOGF){ // если файл открыт успешно
@	flock($LOGF, 2);
@	fwrite($LOGF, "================================================================\n");
if(	$ITS_FUCKING_LAMOZ == 1 )
@	fwrite($LOGF, "[!!!] ".date('H:i:s Y-m-d')." :>>>    ".$HTTP_SERVER_VARS['REMOTE_ADDR']." scaned $chost\n");
else
@	fwrite($LOGF, date('H:i:s Y-m-d')." :>>>    ".$HTTP_SERVER_VARS['REMOTE_ADDR']." scaned $chost\n");
@	fwrite($LOGF, "================================================================\n");
}
// ну а это шапка лога, тоесть дата, айпишник, сканируемый хост...

else{ // если возникла ошибка при логировании - пишем в файл ошибок

@$ERRF = fopen($err_path, "a");

	if($ERRF){
@		flock($ERRF, 2);
@		fwrite($ERF, "[date('H:i:s Y-m-d')] невозможно залогировать $who\n");
@		flock($ERRF, 3);
@		rewind($ERRF);
@		fclose($ERRF);
	}
}
// 

$port = 0;
$pcnt = count($portz);
$dcnt = count($descr);
$ccnt = 0;
$errno = 0;
$errstr = "no errorZ";

if( ($pcnt==0) || ($dcnt==0) ){
	echo "список портов не пустой. всем на выход.<br>\n";	
	exit;
}

if($pcnt!=$dcnt){
	if($pcnt>$dcnt)
		$ccnt=$dcnt;
	else
		$ccnt=$pcnt;				
}
else
	$ccnt=$pcnt;
// если количество портов и количество описаний разные - обрезаем до равного


echo "сканируем ".$hostname.".....<br>\n";
if($ITS_FUCKING_LAMOZ==1){
	printf('<center><b><div align="center">региональный департамент ФСБ, отдел по борьбе с компьютерной преступностью</div><b></center><br>');
	printf('<br><br><center><b><div align="center">подождите пока система проверит ваш компьютер<br>');
	echo '<div align="center">просим не отсоединятся еще две минуты, идет скачка информации.......</center><br>';
	sleep(1); // делаем маленькую задержку, типа имитация мощной работы скрипта 8)
	echo '<br><div align ="center"><b>настоятельно рекомендуем пройти сеанс мануальной терапии у гинеколога, у вас проблемы</b></div><br>';
	}


echo '
<p>&nbsp;</p>
<table width="85%" border="0" align="center">
  <tr> 
    <td width="8%" bgcolor="#999999"> <div align="center">status</div></td>
    <td width="14%" bgcolor="#999999"> <div align="center">ip adress</div></td>
    <td width="8%" bgcolor="#999999"> <div align="center">port</div></td>
    <td width="50%" bgcolor="#999999"> <div align="center">service description</div></td>
    <td width="20%" bgcolor="#999999"> <div align="center">err0r</div></td>
  </tr>
  ';

if( $ITS_FUCKING_LAMOZ != 1){ // LAMOZ NOT DETECTED
    echo str_repeat(" ", 256); 
 for($i=0; $i<$ccnt; $i++){
	if(!$timeout)
		@$usenet_handle = fsockopen($chost, (int)$portz[$i]);
	else
		@$usenet_handle = fsockopen($chost, (int)$portz[$i], &$errno, &$errstr, $timeout);
		
	if(!$usenet_handle)
	
	printf('
				 <tr> 
				<td><div align="center">refused</div></td>
				<td><div align="center">%s</div></td>
				<td><div align="center">%s</div></td>
				<td><div align="center">%s</div></td>
				<td><div align="center">%s</div></td>
				</tr>' , $chost, $portz[$i], $descr[$i], $errstr
			);
	else{
@		fwrite($LOGF, $chost."\t".$portz[$i]."\t".$descr[$i]."\t".$errstr."\n");
		printf('
				 <tr> 
				<td><div align="center"><font color=red>соединен</font></div></td>
				<td><div align="center"><font color=red>%s</font></div></td>
				<td><div align="center"><font color=red>%s</font></div></td>
				<td><div align="center"><font color=red>%s</font></div></td>
				<td><div align="center"><font color=red>%s</font></div></td>
			   </tr>' , $chost, $portz[$i], $descr[$i], "no err0rZ"
			   );
	} // end else
	
	flush();
	
} // end for

@	fwrite($LOGF, "\n\n");
@	flock($LOGF, 3);
@	rewind($LOGF);
@	fclose($LOGF);


}
else{ // LAMOZ WAS DETECTED, ATTENTION!!! 8-)

$errstr = "порт закрыт"; // heh, lamer did not expect such shit! ;)
    echo str_repeat(" ", 256); 
	for($i=0; $i<$ccnt; $i++){    // типа открыт только 31337 Ж8-)
		printf('
					<tr> 
					<td><div align="center">закрыт</div></td>
					<td><div align="center">%s</div></td>
					<td><div align="center">%s</div></td>
					<td><div align="center">%s</div></td>
					<td><div align="center">%s</div></td>
					</tr>' , $chost, $portz[$i], $descr[$i], $errstr
				);		
					flush();
	}//end for
	
	
	printf('
			    <tr> 
				<td><div align="center"><font color=red>соединен</font></div></td>
				<td><div align="center"><font color=red>%s</font></div></td>
				<td><div align="center">31337</div></td>
				<td><div align="center"><font color=red>lol... inet cracker here!</font></div></td>
				<td><div align="center"><font color=red>no err0rz</font></div></td>
				</tr>', $chost
			);				
}
	
echo '</table><p>&nbsp;</p>';

echo "<br><br>\n <center><b>tNPScan v1.0.0</b> bY black c0de //[tN] :: [the nobodies] :: [www.nteam.ru]<br></center>\n";

unset($chost);
unset($new_chost);
unset($timeout);
unset($port);
unset($pcnt);
unset($dcnt);
unset($ccnt);
unset($errno);
unset($errstr);
// ну и напоследок освобождаем память, выделенную под переменные. кому нужны значения
// наших переменных у прова в свопе? ;)
?> 


//===( 0x7 :: Полезные советы и хинты )=========================================

для  того  чтобы  ваш  PHP позволял работать с сокетами его необходимо собрать с
опцией --enable-sockets. обычно по-дэфолту он собран с этим параметром.


//===( 0x8 :: Исходник )========================================================

sum -r/size 60956/4828


//===( 0x9 :: Линки на полезные ресурсы )=======================================

(+) все что нужно даже больше есть на php.net
(+) если вам хочется спросить совета у продвинутого PHP-кодера - обратитесь 
    к L0vCh1Y 8)


//===( 0xA :: greetZ )==========================================================

greetz2:
--------
firew0rker, [R00T], S`QuaD, bio3k, OxiD, BSoD, Xternal, euronymous, Over_G, 
L0vCh1Y, sp0raw, tyuba, Kabuto, XPYD3X
&&
F0kp, ZUD, DWC, m00security, cyberinfo


respect2: 
---------
security.nnov.ru, securityfocus.org, void.ru, wasm.ru, php.net

# 
# all rights reserved (c) 2003 black c0de //tN [the nobodies] :: [www.nteam.ru]
#
################################################################################