Sunday, February 1, 2009

Автостопом по крипто апи.



Пребью
Криптографии в разработке системных и не только приложениях принято уделять повышенное внимание. Особенно сейчас, когда набитость сундуков многих благородных сэров, как и степень их свободы, напрямую зависит от степени конфеденциальости их информации. Чтобы секономить время и не ходить лишний раз к проктологу восьпользуемся тем что, большинство стойких и эффективных алгоритмов уже реализованно професионалами этого дела. Плод их трудов открыто предоставляется на комерческой и бесплатной основе. Разработчики операционных систем тоже не сидят сложа руки предоставляя разработчикам специальные API. В этой статье мы хотим рассказать об исползования таких API в модуле ядра для операционной системы Linux, котороый будет шифровать исходящий трафик и расшифровывать входящий.

Летс гоу.
А начнем пожалуй с подготовки системы. Для начала надо убедится что система готова к созданию разного рода приложений, а конкретно к разработке модулей ядра. Помимо присутсвия GCC надо еще убедиться что ядро было скомпилированно с поддержкой модульности и криптографических API. Про установку GCC и включение модульности написано много мануалов поэтому не будем тратить ни времени ни чернил, в информации по созданию модулей недостатка тоже не чувствуется, так что приступим сразу к делу. Крипто API включаются выставлением параметров CONFIG_CRYPTO* в конфигурационном файде ядра (/usr/src/.config). А самый легкий способ проверки их доступности это попытаться скомпилировать пример который находится все в техже исходниках ядра. Заходим в папку с иходниками ядра, дальше как наверное не трудно догадаться в дирректорию crypto и компилируем tcrypt.c. Если он компелируется без фатальных ошибок и даже работает, то собираемся с духом и идем дальше.

Вот из ит.
Теперь надо немного разобраться чтоже всетаки мы подключили и где это найти. Исходники этого всего дела лежат в тойже директории что и упомянутый выше tcrypt.c, а сам он является примером в котором показано как использовать все реализованные в Cryptographic API алгоритмы. Пример этот хорошо коментирован, а если что-то остается не совсем понятным то всегда можно заглянуть в лежащие рядом исходники самих Cryptographic API. Но как говорится сказать или даже написать проще чем сделать. На практике довольно часто можно свалиться в штопор в самых неожиданных местах, и потом довольно долго по частям собирать то что всего пять минут назад летело со скоростью звука. К сожалению ошибки всегда банальны, но постоянны, и каждый раз вспоминать как приклеивается один и тоже кусок становится утомительным. Сделать один раз инструкцию и современем её дополнять гораздо эффективнее и проще. Относительно наших API можно сказать тоже самое. Нормального мана на русском языке по ним нам найти не удалось, а повторно вкуривать одну и туже траву это не тру. Поэтому хотим оставить своего рода рабочие записки и надеемся что это еще комунибудь поможет.

Литл море
Предположим мы хотим реализвать немного устаревший но достаточно быстрый и провереный алгоритм DES. У этого алгоритма существует несколько режимов:

* ECB (Electronic Code Book) - режим все блоки шифруются независимо друг от друга и не сцепляются;
* CBC (Cipher Block Chaining)- режим в котором результат шифрования предыдущего блока используется для шифрации текущего.

Под блоками тут подразумевается часть шифротекста. Так с виду один и тот же алгоритм может быть реализован в разных режимах. Если кому интересно, то в качестве домашнего задания можно еще самостоятельно покурить CFB и OFB.
Однако, мы отвлеклись от темы. Для своих целей выберем режим CBC как более надежный и приступим сделав наброски будующего кода.
Как это часто бывает начнем с написания и описания ключевых структур и переменных.

struct completion comp;
struct scatterlist sg[8];
struct crypto_ablkcipher *tfm;
struct ablkcipher_request *req;


Переменная comp служит для синхронизации выполнения между нашей функцией и непосредственно шифрованием. Суть этого станет ясна чуть ниже. А пока рассмотрим саму структуру. Она объявлена в include/linux/completion.h и содержит всего два поля:
struct completion {
unsigned int done;
wait_queue_head_t wait;
};

Первое это флаг выполнения, а второе указатель на очередь ожидающих задач.

Следующая переменная sg описана в include/linux/scatterlist.h. Это структура платформо зависимая, и на i386 платформе она определена следующим образом:
struct scatterlist {
struct page *page;
unsigned int offset;
dma_addr_t dma_address;
unsigned int length;
};

