------------------------------------------------
#!/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> </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> </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]
#
################################################################################