Данный материал написан для начинающих net-programmer'ов, и поэтому насмешки в мой адрес по типу "Фу че за ламерский док ваще!" неуместны. А если кто-то хочет похвастаться своей крутостью, пусть отсылают мне на e-mail теорию buffer overflow, а также свое мнение насчет вычисления адреса стека :).
Также хочу заметить, что я просто ненавижу internet-сленг (рулез, пиплы, аська, маздай и тд), поэтому не использую данные термины в статье.
Перед началом прочтения данной статьи я хочу чтобы ты знал, ЧТО тебе понадобиться для её освоения. Ты наверное уже успел прочесть название и
надеешься закодить какой-нибудь winnuke (не трогаю профов в этом деле), но осмелюсь заявить что тебе понадобятся минимум знания по С и UNIX, а также желательно (но не обязательно), чтобы ты имел опыт программирования socket'ов.
Зачем вообще тебе нужен этот гимор с изучением сетевого программирования? Объясняю: Зная, что у протокола внутри, легче заметить и обезвредить атаку извне (звучит?:). Данный материал неплох для админов, которым все наскучило в этой жизни, и они хотят узнать что-то новенькое. И вообще, по-моему, просто не прилично сканировать чужие порты, не зная при этом, какого фига эти порты высвечиваются :).
Итак, приступим к изучению сетевого кодинга, самого веселого кодинга, когда-либо существовавшего на земле. Начнем конечно
же с основ - напишем нижеприведенную прогу:
#include <STDIO.H>
#include <STDLIB.H>
#include <SYS socket.h>/*подключаем заголовок для
работы с сокетами*/
#include <NETINET in.h>/*для работы с функцией htons()*/
#define FTP_PORT 21 /*наша программа использует 21-й порт (ftp)*/
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in addr; /*данная структура является адресатом(то есть порт и ip для коннекта или прослушивания)*/
addr.sin_family = AF_INET; /*какое семейство сокетов мы используем*/
addr.sin_addr.s_addr = inet_addr( "127.0.0.1"); /*локальный или удаленный ip address*/
addr.sin_port = htons(FTP_PORT); /*локальный или удаленный порт*/
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /*создаем сокет*/
}
Для новичка в net кодинге данный исходник не будет понятным, поэтому разъясняю на пальцах.
Во-первых, что такое socket? Socket - это что-то вроде твоего телефона, то
есть прибор для общения. Любой клиент/сервер, перед коннектом/прослушиванием (соответственно) открывает сокет. Например telnetd сначала, открывает сокет, а только затем присобачивает ему порт 23. Надеюсь
ты понял.
Второй вопрос: зачем я везде писал, удаленный или локальный? Просто данный исходник является каркасом для клиента/сервера. Мы еще не определили, какой тип программы мы будем писать. В данной статье я расскажу только о написании клиента.
Продолжаем (пишем клиент):
#include ............................................................
int main(int argc, char *argv[])
{
............... /*то же самое что и в предыдущем source'e*/
char pack[] = "Hello SERVER, it's me CLIENT!!!\n"; /*строчка, которую мы пошлем на сервер*/
connect(sock, (struct sockaddr*)&addr, sizeof(addr)); /*коннектимся, используя "sock" и адресат "addr"*/
send(sock, pack, 0, sizeof(pack)); /*посылаем строчку в переменной pack[]*/
/*в функции send(), там где третий параметр равен 0, можешь написать MSG_OOB, и у тебя получится WINNUKE*/
}
Я думаю, что теперь ты понял, что из себя представляет net-кодинг. Наверное, пришло время развеяться, забыть этот четкий порядок изъяснений и всякой прочей лабуды. Почему бы просто не показать реальное применение сетевого программирования в жизни хакера или админа? Ты же не собираешься писать свой HTTP сервер, так? Тогда давай напишем такой народный и
жизненно важный инструмент как порт-сканнер. Как он вообще работает? Ну я думаю это ты уж точно знаешь, иначе дочитал бы ты до данного места?
Когда ты вручную коннектишься к портам telnet'ом, ты сам являешься port-scanner'ом. Программы-сканнеры, просто автоматизируют данный процесс, делают его более быстрым и удобным. Выходит, что
вычислить алгоритм работы порт сканнера не так
уж и сложно!
Вот алгоритм
Включить секундомер.
пока(секундомер не приравняется цифре 65535; продолжать увеличивать)
{
если( подключится(к порту с числом равным числу секундомера) удается)
тогда
вывести_на_экран(номер порта)
}
Здесь мы видим, что клиент(наша программа) будет соединяться с сервером 65535 раз, при этом увеличивая номер порта
с каждым коннектом на единицу. Теперь мы приведем данный алгоритм в С коде:
#include <STDIO.H>
#include <STDLIB.H>
#include <SYS socket.h>
#include <NETINET in.h>
int sec = 0; /*секундомер*/
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr( "127.0.0.1");
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
for(sec=0; sec<=65535; sec++) /* пока(секундомер не приравняется цифре 65535; продолжать увеличивать) */
{
addr.sin_port = htons(sec); /*увеличивать номер порта */
if(connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == 0)
/*если( подключится(к порту с числом равным числу секундомера) удается)*/
{
printf("открытый порт: %d\n", sec); /* вывести_на_экран(номер порта) */
}
}
}
Надеюсь ты понял, все выше написанное, так
как на этом глава для новичков заканчивается.
Теперь я приведу описание функций, которые были использованы мной при написании исходников:
- socket ( 1_семейство сокетов, 2_тип пересылки, 3_тип протокола );
1 параметр "семейство сокетов" - обычные сетевые приложения,
включая DoS эксплоиты, используют AF_INET. Если ты хочешь кодить в сетях
X.25, IPX и т.п., то можешь заменить этот параметр на AF_X25, AF_IPX. Для полного списка погляди на свой linux/socket.h файл.2 параметр "тип пересылки" - здесь определяется как ты будешь посылать свои пакеты. Например SOCK_STREAM это тип пересылки для протокола TCP, SOCK_DGRAM - для UDP, и наконец SOCK_RAW ( о нем во второй главе ) для всех остальных (ICMP, IGMP), SOCK_RAW кстати ты можешь использовать и для протоколов TCP/UDP.
3 параметр "тип протокола" - это самый понятный пункт, здесь ты просто выбираешь протокол с которым будешь работать(IPPROTO_TCP, IPPROTO_UDP, ....... )
- inet_addr (ip адрес);
Данная функция преобразовывает указанный ip в 16ричную систему, понятную для ядра ОС.
- htons(порт);
То же, что и inet_addr(), но с портом.
- connect(1_сокет, 2_адресат, 3_размер сокета);
1 параметр "сокет" - просто указывает, какой сокет использовать
2 параметр "адресат" - куда посылать
3 параметр "размер сокета" - no comments
- send(1_сокет, 2_пакет, 3_флаг, 4_размер пакета);
2 параметр "пакет" - какой пакет отсылаем
3 параметр "флаг" - здесь ставятся опции, советую всегда ставить 0
Вот я думаю и все, на этом первая глава заканчивается. Более глубокий уровень сетевого кодинга я изложу в во второй главе моей статьи. Бывай друг!