Заполнение полей этой структуры вполне можно поручить функции sg_init_one(). В этой функции определяется страница памяти, с которой "начинается" buf, и определяется смещение указателя buf относительно адреса начала страницы.
tfm и есть наша основная структура, в файле include/linux/crypto.h находится ее описание
struct crypto_ablkcipher {
struct crypto_tfm base;
};


Не очень информативно поэтому посмотрим чуть выше, где находится
struct crypto_tfm {
u32 crt_flags;
union {
struct ablkcipher_tfm ablkcipher;
struct aead_tfm aead;
struct blkcipher_tfm blkcipher;
struct cipher_tfm cipher;
struct hash_tfm hash;
struct compress_tfm compress;
} crt_u;
struct crypto_alg *__crt_alg;
void *__crt_ctx[] CRYPTO_MINALIGN_ATTR;
};

Уже что-то неправдали? первым полем идут флаги, о некоторых из них расскажем чуть ниже. Далее объединение более низкуровневых структур для разных типов криптографических задач, прямой доступ к которым использовался в предыдущих версиях. В crypto_alg содержится указатель на структуру. в которой есть все необходимое для корректной работы непосредственно алгоритма шифрования. А именно имя самого алгоритма, приоритет и т.д. /*про это можно подробнее отсюда http://diploma-thesis.siewior.net/html/diplomarbeitch4.html*/

Следующая переменная req содержит указатель на структуру запросов struct ablkcipher_request.
struct ablkcipher_request {
struct crypto_async_request base;
unsigned int nbytes;
void *info;

struct scatterlist *src;
struct scatterlist *dst;

void *__ctx[] CRYPTO_MINALIGN_ATTR;
};


С помошью этой прменной мы обращамся к страницам памяти где находится шифрованный и расшифрованый текст.

Когда мы разобрались с основными переменными можно приступать к написанию самого кода. Начнем с инициализации переменной comp с помощью функции init_completion().
init_completion(&comp);

Эта функция обнулят флаг done, и добвляет comp в голову очереди wait_queue_head_t, о которых рассказывалось выше. Подробнее о механизме работы этой структуры и о том для чего мы ее используем будет рассказано еще чуть ниже ;).

Теперь выделим память дла нашей оновной пременной.
tfm = crypto_alloc_ablckhipher ("cbc(des)", 0, CRYPO_TFM_REQ_WEAK_KEY);

В качестве первого параметра мы передаем имя алгоритма, второй параметр это тип шифрования (вспомните объединение crt_u в опиании структуры), третьим параметром мы передам флаги, переданный флаг означает что алгоритм должен принимать даже слабые ключи.

Далее выделям память для ablkcipher_request
req = ablkcipher_request_alloc (tfm, GFP_KERNEL);

С первым параметром думаю все понятно и так. Непосредственно память под структуру выделяется функцией kmalloc, которая в качестве параметра принимает флаг, говорящий о том как именно стоит выделять память. Флаг GFP_KERNEL (GFP - Get Free Page) резервирует блок памяти, выделяя страницы памяти по мере обращения к ним. Существует и другие флаги например:
GFP_ATOMIC выделяет требуемую память немедленно (при необходимости вытесняя другие страницы на диск);
GFP_BUFFER никогда не вытесняет другие страницы, и если запрошенная память недоступна, с выделением наступает облом.
Фактически приходится выбирать между GFP_ATOMIC и GFP_KERNEL. Обычно используют GFP_KERNEL, так как он ведет себя не столь агрессивно.

Потом установим ключ которым будем шифровать
ret = crypto_ablkcopher_sekey (tfm, key, strlen(key));

Эта функция возвращает 0 в случае успеха и код ошибки больший нуля в случа неудачи. К првому параметру думаю опять не возникает никаких вопросов, да и с остальными ничего сложного: второй - указатель на строку с ключем, третий - длина.

Теперь позаботимся о расположении текста который будем шифровать
sg_init_one (&sg[0], text, strlen(text));

Стоит отметить что текст должен быть кратен восьми, иначе при попытке зашифровать\дешифровать получите ошибку -21 (что означает «некорректные входные данные»). То как с этим боремся мы можно посмотреть в приложенном коде. Сама же функция просто заполняет страницы памяти текстом, который собираемся зашифровать или дешифровать :).

Подготовим запрос для шифрования/дешифрования сообщив ему с какими страницами и текстом какой длины предстоит работать
u8  iv = {0xff, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10};
ablkcipher_request_set_crypt (req, sg, sg, strlen(text), iv);

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

