Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
книги хакеры / практический хакинг.pdf
Скачиваний:
23
Добавлен:
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

 

 

 

 

--

--@param dcm DICOM object

--@return (status, data) возвращает данные, если status равен true, иначе возвращает сообщение об ошибке.

function receive(dcm)

local status, data = dcm["socket"]:receive() if status == false then

return false, data end

stdnse.debug2("DICOM: receive() read %d bytes", #data) return true, data

end

 

 

 

 

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

 

 

 

 

Функции send(dcm, data) и receive(dcm) используют функции со- кета Nmap send() и receive() соответственно.Они обращаются к дес- криптору соединения,хранящемуся в переменной dcm["socket"],для чтения и записи пакетов DICOM через сокет.Обратите внимание на stdnse.debug[1-9], который используется для печати отладочных операторов, когда Nmap работает с флагом отладки (-d). В этом слу- чае при использовании stdnse. debug2() будет печать, когда уровень отладки установлен на 2 или выше.

Создание заголовков пакетов DICOM

Теперь,когдамынастроилиосновныеоперацииввода/выводасети,да- вайте создадим функции, отвечающие за формирование сообщений DICOM. Как упоминалось ранее, PDU DICOM использует заголовок для указания своего типа и длины. В движке сценариев Nmap мы исполь- зуем строки для хранения байтовых потоков и строковые функции string.pack() иstring.unpack() длякодированияиизвлеченияинфор- мации с учетом разных форматов и порядка байтов. Чтобы использо- ватьstring.pack() иstring.unpack(),вамнеобходимоознакомитьсясо строками формата Lua, поскольку нужно будет представлять данные в различных форматах. Вы можете прочитать о них на https://www.lua. org/manual/5.3/manual.html#6.4.2. Уделите время тому, чтобы изучить способы записи порядка байтов и распространенные преобразования.

---

--pdu_header_encode(pdu_type, length) кодирует заголовок PDU DICOM

--@param pdu_type тип PDU – беззнаковое целое

--@param length длина сообщения DICOM

--@return (status, dcm) если status равен true, возвращает заголовок.

--если status равен false, dcm содержит сообщение об ошибке

---

function pdu_header_encode(pdu_type, length)

--несколько простых проверок; мы не проверяем диапазоны, чтобы позволить пользователю создавать некорректные пакеты.

if not(type(pdu_type)) == "number" then

return false, "PDU должен быть беззнаковым целым. Диапазон:0-7"

142  Глава 5

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

end

 

 

 

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

m

w Click

 

 

 

 

e

if not(type(length)) == "number" then

w Click

 

 

 

 

e

 

.

 

 

 

 

 

 

 

.

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

 

p

df

 

 

 

g

.c

 

 

 

 

p

df

 

 

 

g

.c

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

 

 

-x cha

 

 

 

 

 

return false, "Длина должна быть беззнаковым целым." end

local header = string.pack("<B >B I4",

pdu_type, -- тип PDU ( 1 байт – беззнаковое целое в формате Big

Endian )

0, -- раздел зарезервирован ( 1 байт, должен быть равен 0x0 ) length) -- длина PDU ( 4 байта – беззнаковое целое в формате

Little Endian)

if #header < MIN_HEADER_LEN then

return false, "Заголовок не должен быть короче 6 байтов. Произошла ошибка." end

return true, header end

Функция pdu_header_encode() кодирует информацию о типе и дли- не PDU. Выполнив несколько простых проверок , мы определяем переменную заголовка. Чтобы закодировать поток байтов в соот- ветствии с порядком байтов и форматом, мы используем string. pack() и строку формата <B> B I4,где <B –это один байтв Big Endian , а > B I4 – байт, за которым следует целое число без знака из четырех байтов в Little Endian . Функция возвращает логическое значение, представляющее состояние операции и результат .

Написание запросов контекстов сообщений A-ASSOCIATE

Крометого,нам нужно написатьфункцию,которая отправляети ана- лизирует запросы и ответы A-ASSOCIATE.Как вы видели ранее в этой главе, сообщение запроса A-ASSOCIATE содержит различные типы контекстов: Application,Presentations и User Info.Поскольку это более длинная функция,давайте разделим ее на части.

Контекст приложения Application Context явно определяет элемен- ты службы и параметры.В DICOM вы часто будете видеть определения информационных объектов (Information Object Definitions, IOD), кото-

рые представляют объекты данных,управляемые через центральный реестр. Вы найдете полный список IOD на сайте http://dicom.nema.org/ dicom/2013/output/chtml/part06/chapter_A.html. Мы будем читать эти IOD

из определений констант, которые мы разместили в начале нашей библиотеки. Давайте запустим DICOM-соединение и создадим кон- текст приложения.

---

--associate(host, port) Пытается связаться с провайдером службы DICOM путем отправки запроса A-ASSOCIATE.

--@param host объект хоста

--@param port объект порта

--@return (status, dcm) если status равен true, возвращает объект DICOM

Анализ сетевых протоколов  143

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

 

 

X

 

 

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

to

--

 

 

 

если status равен false, dcm содержит сообщение об ошибке

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

m

w Click

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

 

 

 

.

 

 

 

---e

 

 

 

 

p

df

 

 

 

 

g

.c

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

-xcha

 

 

 

 

 

function associate(host, port, calling_aet_arg, called_aet_arg) local application_context = ""

local presentation_context = "" local userinfo_context = ""

 

 

 

 

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

 

 

 

 

local status, dcm = start_connection(host, port) if status == false then

return false, dcm end

application_context = string.pack(">B B I2 c" .. #UID_VALUES["APPLICATION_CONTEXT"],

0x10, -- тип элемента (1 байт) 0x0, -- зарезервировано ( 1 байт)

#UID_VALUES["APPLICATION_CONTEXT"], -- длина (2 байта)

UID_VALUES["APPLICATION_CONTEXT"]) -- контекст приложения

Контекст приложения состит из типа (один байт) , зарезервиро- ванного поля (один байт) , длины контекста (два байта) и значе- ния, представленное идентификаторами OID . Чтобы представить эту структуру в Lua, мы используем строку формата B B I2 C[#length]. Можем опустить значение размера из строк в один байт.

Мы создаем контексты представления и информации о пользова- теле аналогичным образом. Вот контекст представления, который определяетAbstract Syntax (абстрактный синтаксис) и Transfer Syntax (синтаксис передачи). Это наборы правил для форматирования и об- мена объектами, и мы представляем их с помощью IOD.

presentation_context = string.pack(">B B I2 B B B B B B I2 c" .. #UID_VALUES["VERIFICATION_ SOP"] .. "B B I2 c".. #UID_VALUES["IMPLICIT_VR"],

0x20, -- тип контекста представления ( 1 байт ) 0x0, -- зарезервировано ( 1 байт )

0x2e, -- длина элемента ( 2 байта )

0x1, -- идентификатор контекста представления ( 1 байт ) 0x0,0x0,0x0, -- зарезервировано ( 3 байта )

0x30, -- дерево абстрактного синтаксиса ( 1 байт ) 0x0, -- зарезервировано ( 1 байт )

0x11, -- длина элемента ( 2 байта )

UID_VALUES["VERIFICATION_SOP"],

0x40, -- синтаксис передачи ( 1 байт ) 0x0, -- зарезервировано ( 1 байт ) 0x11, -- длина элемента ( 2 байта )

UID_VALUES["IMPLICIT_VR"])

Обратите внимание, что может быть несколько контекстов пред- ставления. Затем определяем контекст информации о пользователе:

local implementation_id = "1.2.276.0.7230010.3.0.3.6.2" local implementation_version = "OFFIS_DCMTK_362"

144  Глава 5

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

to

 

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

m

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

e

o

 

 

.

 

 

 

 

 

B

 

 

p

df

 

 

 

g

.c

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

userinfo_context = string.pack(">B B I2 B B I2 I4 B B I2 c" .. #implementation_id ..w" B

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

I2 c".. #implementation_version,

w Click

 

 

 

 

 

 

o

 

w

 

 

 

 

 

 

 

 

 

 

.

 

 

 

 

 

e

 

 

 

 

p

df

 

 

 

g

.c

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

 

-x cha

 

 

 

 

 

0x50, -- тип 0x50 (1 байт)

0x0, -- зарезервировано ( 1 байт ) 0x3a, -- длина ( 2 байта )

0x51, -- тип 0x51 ( 1 байт)

0x0, -- зарезервировано ( 1 байт ) 0x04, -- длина ( 2 байта ) 0x4000, -- данные ( 4 байта ) 0x52, -- тип 0x52 (1 байт )

0x0, -- зарезервировано (1 байт ) 0x1b, -- длина (2 байта)

implementation_id, -- идентификатор реализации ( байты

#implementation_id)

0x55, -- тип 0x55 (1 байт) 0x0, -- зарезервировано (1 байт)

#implementation_version, -- длина (2 байта) implementation_version)

Теперь у нас есть три переменные, содержащие контексты: application_context, presentation_context и userinfo_context.

Чтение аргументов скрипта в движке сценариев Nmap

Добавимконтексты,которыетолькочтосоздали,взаголовокизапрос A-ASSOCIATE. Чтобы позволить другим сценариям передавать аргу- ментынашейфункцииииспользоватьразныезначениядляназваний вызывающих и вызываемых объектов приложения, мы предложим два варианта: необязательный аргумент или вводимые пользовате- лем данные. В движке сценариев Nmap вы можете прочитать аргу- менты скрипта, предоставленные --script-args, используя функцию

Nmap stdnse.get_script_args() следующим образом:

local called_ae_title = called_aet_arg or stdnse.get_script_args("dicom.called_aet") or "ANYSCP"

local calling_ae_title = calling_aet_arg or stdnse.get_script_args("dicom.calling_aet") or "NMAP-DICOM"

if #calling_ae_title > 16 or #called_ae_title > 16 then

return false, "Calling/Called AET field can't be longer than 16 bytes."

еnd

Структура,содержащаязаголовкиприкладныхкомпонентов,долж- на быть длиной 16 байт, поэтому мы используем string.rep(), чтобы заполнить оставшуюся часть буфера пробелами:

--Fill the rest of buffer with %20

called_ae_title = called_ae_title .. string.rep(" ", 16 – #called_ae_title) calling_ae_title = calling_ae_title .. string.rep(" ", 16 – #calling_ae_title)

Анализ сетевых протоколов  145