Введение:
В ноябре 2021 года SentinelLabs публично сообщила об удаленном переполнении кучи, которое они обнаружили в сетевом модуле ядра Linux для протокола Transparent Inter-Process Communication (TIPC) (CVE-2021-43267).
TL;DR on TIPC
Прозрачная межпроцессная связь (TIPC) — это механизм IPC, предназначенный для связи внутри кластера. Топология кластера управляется вокруг концепции узлов и связей между этими узлами.
Возьмем пример из Руководства по началу работы с TIPC:
eth0 Здесь мы настраиваем узел для использования однонаправленного канала с типом носителя Ethernet на интерфейсе.
Теперь TIPC знает, что он может использовать eth0 для связи через Ethernet.
Время добраться до самой уязвимости.
CVE-2022-0435
Одной из многих функций модуля TIPC является его структура мониторинга. Представленный в ядре в июне 2016 года, фреймворк использует распределенный «алгоритм контроля перекрывающихся колец» для мониторинга соседних узлов в одном домене.
Статус пира отслеживается метко названной struct
Как мы видим, среди прочего, мы сохраняем ссылку на структуру
Копии этих записей домена передаются между одноранговыми узлами, чтобы сообщить друг другу их соответствующие топологические представления. Затем каждый узел сохраняет копию через
В TIPC сообщения между узлами классифицируются по полям заголовка в общий «пользователь сообщения» (то есть, какая часть стека TIPC использует это сообщение), а затем далее в «типы сообщений».
Эти записи домена используют пользователя сообщения
При получении
Звучит просто, правда? Давайте углубимся в код, чтобы увидеть, где проблема:
Как злоумышленник, мы можем ответить на один из широковещательных пакетов и установить связь, притворившись пиром. Затем мы сможем отправить созданную запись домена размером 1072 байта (с 264 участниками) и пройти проверку.
Нам нечего кэшировать [6], так как это была первая запись домена, которую мы отправили с вредоносного узла, но теперь узел без проблем выделил место для нашей 1072-байтовой записи [8], наша пара структур и т. д. теперь ссылается на нее. [9].
Что такое
Единственными ограничениями для нашей структуры полезной нагрузки
Поскольку
Резюмируя все, что мы рассмотрели: CVE-2022-0435 позволяет локальному или удаленному злоумышленнику вызвать переполнение стека в сетевой подсистеме TIPC — размер переполнения ограничен MTU включенной несущей среды (Ethernet/Infiniband/UDP). .
Ограничения на фактическое содержание полезной нагрузки очень малы и в основном произвольны.
Скопировав более 272 байт в буфер стека
CVE-2022-0435: A Remote Stack Overflow in The Linux Kernel
В ноябре 2021 года SentinelLabs публично сообщила об удаленном переполнении кучи, которое они обнаружили в сетевом модуле ядра Linux для протокола Transparent Inter-Process Communication (TIPC) (CVE-2021-43267).
TL;DR on TIPC
Прозрачная межпроцессная связь (TIPC) — это механизм IPC, предназначенный для связи внутри кластера. Топология кластера управляется вокруг концепции узлов и связей между этими узлами.
Возьмем пример из Руководства по началу работы с TIPC:
Код:
tipc bearer enable media eth dev eth0
eth0 Здесь мы настраиваем узел для использования однонаправленного канала с типом носителя Ethernet на интерфейсе.
Теперь TIPC знает, что он может использовать eth0 для связи через Ethernet.
Время добраться до самой уязвимости.
CVE-2022-0435
Одной из многих функций модуля TIPC является его структура мониторинга. Представленный в ядре в июне 2016 года, фреймворк использует распределенный «алгоритм контроля перекрывающихся колец» для мониторинга соседних узлов в одном домене.
Статус пира отслеживается метко названной struct
tipc_peer, определяемой следующим образом:
Код:
/* struct tipc_peer: state of a peer node and its domain
* @addr: tipc node identity of peer
* @head_map: shows which other nodes currently consider peer 'up'
* @domain: most recent domain record from peer
* @hash: position in hashed lookup list
* @list: position in linked list, in circular ascending order by 'addr'
* @applied: number of reported domain members applied on this monitor list
* @is_up: peer is up as seen from this node
* @is_head: peer is assigned domain head as seen from this node
* @is_local: peer is in local domain and should be continuously monitored
* @down_cnt: - numbers of other peers which have reported this on lost
*/
struct tipc_peer {
u32 addr;
struct tipc_mon_domain *domain;
struct hlist_node hash;
struct list_head list;
u8 applied;
u8 down_cnt;
bool is_up;
bool is_head;
bool is_local;
};
Как мы видим, среди прочего, мы сохраняем ссылку на структуру
tipc_mon_domain. Эта структура представляет записи домена, используемые для определения представления топологии TIPC, такого как известное количество членов. См. определение ниже:
Код:
#define MAX_MON_DOMAIN 64
...
/* struct tipc_mon_domain: domain record to be transferred between peers
* @len: actual size of domain record
* @gen: current generation of sender's domain
* @ack_gen: most recent generation of self's domain acked by peer
* @member_cnt: number of domain member nodes described in this record
* @up_map: bit map indicating which of the members the sender considers up
* @members: identity of the domain members
*/
struct tipc_mon_domain {
u16 len;
u16 gen;
u16 ack_gen;
u16 member_cnt;
u64 up_map;
u32 members[MAX_MON_DOMAIN];
};
Копии этих записей домена передаются между одноранговыми узлами, чтобы сообщить друг другу их соответствующие топологические представления. Затем каждый узел сохраняет копию через
tipc_peer->domain field.В TIPC сообщения между узлами классифицируются по полям заголовка в общий «пользователь сообщения» (то есть, какая часть стека TIPC использует это сообщение), а затем далее в «типы сообщений».
Эти записи домена используют пользователя сообщения
LINK_PROTOCOLTIPC и типы сообщений STATE_MSG для связи между ссылками.При получении
STATE_MSG, если оно проходит проверку заголовка и некоторые другие проверки, тело сообщения передается функции tipc_mon_rcv.Звучит просто, правда? Давайте углубимся в код, чтобы увидеть, где проблема:
Код:
/* tipc_mon_rcv - process monitor domain event message
*
* @data: STATE_MSG body
* @dlen: STATE_MSG body size (taken from TIPC header)
*/
void tipc_mon_rcv(struct net *net, void *data, u16 dlen, u32 addr,
struct tipc_mon_state *state, int bearer_id)
{
...
struct tipc_mon_domain *arrv_dom = data;
struct tipc_mon_domain dom_bef; [0]
...
/* Sanity check received domain record */ [1]
if (dlen < dom_rec_len(arrv_dom, 0)) [2]
return;
if (dlen != dom_rec_len(arrv_dom, new_member_cnt)) [3]
return;
if (dlen < new_dlen || arrv_dlen != new_dlen) [4]
return;
...
/* Drop duplicate unless we are waiting for a probe response */
if (!more(new_gen, state->peer_gen) && !probing) [5]
return;
...
/* Cache current domain record for later use */
dom_bef.member_cnt = 0;
dom = peer->domain;
if (dom) [6]
memcpy(&dom_bef, dom, dom->len); [7]
/* Transform and store received domain record */
if (!dom || (dom->len < new_dlen)) {
kfree(dom);
dom = kmalloc(new_dlen, GFP_ATOMIC); [8]
peer->domain = dom; [9]
if (!dom)
goto exit;
}
...
Как злоумышленник, мы можем ответить на один из широковещательных пакетов и установить связь, притворившись пиром. Затем мы сможем отправить созданную запись домена размером 1072 байта (с 264 участниками) и пройти проверку.
Нам нечего кэшировать [6], так как это была первая запись домена, которую мы отправили с вредоносного узла, но теперь узел без проблем выделил место для нашей 1072-байтовой записи [8], наша пара структур и т. д. теперь ссылается на нее. [9].
Код:
dom = {
len = 1072,
gen = 3,
ack_gen = 3,
member_cnt = 264;
up_map = 0xffffffffffffffff;
u32 members[264] = 0x1337...
};
Что такое
&dom_bef? Это локальная структура [0], и поскольку она ожидает, что members будет массивом из 64 элементов, она размещается в стеке как 272-байтовый буфер. Мы собираемся скопировать в него 1072 байта.Единственными ограничениями для нашей структуры полезной нагрузки
tipc_mon_domain являются: len = dlen = sizeof(len,gen,ack_gen,member_cnt,up_map) + member_cnt * sizeof(u32) -gen должен быть больше, чем последняя принятая запись - должна подходить для MTU носителя носителя.Поскольку
members находится в конце структуры, теперь мы можем свободно перезаписывать что угодно в стеке с произвольными полезными нагрузками, со значительными требованиями к размеру. Мы обсудим возможность использования этого в следующей статье.Резюмируя все, что мы рассмотрели: CVE-2022-0435 позволяет локальному или удаленному злоумышленнику вызвать переполнение стека в сетевой подсистеме TIPC — размер переполнения ограничен MTU включенной несущей среды (Ethernet/Infiniband/UDP). .
Ограничения на фактическое содержание полезной нагрузки очень малы и в основном произвольны.
Скопировав более 272 байт в буфер стека
dom_bef, мы смогли перезаписать все, что находится после него в стеке, включая стековую канарейку, а также базовый указатель и адрес возврата, что могло привести к перехвату потока управления.CVE-2022-0435: A Remote Stack Overflow in The Linux Kernel