Теперь приступаем непосредствнно к шифрованию/дешифрованию
ret = enc ? crypto_ablkcipher_encrypt (req) : crypto_ablkcipher_decrypt(req);

Сами функции и их параметр в пояснении думаю не нуждаются, если не понятно перечтайте еще раз внимательно о req. Ну с ret все совсем понятно скажите вы. А вот и нет :). Да ret в случае удачного выполнения действительно будет равна 0. Но вот остальные значения не всегда означают ошибку.

Теперь пришло время рассказать совсем подробно о роли переменной comp и этом механизме.
switch (ret){
case 0:
break;

case -EINPROGRESS: case -EBUSY:
printk ("\nwait\n");
ret = wait_for_completion_interruptible (&comp);
if (!ret) {
INIT_COMPLETION(comp);
break;
}

default:
printk ("failred err=%d", -ret);
goto out;
}

Вспомните описание структуры completion, непонятные слова которые мы говорили о флаге выполнения и очереди задач. Дело в том что криптоалгоритмы не так быстры как хотелось бы. Но как же так скажите вы как мы можем вернутся в вызвавщую функцию до того как завершилась вызываемая. Дело в том что авторы этой библиотеки очень хитрые люди и оптимизировали работу криптоалгоритмов в расчете на распаралеливание вашего алгоритма и с учетом что к шифруемым дешифруемым двнным будут обращатся другие алгоритмы. Поэтому и получилось так что мы можем вернутся в вызвавшую функцию до того как шифрование/дешифрование завершится. Для того чтобы избежать обращения к еще не зашифрованным/ не расшифрованым данным мы и используем структуру completion. Механизм работы этой структуры и функций с ним связанным идентичен механизму работы блокирующих семафоров. Когда работа криптоалгоритма будет завершена он выставит поле done в 1 и наша функция продолжит работу. Если вы знакомы с семафорами то вопросов не возникнет, если нет то настоятельно рекомендуем познакомится.

Далее можно для проверки распечатать зашифрованый/дешифрованный текст или делать с ним все что угодно.

Дуй ит нау
Сам модуль можно найти здесь. Код подробно прокоментирован и не должен вызывать затруднений. По сути он добалвляет свою фукцию (nethook) по обработке полученных и отправленных пакетов на определенное устройство, символьное имя которого задается параметром device_name. А за шифрование/дешифрование отвечает функция my_des, в ней пременено все о чем мы писали выше. Инструкция по сборке и установке лежит рядом. Дерзайте ;)

Sunday, January 25, 2009

