Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
книги хакеры / практический хакинг.pdf
Скачиваний:
24
Добавлен:
19.04.2024
Размер:
31.35 Mб
Скачать

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Рис.4.11.Пакет MQTT CONNACK с кодом 0x00,указывающим,что учетные данные были верны

Написание модуля MQTT Authentication-Cracking в Ncrack

В этом разделе мы расширим Ncrackдля поддержки MQTT,что позво- литвзламыватьучетныеданные этого протокола.Ncrack (https://nmap. org/ncrack/) – это высокоскоростной сетевой инструмент для взлома аутентификации с модульной архитектурой. Он поддерживает мно- жество сетевых протоколов (для версии 0.7 это SSH, RDP, FTP, Telnet, HTTP и HTTPS, WordPress, POP3 и POP3S, IMAP, CVS, SMB, VNC, SIP, Redis,PostgreSQL,MQTT,MySQL,MSSQL,MongoDB,Cassandra,WinRM, OWA и DICOM) и входит в набор инструментов безопасности­ Nmap. Его модули выполняют словарные атаки против аутентификации протокола, и он поставляется с различными списками имен пользо- вателей и паролей.

Последняя рекомендуемая версия Ncrack находится на GitHub по адресу https://github.com/nmap/ncrack/, хотя предварительно скомпили- рованные пакеты существуют для таких дистрибутивов, как Kali Li- nux. Последняя версия уже включает модуль MQTT, поэтому, если вы хотите воспроизвести следующие шаги самостоятельно, найдите на git самую свежую версию непосредственно перед добавлением мо- дуля. Для этого используйте следующие команды:

root@kali:~# git clone https://github.com/nmap/ncrack.git root@kali:~# cd ncrack

root@kali:~/ncrack# git checkout 73c2a165394ca8a0d0d6eb7d30aaa862f22faf63

Краткое знакомство с архитектурой Ncrack

Как и Nmap, Ncrack написан на C/C++ и использует библиотеку Nmap Nsock для асинхронной обработки сокетов, управляемой событиями. Этоозначает,чтовместоиспользованиянесколькихпотоковилипро- цессов для достижения параллелизма Ncrack непрерывно опрашива- ет дескрипторы сокетов, зарегистрированные каждым вызванным

Оценка сети  109

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

модулем.Каждый раз,когда происходитновое сетевое событие,такое

 

 

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w Click

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

df-x chan

 

o

 

как чтение, запись или тайм-аут, он переходит к предварительно за-

.

.c

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

 

 

 

 

 

e

 

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

ное руководство разработчика (https://nmap.org/ncrack/devguide.html).

Мы ограничимся объяснением того, какое место парадигма управля- емых событиями сокетов занимает в разработке модуля MQTT.

Компиляция Ncrack

Дляначалаубедитесь,чтоувасестьработающаякомпилируемаявер- сия Ncrack в вашей тестовой среде. Если вы используете Kali Linux, убедитесь, что у вас есть все доступные инструменты сборки и зави- симости, выполнив команду:

root@kali:~# sudo apt install build-essential autoconf g++ git libssl-dev

Затем клонируйте последнюю версию Ncrack с GitHub, введя:

root@kali:~# git clone https://github.com/nmap/ncrack.git

Для компиляции достаточно ввести следующую строку во вновь созданном каталоге ncrack:

root@kali:~/ncrack# ./configure && make

Теперь у вас должен быть рабочий двоичный файл Ncrack внут­ри локального каталога. Чтобы проверить это, попробуйте запустить Ncrack без аргументов:

root@kali:~/ncrack# ./ncrack

Должно появиться меню справки.

Инициализация модуля

Вам необходимо выполнять некоторые стандартные шаги каждый раз,когда вы создаете новый модульв Ncrack.Сначала отредактируй- те файл ncrack-services, включив в него новый протокол и его порт поумолчанию.ПосколькуMQTTиспользуетTCP-порт1833,мыдобав- ляем следующую строку (можно в любом месте файла):

mqtt 1883/tcp

110  Глава 4

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Во-вторых,включите ссылку на основную функцию вашего модуля

 

 

 

 

 

m

w Click

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

(например,ncrack_mqtt в нашем случае) в функцию call_module внутd­f-x chan

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

 

 

 

 

e

 

рифайлаncrack.cc.Всеосновныефункциимодуляимеютсоглашение об именах ncrack_protocol, заменяющее опцию protocol на факти- ческое имя протокола. Добавьте следующие две строки в основной регистр else-if:

else if (!strcmp(name, "mqtt")) ncrack_mqtt(nsp, con);

В-третьих, мы создаем главный файл для нашего нового модуля в каталоге модулей и называем его ncrack_mqtt.cc.В файле modules.h должнобытьопределениеосновнойфункциимодуля,поэтомумыего добавляем. Все функции основного модуля имеют одинаковые аргу-

менты (nsock_pool, Connection *):

void ncrack_mqtt(nsock_pool nsp, Connection *con);

В-четвертых, мы редактируем configure.ac в основном катало- ге Ncrack, чтобы включить новые файлы модулей ncrack_mqtt.cc

и ncrack_mqtt.o в переменные MODULES_SRCS и MODULES_OBJS со-

ответственно:

MODULES_SRCS="$MODULES_SRCS ncrack_ftp.cc ncrack_telnet.cc ncrack_http.cc \ ncrack_pop3.cc ncrack_vnc.cc ncrack_redis.cc ncrack_owa.cc \ ncrack_imap.cc ncrack_cassandra.cc ncrack_mssql.cc ncrack_cvs.cc \ ncrack_wordpress.cc ncrack_joomla.cc ncrack_dicom.cc ncrack_mqtt.cc" MODULES_OBJS="$MODULES_OBJS ncrack_ftp.o ncrack_telnet.o ncrack_http.o \ ncrack_pop3.o ncrack_vnc.o ncrack_redis.o ncrack_owa.o \

ncrack_imap.o ncrack_cassandra.o ncrack_mssql.o ncrack_cvs.o \ ncrack_wordpress.o ncrack_joomla.o ncrack_dicom.o ncrack_mqtt.o"

Обратите внимание, что после внесения каких-либо изменений в configure.ac нам необходимо запустить инструмент autoconf внут­ ри основного каталога,чтобы создать новый скриптнастройки,кото- рый будет использоваться при компиляции:

root@kali:~/ncrack# autoconf

Основной код

Теперь давайте разработаем код модуля MQTT в файл ncrack_mqtt. cc.Этотмодуль проведетсловарную атаку на аутентификацию серве- ра MQTT. В листинге 4.1 показана первая часть нашего кода, которая включает заголовки и объявления функций.

Оценка сети  111

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

Листинг 4.1. Подключение заголовочных файлов и объявления функций

#include "ncrack.h" #include "nsock.h" #include "Service.h" #include "modules.h"

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

#define MQTT_TIMEOUT 20000

extern void ncrack_read_handler(nsock_pool nsp, nsock_event nse, void *mydata); extern void ncrack_write_handler(nsock_pool nsp, nsock_event nse, void *mydata); extern void ncrack_module_end(nsock_pool nsp, void *mydata);

static int mqtt_loop_read(nsock_pool nsp, Connection *con); enum states { MQTT_INIT, MQTT_FINI };

Файл начинается с включения локального заголовка, стандартно- го для каждого модуля. Затем в MQTT_TIMEOUT мы определяем как долго будем ждать, пока не получим ответ от брокера. Мы будем ис- пользовать это значение позже в коде. Затем объявляем три важных обработчика обратного вызова: ncrack_read_handler и ncrack_write_ handler для чтения и записи данных в сеть и ncrack_module_end, кото- рыйнеобходимовызыватькаждыйраз,когдамызавершаемвесьэтап аутентификации . Эти три функции определены в ncrack.cc, и их семантика здесь не важна.

Функция mqtt_loop_read – это вспомогательная функция с ло- кальной областью видимости (это означает, что она видна только в файле модуля из-за статического модификатора),которая анализи- руетвходящиеданныеMQTT.Наконец,унасбудетдвасостояниявна- шем модуле . Состояния на языке Ncrack относятся к конкретным этапам процесса аутентификации для конкретного протокола, кото- рый мы взламываем. Каждое состояние выполняет микродействие, которое почти всегда включает регистрацию определенного сетевого события Nsock.Например,в состоянии MQTT_INIT мы отправляем наш первый пакет MQTT CONNECT брокеру. Затем в состоянии MQTT_FINI мы получаем от него пакет CONNACK. Оба состояния включают запись или чтение данных в сеть.

Вторая часть файла определяет две структуры, которые помогут намуправлятьпакетамиCONNECT иCONNACK.Влистинге4.2показанкод для первого из них.

Листинг 4.2. Структура для управления пакетом CONNECT

struct connect_cmd {

 

 

 

uint8_t message_type;

/* 1

для

пакета CONNECT */

uint8_t msg_len;

/* длина

оставшегося пакета */

uint16_t prot_name_len; /*

должно быть 4 для "MQTT" */

u_char protocol[4];

/* здесь

всегда "MQTT" */

uint8_t version;

/* 4

для

MQTT версии 3.1.1 */

uint8_t flags;

/* 0xc2 для следующих флагов: username, password, clean session */

uint16_t keep_alive;

/* 60 секунд */

uint16_t client_id_len; /*

должно быть 6 для идентификатора "Ncrack" */

112  Глава 4

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

to

 

 

 

 

 

 

u_char client_id[6]; /* соответствует Ncrack */

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

m

w Click

 

 

 

 

 

 

o

uint16_t username_len; /* длина строки имени пользователя */

 

w

 

 

 

 

 

 

 

 

 

 

.

 

 

 

 

 

e

 

 

 

p

df

 

 

 

g

.c

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

 

-xcha

 

 

 

 

 

/* остаток пакета, динамически добавляемый из буфера:

 

 

 

 

 

 

 

 

 

 

 

 

*username (dynamic length),

*password_length (uint16_t)

*password (dynamic length)

*/

connect_cmd() { /* конструктор – инициализация указанными значениями */ message_type = 0x10;

prot_name_len = htons(4); memcpy(protocol, "MQTT", 4); version = 0x04;

flags = 0xc2; keep_alive = htons(60);

client_id_len = htons(6); memcpy(client_id, "Ncrack", 6);

}

} __attribute__((__packed__)) connect_cmd;

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

МыопределяемструктуруСconnect_cmd,чтобыонасодержалаожи- даемые поля пакета MQTT CONNECT в качестве ее членов. Поскольку начальная часть этого типа пакета состоит из фиксированного заго- ловка, легко статически определить значения этих полей. Пакет CONNECT – это управляющий пакет MQTT, который имеет:

zzфиксированный заголовок, состоящий из типа пакета и длины полей;

zzпеременный заголовок, состоящий из имени протокола с префик-

сомProtocol Name Length (длинаименипротокола),Protocol Level

(уровень протокола), Connect Flags (флаги подключения) и Keep Alive (поддержание активного соединения);

zzполезную нагрузку с одним или несколькими полями с префик- сом длины. Наличие этих полей определяется флагами подклю- чения – в нашем случае идентификатором клиента, именем пользователя и паролем.

Чтобы точно определить структуру пакета MQTT CONNECT, обрати- тесь к официальной спецификации протокола по адресу https://docs. oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901033. Для удобства вы можете использовать созданную нами табл. 4.2. Мы также рекомен- дуем поискать ту же структуру пакета в дампе трафика Wireshark (на- пример,рис.4.9).Какправило,увасбудетнесколькоспособовсопостав- ления полей пакета в полях структуры C; наш способ–один из многих.

Message_type – это четырехбитное поле, которое определяет тип пакета. Значение 1 определяет пакет CONNECT. Обратите внимание, что мы выделяем восемь бит (uint8_t) для этого поля,чтобы покрыть четыре младших бита, зарезервированных для этого типа пакета (все 0). Msg_len – это количество байтов, оставшихся в текущем па- кете, не включая байты поля длины. Он соответствует полю длины пакета Length.

Оценка сети  113

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

d

 

 

 

F

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

to

Таблица 4.2.Структура пакета MQTT CONNECT: фиксированный заголовок,

 

 

 

 

 

w

 

 

 

 

w Click

 

 

 

 

o

m

заголовок и полезная нагрузка,разделенные жирной рамкой

 

w

 

 

 

 

 

 

 

 

.

df-xchaпеременныйn

 

 

 

 

 

.c

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

 

 

 

 

e

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Бит

7

6

5

4

3

2

1

0

Тип пакета

Тип пакета (1 для CONNECT)

 

Зарезервировано (все 0)

 

Длина

Оставшаяся длина пакета

 

 

 

 

 

 

Длина имени

MSB длины имени протокола (4 для «MQTT»)

 

 

 

 

протокола

LSB длины имени протокола

 

 

 

 

 

 

«M»

 

 

 

 

 

 

 

Имя протокола

«Q»

 

 

 

 

 

 

 

«T»

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

«T»

 

 

 

 

 

 

 

Уровень

Уровень протокола (4 для MQTT версии 3.1.1)

 

 

 

 

протокола

 

 

 

 

 

 

 

 

Флаги

Флаг имени

Флаг

Будет

QoS

 

Флаг

Очистка

Зарезер-

соединения

пользователя

пароля

сохранен

 

 

 

сессии

вировано

Удержание

Удержание MSB

 

 

 

 

 

 

 

соединения

Удержание LSB

 

 

 

 

 

 

 

Длина

MSB длины идентификатора клиента

 

 

 

 

 

ID клиента

LSB длины идентификатора клиента

 

 

 

 

 

ID клиента

(произвольный размер–зависит от длины поля имени пользователя)

 

Длина имени

MSB длины имени пользователя

 

 

 

 

 

пользователя

LSB длины имени пользователя

 

 

 

 

 

Имя пользователя

(произвольный размер–зависит от длины поля имени пользователя)

 

Длина пароля

MSB длины пароля

 

 

 

 

 

 

LSB длины пароля

 

 

 

 

 

 

 

 

 

 

 

 

 

Пароль

(произвольный размер–зависит от длины поля пароля)

 

 

 

Фиксированный

заголовок

Произвольный

заголовок

Полезная

нагрузка

В заголовке переменной prot_name_len и protocol соответствуют полям Protocol Name Length и Protocol Name. Длина этого поля всегда должна быть равной 4, поскольку имя протокола всегда представле- но заглавной строкой в кодировке UTF-8 "MQTT". Поле version, пред- ставляющее поле уровня протокола, имеет значение 0x04 для MQTT версии 3.1.1, но в более поздних стандартах могут использоваться другие значения. Параметр flags, представленный в поле Connect Flags, определяет поведение MQTT-соединения и наличие или от- сутствие полей в полезной нагрузке.Мы инициализируем его значе- нием 0xC2, чтобы установить три флага: username, password и clean session. Параметр keep_alive, представляющий поле Keep Alive,

представляетсобой временной интервал в секундах,определяющий максимальное время, которое может пройти между отправкой по- следовательных пакетов управления. В нашем случае это не важно, но мы будем использовать то же значение, что и приложение Mos- quitto.

Наконец, полезная нагрузка пакета начинается с client_id_length и client_id. Идентификатор клиента всегда должен быть первым по- лем в полезной нагрузке пакета CONNECT. Он должен быть уникаль- нымдлякаждогоклиента,поэтомумыбудемиспользоватьNcrackдля нашего модуля. Остальные поля – это Username Length (username_len),

Username, Password Length и Password. Поскольку мы ожидаем исполь-

зовать разные имена пользователей и пароли для каждого соедине- ния(потомучтовыполняематакупословарю),позже вкодемыдина- мически выделяем место под последние три параметра.

114  Глава 4

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Затем мы используем конструктор структуры для инициализа-

 

 

 

 

 

m

w Click

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

ции этих полей значениями, которые, как мы знаем, останутся неизd-f-x chan

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

 

 

 

 

e

 

менными.

Наш сервер отправитпакетCONNACK в ответна пакетCONNECT от кли- ента. Листинг 4.3 показывает структуру пакета CONNACK.

Листинг 4.3. Структура C для управления пакетом CONNACK

struct ack {

uint8_t message_type; uint8_t msg_len; uint8_t flags; uint8_t ret_code;

} __attribute__((__packed__)) ack;

Message_type и msg_len составляют стандартный фиксированный заголовок пакета управления MQTT, аналогичный заголовку пакета CONNECT. MQTT устанавливает значение message_type для пакета CONNACK равным 2. Для этого типа пакета флаги обычно равны 0. Вы мо- жете увидетьэтотакже на рис.4.10 и 4.11.Ret_code –наиболее важное поле, потому что в зависимости от его значения мы можем опреде- лить, были ли приняты наши учетные данные. Код возврата 0x00 оз- начает принятое соединение, а код возврата 0x05 указывает, что со- единение не авторизовано (как мы видели на рис. 4.10), поскольку учетные данные либо не были предоставлены, либо неверны. Хотя есть и другие возвращаемые значения, для упрощения кода модуля мы предположим, что любое значение, отличное от 0x00, означает, что мы должны попробовать другие учетные данные.

Атрибут packed – это директива компилятору C не добавлять ка- ких-либо отступов между полями (что обычно делается автомати- чески для оптимизации доступа к памяти), чтобы все оставалось не- тронутым. Мы сделали то же самое для структуры connect_cmd. Это хорошая практика для структур, используемых в сети.

Затем определяем функцию с именем mqtt_loop_read для анализа пакета CONNACK, как показано в листинге 4.4.

Листинг 4.4. Определение функции mqtt_loop_read, которая отвечает за синтаксический анализ пакетов CONNACK, и проверка кода возврата

static int

mqtt_loop_read(nsock_pool nsp, Connection *con)

{

struct ack *p;

if (con->inbuf == NULL || con->inbuf->get_len() < 4) { nsock_read(nsp, con->niod, ncrack_read_handler, MQTT_TIMEOUT, con); return -1;

}

p = (struct ack *)((char *)con->inbuf->get_dataptr());

if (p->message_type != 0x20) /* отвергнуть, если это не MQTT ACK */

Оценка сети  115

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

return -2;

if (p->ret_code == 0) /* вернуть 0 только если код возврата равен 0 */ return 0;

return -2;

}

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Сначала мы объявляем локальный указатель p на структуру типа ack. Затем проверяем, получили ли мы какие-либо данные в нашем входящем буфере (содержит ли указатель con->inbuf значение NULL), или длина полученных данных меньше 4, что составляет минималь- ный размер ожидаемого ответа сервера. Если любое из этих условий истинно, нам нужно продолжать ждать входящих данных, поэтому мы планируем событие чтения nsock, которое будет обрабатываться нашим стандартным ncrack_read_handler.

Как это происходит, мы здесь не будем обсуждать, но важно пони- матьасинхроннуюприродуэтогометода.Сутьвтом,чтоэтифункции будут выполнять свою работу после того, как модуль вернет управ- ление основному механизму Ncrack, что произойдет по завершении функции ncrack_mqtt. Чтобы знать, где модуль останавливался для каждого TCP-соединения при следующем вызове, Ncrack сохраняет текущее состояние в переменной con-> state. Дополнительная ин- формациятакжесохраняетсявдругихчленахклассаConnection,таких как буферы для входящих (inbuf) и исходящих (outbuf) данных.

Как только мы получим полный ответ CONNACK, мы можем пере- строить наш локальный указатель p на буфер , предназначенный для входящих сетевых данных. Мы приводим этот буфер к указателю struct ack.Проще говоря,это означает,чтотеперь мы можем исполь- зовать указатель p, чтобы легко просматривать элементы структуры. Затем первое, что мы проверяем в полученном пакете,– является ли онпакетомCONNACK;еслиэтонетак,намнеследуетбеспокоитьсяоего дальнейшем анализе.Если же это пакетCONNACK,мы проверяем,равен ли код возврата 0 , и в этом случае возвращаем 0, чтобы уведомить вызывающего абонента о правильности учетных данных. В против- ном случае произошла ошибка или учетные данные были неверны- ми, и мы возвращаем –2.

Последняя часть нашего кода – это основная функция ncrack_mqtt, которая обрабатывает всю логику для аутентификация на сервере MQTT. Он представлен двумя листингами: листинг 4.5 представляет логикусостоянияMQTT_INIT,алистинг4.6–логикусостоянияMQTT_FINI.

Листинг 4.5. Код состояния MQTT_INIT, который отправляет пакет

CONNECT

void

ncrack_mqtt(nsock_pool nsp, Connection *con)

{

nsock_iod nsi = con->niod;

116  Глава 4

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

struct connect_cmd cmd;

 

 

 

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

m

uint16_t pass_len;

w Click

 

 

 

 

 

 

o

 

w

 

 

 

 

 

 

 

 

 

 

.

 

 

 

 

 

e

 

 

 

 

p

df

 

 

 

g

.c

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

 

-x cha

 

 

 

 

 

switch (con->state)

{

case MQTT_INIT: con->state = MQTT_FINI;

delete con->inbuf; con->inbuf = NULL; if (con->outbuf)

delete con->outbuf; con->outbuf = new Buf();

/* длина сообщения равна длине структуры плюс длина имени пользователя

*и пароля минус 2 первых байта (тип сообщения и длина сообщения) которые

*не подсчитываются

*/

cmd.msg_len = sizeof(connect_cmd) + strlen(con->user) + strlen(con->pass) + sizeof(pass_len) - 2;

cmd.username_len = htons(strlen(con->user)); pass_len = htons(strlen(con->pass));

con->outbuf->append(&cmd, sizeof(cmd)); con->outbuf->snprintf(strlen(con->user), "%s", con->user); con->outbuf->append(&pass_len, sizeof(pass_len)); con->outbuf->snprintf(strlen(con->pass), "%s", con->pass);

nsock_write(nsp, nsi, ncrack_write_handler, MQTT_TIMEOUT, con,

(const char *)con->outbuf->get_dataptr(), con->outbuf->get_len());

break;

Первый блок кода в нашей основной функции объявляет три ло- кальныепеременные.Nsockиспользуетпеременнуюnsock_iod вся- кий раз, когда мы регистрируем сетевое чтение и записываем собы- тия через nsock_read и nsock_write соответственно. Структура struct cmd, которую мы определили в листинге 4.2, обрабатывает входящий пакет CONNECT. Обратите внимание, что его конструктор автомати- чески вызывается, когда мы объявляем его, поэтому он инициализи- руется значениями по умолчанию, которые мы дали каждому полю. Будем использовать pass_len для временного хранения двухбайтово- го значения длины пароля.

КаждыймодульNcrackимеетоператорswitch ,вкоторомкаждый случай представляет определенный этап аутентификации фазы для конкретного протокола,который мы взламываем.У аутентификации MQTT есть только два состояния: мы начинаем с MQTT_INIT, а затем устанавливаемследующеесостояние как MQTT_FINI.Этоозначает,что, когда мы завершаем выполнение этой фазы и возвращаем управле- ние основному механизму Ncrack, оператор switch продолжится со следующего состояния, MQTT_FINI (см.листинг 4.6), когда модуль сно- ва запускается для этого конкретного TCP-соединения.

Оценка сети  117

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

Затем проверяем, чтобы наши буферы для приема (con->inbuf)

 

 

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w Click

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

df-x chan

 

o

 

и отправки (con->outbuf) сетевых данных были пустыми .Далее об-

.

.c

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

 

 

 

 

 

e

 

новляем оставшееся поле длины в нашей структуре cmd . Помните, что оно вычисляется как оставшаяся длина пакета CONNECT, не вклю- чая поле длины. Мы должны учитывать размер трех дополнительных полей(имяпользователя,длинапароляипароль),которыедобавляем в конце нашего пакета, потому что мы не включили их в структуру cmd. Также обновляем поле длины имени пользователя с учетом фак- тического размера текущего имени пользователя. Ncrack автомати- чески выполняет итерацию по словарю, обновляет имя пользователя и пароль в переменных user и pass класса Connection соответственно. Мы также вычисляем длину пароля и сохраняем ее в pass_len. Затем начинаем создавать наш исходящий пакет CONNECT, сначала добавляя обновленную структуру cmd в outbuf , а затем динамически добав- ляядополнительныетри поля.Класс Buffer (inbuf,outbuf) имеетсвои собственные удобные функции, такие как append и snprintf, с помо- щью которых вы можете легко и постепенно добавлять отформати- рованные данные для создания собственных полезных нагрузок TCP.

Кроме того, мы планируем отправить наш пакет из буфера outbuf в сеть, зарегистрировав событие сетевой записи через nsock_write, обрабатываемое ncrack_write_handler . Затем завершаем switch и ncrack_mqtt (на данный момент) и возвращаем управление выпол- нением основному механизму, который среди других задач будет перебирать все зарегистрированные сетевые события (например, то, что мы только что запланировали выше с использованием функции ncrack_mqtt) и обрабатывать их.

Следующее состояние, MQTT_FINI, принимает и анализирует входя- щий пакет CONNACK от брокера и проверяет, были ли предоставлены наши учетные данные правильно. В листинге 4.6 показан код, кото- рый входит в то же определение функции, что и листинг 4.5.

Листинг 4.6. Код состояния MQTT_FINI, который получает входящий пакет CONNACK и оценивает, верны ли отправленные нами имя пользователя и пароль

case MQTT_FINI:

if (mqtt_loop_read(nsp, con) == -1) break;

else if (mqtt_loop_read(nsp, con) == 0) con->auth_success = true;

con->state = MQTT_INIT; delete con->inbuf; con->inbuf = NULL;

return ncrack_module_end(nsp, con);

}

}

Мы начинаем с того, что спрашиваем mqtt_loop_read, получили ли мы ответсервера .Вспомните излистинга 4.4,что он вернет-1,если

118  Глава 4