C++ C++ C# C# ASP.NET Security ASP.NET Security ASM ASM Скачать Скачать Поиск Поиск Хостинг Хостинг  
  Программа для работы с LPT портом...
Язык: .NET — ©Alexey...
  "ASP.NET Atlas" – AJAX в исполнении Micro...
Язык: .NET — ©legigor@mail.ru...
  "Невытесняющая" Многопоточность...
Язык: C/C++ — ©...
  01.05.2010 — Update World C++: Сборник GPL QT исходников
  15.12.2007 — Весь сайт целиком можно загрузить по ссылкам из раздела Скачать
Хостинг:
Windows 2003, ASP.NET 2.0
бесплатный и от 80 руб./мес


   Отправить письмо
Кулабухов Артем, Беларусь




 Netfilter Kernel Programming / Kernel / UNIX

.. Netfilter Kernel Programming  //devol

В этой статье я постараюсь дать начальные сведения о netfilter'e и о том, как предотвратить Land-подобную атаку с помощью написания модуля для ядра.

И так, netfilter - это подсистема фильтрации пакетов в ядрах ветки 2.4/6.x, он же - первый встроенный в ядро контекстный брэндмауер (Stateful Firewall). Контекстный брэндмауер отличается от обычного тем, что он может определять, является ли настоящий пакет частью какого-либо соединения. В частности, в TCP протокол встроена система трехэтапного квинтирования. Для этого клиент шлет серверу запрос на соединение, указав в хедере флаг syn, на что сервак отвечает ему таким же пакетом, но плюс к syn флагу он еще добавляет флаг ack, указывая тем самым, что он хочет с ним установить соединение, после согласия на это клиента. Ну, так вот, обычный брэндмауер не способен отличить пакет, который будет идти в этой сессии соединения или же это какой-либо другой пакет, владелец которого уже секунд 20 назад установил соединение. Зато контекстный брэндмауер определяет, относится ли этот пакет к нашему с ним соединению или же к другому, посмотрев для этого таблицу коннектов. Примерно таким же образом он обрабатывает и другие протоколы: UDP, ICMP, etc (смотри /etc/protocols). В частности, такой тип брэндмауеров используется в Cisco. Ну да ладно, много интересного об архитектуре и особенностях netfilter'a вы можете узнать, поботав доки с www.netfilter.org.

А теперь поговорим о том, как же нам запрогать netfilter. Он способен перехватывать пакеты следующих сетевых стеков: IPv4, IPv6, DECnet. Мы рассмотрим только IPv4. Для данного стека в хереде /usr/include/linux/netfilter_ipv4.h определены следующие возможные значения захвата IP-пакетов (так называемые хуки):

0.NF_IP_PRE_ROUTING: решаем, что делать с пакетом на входе.
1.NF_IP_LOCAL_IN: входящий, для нашего компа.
2.NF_IP_FORWARD: если пакет предназначен для другого интерфейса.
3.NF_IP_LOCAL_OUT: если этот пакет создан локально.
4.NF_IP_POST_ROUTING: решаем что делать с пакетом на выходе.
Перед тем, как к нам прилетит пакет, вызывается NF_IP_PRE_ROUTING хук. Далее вызывается функция, которая и решит, что мы сделаем с пакетом. Эти функции определены в /usr/include/linux/netfilter.h:
0.NF_DROP: отбросить пакет.
1.NF_ACCEPT: пропустить на дальнейшую обработку.
2.NF_STOLEN: запомнить этот пакет в понятии котекстного брандмауера.
3.NF_QUEUE: поставить пакет в очередь.
4.NF_REPEAT: вызвать эту функцию повторно.
Структура объявления хуков определена в /usr/include/linux/netfilter.h:
struct nf_hook_ops
{
/* член списка этой структуры используется для поддержки списка хуков
netfilter'a и он не несет никакой смысловой нагрузки на регистрацию хука */
	struct list_head list;
/* укаказатель на хук-функию, см.выше */
	nf_hookfn *hook; 
/* какое семейство протоколов будем использовать. Так как мы обусловились
работать со стеком IPv4, то посмотрев хедер /usr/include/linux/socket.h,
узнаем что это PF_INET */
	int pf; 
/* какой из хуков мы будем использовать, см.выше */
	int hooknum; 
/* каждому хуку можно назначить свой приоритет, для нашего стека см. файл
/usr/include/linux/netfilter_ipv4.h */
	int priority;
};
Теперь же, чтобы зарегистрировать хук, нам понадобиться функция nf_register_hook, прототип которой определен в файле /usr/include/linux/netfilter.h.
int nf_register_hook(struct nf_hook_ops *reg);
В качестве аргумента эта функция принимает выше обозначенную структуру. Для определения данных, которые передаются в хук-функцию, используется прототип nf_hookfn, который определен в том же хедере:
typedef unsigned int nf_hookfn(unsigned int hooknum,
			       struct sk_buff **skb,
			       const struct net_device *in,
			       const struct net_device *out,
			       int (*okfn)(struct sk_buff *));