Quick Note: nmap

  • nmap -sS -PB -F 3 опции используемые по умолчанию. Трехкодовое квитирование не завершается оставляя факт сканирования незаметным для большинства машин. Для определения статуса хоста используются как TCP так и ICMP пакет что повышает надежность но делает много шума. -F 3 означает что пакеты посылаются со скростью работы ОС.
  • nmap -sP Выполняется простое эхо-тестирование всех адресов, чтобы увидеть, какие из них ответят на ICMP-запрос.
  • nmap -sU -p 1024-65535 проверяет наличие слушаемых UDP-портов. cпособен выявить троянские программы, использующие UDP-порты с большими номерами и скрытые RPC-сервисы. Опция -p позволяет задать номера портов наиболле часто используемых малварью.
  • nmap -sF Это скрытное сканирование использующее пакеты TCP FIN. Может осуществляться под наблюдением некоторых программ выявления вторжений и при наличии других контрмер.
  • nmap -sN Cкрытное сканирование, при котором все флаги заголовка TCP сброшены (или пусты). Для серверов не под Windows, защищенных межсетевым экраном, оно может стать способом проникновения.
  • nmap -n FTP_HOST Использует лазейку в протоколе TCP для "отражения" сканирующих пакетов от сервера FTP во внутреннюю сеть, которая обычно недоступна. Зная IP-адрес сервера FTP, который подключен к локальной сети, вы можете проникнуть через межсетевой экран и сканировать внутренние машины.
  • nmap -sR ищет машины, отвечающие сервисам удаленного вызова процедур (RPC). RPC-сканирование зондирует найденные открытые порты с помощью команд, показывающих имя программы и версию сервиса RPC.
  • nmap -sW Данный тип сканирования полагается на аномалию в ответах на пакеты ACK в некоторых операционных системах, чтобы обнаружить порты, которые предположительно фильтруются. Известно, что к числу операционных систем, уязвимых для подобного сканирования, принадлежат некоторые версии AIX, Amiga, BeOS, BSDI, Cray, DG/UX, Digital UNIX, FreeBSD, HP/UX, IRIX, MacOS, NetBSD, OpenBSD, OpenStep, OpenVMS, OS/2, QNX, Rhapsody, SunOS 4.X, Tru64 UNIX, Ultrix, VAX и VxWorks
  • nmap -sI Данный тип сканирования появился в Nmap версии 3.0. Это сверхскрытный метод, при применении которого пакеты сканирования отражаются от внешнего хоста. Необязательно иметь контроль над этим хостом, но он должен работать и удовлетворять некоторым требованиям. Вы должны ввести IP адрес хоста-зомби и номер используемого порта.
  • nmap -PT Для обнаружения хостов используется только метод TCP.
  • nmap -PE Использовать для раскрытия сети только пакеты ICMP.
  • nmap -P0 Nmap не будет пытаться сначала выяснить, какие хосты активны, а будет вместо этого посылать пакеты по каждому IP-адресу заданного диапазона, даже если по этому адресу машины нет. это может быть единственным способом просканировать хорошо защищенную сеть, которая не отвечает на ICMP-пакеты
  • nmap -F 0 пакет раз в 5 минут
  • nmap -F 1 пакет раз в 15 секунд
  • nmap -F 2 пакет раз в 4 секунды
  • nmap -F 4 со скростью ОС но время ожидание сокращено до 5 минут на хост и до 1,25 секунды на пакет
  • nmap -F 5 Время ожидания 0,75 секунды на хост и 0,3 секунды на зондирующий пакет.
  • nmap -n не делать разрешения имен
  • nmap -F быстрое сканирование
  • nmap -D адреса_приманки1 адрес_приманки2 Эта опция создает видимость, что хосты, указанные в качестве приманок, участвуют в сканировании целевых машин.
  • nmap -f вызывает фрагментацию отправляемых пакетов сканирования.
  • nmap -I запрашивать идентификацию
  • nmap -R разрешить все адреса
  • nmap -O идентификация ОС
  • nmap -m сохранять журналы в виде пригодном для NLog

Рецепты на каждый день: iptables - firewall

Тщательно очистите 3 цепочки
iptables -F FORWARD
iptables -F INPUT
iptables -F OUTPUT

Поместите инструкцию "запретить все" в самое начало

iptables -P FORWARD DROP
iptables -A INPUT -i eth0 -j DROP

И разрешите фрагментированным пакетам проходить через вашу сеть

iptables -A FORWARD -f -j ACCEPT

Попытки подделатся под нашу сеть или затопить ее должны быть пресечены сразу же.

iptables -A FORWARD -s 192.168.0.0/24 -i eth0 -j DROP
iptables -A FORWARD -p icmp -i eth0 -d 192.168.0.255 -j DENY

Пропускаем инициированный из внутренней сети соединения.

iptables -A FORWARD -p tcp -i eth0 -d 192.168.0.0/24 --dports www,smtp --tcp-flags SYN, ACK -j ACCEPT

Пропускаем соединения инициированные изнутри.

iptables -A FORWARD -m multiport -p tcp -i eth0 -d 192.168.0.0/24 --dport smtp --syn -j ACCEPT

Разрешаем некоторые порты для входящих соединений.

iptables -A FORWARD -m multiport -p tcp -i eth0 -d 192.168.0.0/24 --dport smtp --syn -j ACCEPT

Разрешаем пользователям инициировать некоторые соединения изнутри

iptables -A FORWARD -m multiport -p tcp -o eth0 -d 0.0.0.0 --dports www,smtp --syn -j ACCEPT

Разрешаем UDP для DNS.

iptables -A FORWARD -m multiport -p udp -i eth0 -d 192.168.0.0/24 --dports domain -j ACCEPT
iptables -A FORWARD -m multiport -p udp -i eth0 -s 192.168.0.0/24 --sports domain -j ACCEPT
iptables -A FORWARD -m multiport -p udp -i eth1 -d 0.0.0.0--dports domain -j ACCEPT
iptables -A FORWARD -m multiport -p udp -i eth0 -s 0.0.0.0 --sports domain -j ACCEPT

Все таки разрешаем немного пинга

iptables -A FORWARD -m multiport -p icmp -i eth0 -d 192.168.0.0/24 --dports 0, 3,11 -j ACCEPT
iptables -A FORWARD -m multiport -p icmp -i eth1 -d 0.0.0.0 --dports 8, 3,11 -j ACCEPT

Устанавливаем журналирование для всех отброшенных пакетов

iptables -A FORWARD -m tcp -p tcp -j LOG
iptables -A FORWARD -m udp -p udp -j LOG
iptables -A FORWARD -m udp -p icmp -j LOG

Friday, December 5, 2008

Quik Note: Мониторинг и отладка

  • ps -eafw отобразить запущенные процессы, используемые ими ресурсы и другую полезную информацию (единожды)
  • ps -e -o pid,args --forest вывести PID'ы и процессы в виде дерева
  • pstree отобразить дерево процессов
  • kill -TERM 98989 Корректно завершить процесс с PID 98989
  • kill -1 98989 заставить процесс с PID 98989 перепрочитать файл конфигурации
  • kill -HUP 98989
  • lsof -p 98989 отобразить список файлов, открытых процессом с PID 98989
  • lsof /home/user1 отобразить список открытых файлов из директории /home/user1
  • strace -c ls >/dev/null вывести список системных вызовов, созданных и полученных процессом ls
  • strace -f -e open ls >/dev/null вывести вызовы бибилотек
  • watch -n1 'cat /proc/interrupts' отображать прерывания в режиме реального времени
  • last reboot отобразить историю перезагрузок системы
  • last user1 отобразить историю регистрации пользователя user1 в системе и время его нахождения в ней
  • lsmod вывести загруженные модули ядра
  • free -m показать состояние оперативной памяти в мегабайтах
  • smartctl -A /dev/hda контроль состояния жёсткого диска /dev/hda через SMART
  • smartctl -i /dev/hda проверить доступность SMART на жёстком диске /dev/hda
  • tail /var/log/dmesg вывести десять последних записей из журнала загрузки ядра
  • tail /var/log/messages вывести десять последних записей из системного журнал

Quick Note: iptables

  • iptables -t filter -nL отобразить все цепочки правил
  • iptables -nL
  • iptables -t nat -L отобразить все цепочки правил в NAT-таблице
  • iptables -t filter -F очистить все цепочки правил в filter-таблице
  • iptables -F
  • iptables -t nat -F очистить все цепочки правил в NAT-таблице
  • iptables -t filter -X удалить все пользовательские цепочки правил в filter-таблице
  • iptables -t filter -A INPUT -p tcp --dport telnet -j ACCEPT позволить входящее подключение telnet'ом
  • iptables -t filter -A OUTPUT -p tcp --dport http -j DROP блокировать исходящие HTTP-соединения
  • iptables -t filter -A FORWARD -p tcp --dport pop3 -j ACCEPT позволить "прокидывать" (forward)


Quik Note: Команды для настройки SAMBA

  • nbtscan ip_addr разрешить netbios-имя nbtscan не во всех системах ставится по-умолчанию, возможно, придётся доустанавливать вручную. nmblookup включен в пакет samba.
  • nmblookup -A ip_addr
  • smbclient -L ip_addr/hostname отобразить ресурсы, предоставленные в общий доступ на windows-машине
  • smbget -Rr smb://ip_addr/share подобно wget может получить файлы с windows-машин через smb-протокол
  • mount -t smbfs -o username=user,password=pass //winclient/share /mnt/share смонтировать smb-ресурс, предоставленный на windows-машине, в локальную файловую систему

Quik Note: Команды для работы с сетью

  • ifconfig eth0 promisc перевести интерфейс eth0 в promiscuous-режим для "отлова" пакетов (sniffing)
  • ifconfig eth0 -promisc отключить promiscuous-режим на интерфейсе eth0
  • route -n вывести локальную таблицу маршрутизации
  • netstat -rn route add -net 0/0 gw IP_Gateway задать ip-адрес шлюза по умолчанию (default gateway)
  • route add -net 192.168.0.0 netmask 255.255.0.0 gw 192.168.1.1 добавить статический маршрут в сеть 192.168.0.0/16 через шлюз с ip-адресом 192.168.1.1
  • route del 0/0 gw IP_gateway удалить ip-адрес шлюза по умолчанию (default gateway)
  • host http://www.linuxguide.it разрешить имя http://www.linuxguide.it хоста в ip-адрес и наоборот
  • tcpdump tcp port 80 отобразить весь трафик на TCP-порт 80 (обычно - HTTP)