Здесь первый аргумент - это номер хука, а второй - указатель на указатель на sk_buff структуру, которая определена в /usr/include/linux/skbuff.h хедере. Это нужно для того, чтобы ядро знало, с какими пакетами мы работаем. Следующие два аргумента - это указатели на net_device структуру, определенную в /usr/include/linux/netdevice.h. Они используются для того, чтобы ядро знало, что за интерфейс мы используем (eth0, tap0, lo, etc). In и Out, соответственно, входящий и исходящий интерфейсы. В частности, in будет осуществлен для NF_IP_PRE_ROUTING и NF_IP_LOCAL_IN, а out - для NF_IP_POST_ROUTING и NF_IP_LOCAL_OUT хуков. Последний аргумент - функция, которая в качестве аргумента опять же принимает структуру sk_buff. Эта функция нужна, чтобы зря не расходовать процессор ожиданием пакета, который поставлен в очередь с помощью функции NF_QUEUE.

Так как все основные определения я уже дал, остается зашарить в ядерном написании модулей. Для этой цели поботайте статейки dev0id'a о "Linux Kernel Modules". Все, теперь я предоставлю исходник нашего фильтра пакетов, который будет обнаруживать пакеты, которые шлются при Land-атаке, т.е. где порт и IP атакуемого сервера совпадают с портом и IP этого же сервера (т.е. source=destination ip/port).

/* хедеры */
#define __KERNEL__
#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
/* структура, которую мы будем использовать для регистрации нашей функции */
static struct nf_hook_ops nfho;

/* интерфейс, который мы используем */
static char *drop_if = "eth0";
/* тут указываем наш ip-адрес, в данном случае 192.168.168.1 */
static unsigned char *drop_ip = "\xc0\xa8\xa8\x01";
/* порт. Укзываем пока что один открытый 80-ый порт, но реально дописать программу,
которая будет отслеживать все открытые TCP/UDP-порты */
unsigned char *deny_port = "\x00\x50";


/* это наша хук-функция */
unsigned int hook_func(unsigned int hooknum,
				struct sk_buff **skb,
				const struct net_device *in,
				const struct net_device *out,
				int (*okfn)(struct sk_buff *))
{
	struct sk_buff *sb = *skb;
	struct tcphdr *port;
	port = (struct tcphdr *)(skb->data + (skb->nh.iph->ihl * 4));
	if ((strcmp(in->name, drop_if) == 0) && 
		(sb->nh.iph->saddr == drop_ip) && 
		((skb->nh.iph->protocol != IPPROTO_TCP) || 
		 (skb->nh.iph->protocol != IPPROTO_UDP)) &&
		((port->dest) == *(unsigned short *)deny_port)) 
	{
		printk("Packet dropped...");
		return NF_DROP;
	}else{
		return NF_ACCEPT;
	}
}

/* сандартная функция инициализации */
int init_module()
{
    nfho.hook     = hook_func;
    nfho.hooknum  = NF_IP_PRE_ROUTING;
    nfho.pf       = PF_INET;
    nfho.priority = NF_IP_PRI_FIRST;
  
    nf_register_hook(&nfho);
    
    return 0;
}
	
/* стандартная функция удаления модуля */
void cleanup_module()
{
    nf_unregister_hook(&nfho);
}
Ну вот собственно и все, что я хотел рассказать в этой вводной статье. Ботайте физику и, физтех - рулез!

Основные источники:
[0] http://netfilter.org
[1] http://lists.netfilter.org/pipermail/netfilter-devel/
[2] http://www.geocities.com/victorhugo83/
[3] http://www.linuxsecurity.com/feature_stories/kernel-netfilter.html

[c] devol aka cl1mp3x, (XFree86@mail.ru).