Skip to content
KitploitKITPLOIT
ИнструментыЭксплойтыБлог
Log in
Отправить
ИнструментыЭксплойтыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

ЛентыКонтактыКонфиденциальность© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2022-25636 — Подробный технический анализ и описание эксплуатации для CVE-2022-25636, уязвимости переполнения кучи в netfilter ядра Linux, позволяющей повышение локальных привилегий через heap spraying и UAF. | Kitploit
Инструменты/GitHubGitHub/chenaotian/cve-2022-25636
Повышение привилегийАнализ уязвимостейЭксплуатацияОбучение и ОбразованиеЭксплуатация Бинарных Файлов
GitHubchenaotian/cve-2022-25636

CVE-2022-25636

Подробный технический анализ и описание эксплуатации для CVE-2022-25636, уязвимости переполнения кучи в netfilter ядра Linux, позволяющей повышение локальных привилегий через heap spraying и UAF.

Репозиторий
32134 лет назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2022-25636 повышение привилегий в netfilter ядра

[toc]

Обзор уязвимости

Идентификатор уязвимости: CVE-2022-25636

Продукт: linux kernel - netfilter

Затрагиваемые версии: linux kernel 5.4 ~

Воздействие: в модуле ядра netfilter присутствует запись за границы кучи; при наличии SYS_ADMIN возможет подъём привилегий.

Настройка среды

Уязвимость находится в модуле ядра netfilter, код в трёх .ko файлах.

nft_dup_netdev.ko  
nf_dup_netdev.ko 
nf_tables.ko 

При запуске через qemu возникают проблемы — модули не загружаются. Используется двухсторонняя отладка через vmware.

В ubuntu 21.10 можно вручную заменить ядро:

apt-get install linux-image-5.13.0-30-generic

Затем удалить исходное ядро и скомпилировать exp:

git clone https://github.com/Bonfee/CVE-2022-25636.git
apt-get install libmnl-dev
apt-get install libfuse-dev
apt-get install libnftnl-dev
make
./exploit

Результат повышения привилегий (успешность менее 50%):

image-20220318151010142

Принцип уязвимости

Место возникновения

Уязвимая функция — nft_fwd_dup_netdev_offload:

linux\net\netfilter\nf_dup_netdev.c : 67 : nft_fwd_dup_netdev_offload

int nft_fwd_dup_netdev_offload(struct nft_offload_ctx *ctx,
			       struct nft_flow_rule *flow,
			       enum flow_action_id id, int oif)
{
	struct flow_action_entry *entry;
	struct net_device *dev;

	/* nft_flow_rule_destroy() releases the reference on this device. */
	dev = dev_get_by_index(ctx->net, oif);
	if (!dev)
		return -EOPNOTSUPP;

	entry = &flow->rule->action.entries[ctx->num_actions++];// выход за границы
	entry->id = id;
	entry->dev = dev;

	return 0;
}
EXPORT_SYMBOL_GPL(nft_fwd_dup_netdev_offload);

При установке flow->rule->action.entries (эта структура переменной длины) отсутствует проверка границ кучи, что приводит к записи за границы (целое число (4 или 5) и указатель).

Стек вызовов

Функция используется в nft_flow_rule_create:

linux\net\netfilter\nf_tables_offload.c : 90 : nft_flow_rule_create

struct nft_flow_rule *nft_flow_rule_create(struct net *net,
					   const struct nft_rule *rule)
{
	struct nft_offload_ctx *ctx;
	struct nft_flow_rule *flow;
	int num_actions = 0, err;
	struct nft_expr *expr;

	expr = nft_expr_first(rule);
	while (nft_expr_more(rule, expr)) {// вычисление num_actions на основе переданного правила
		if (expr->ops->offload_flags & NFT_OFFLOAD_F_ACTION)
			num_actions++;// учитываются только элементы с флагом NFT_OFFLOAD_F_ACTION

		expr = nft_expr_next(expr);
	}

	if (num_actions == 0)
		return ERR_PTR(-EOPNOTSUPP);

	flow = nft_flow_rule_alloc(num_actions);// выделение памяти под num_actions (структура переменной длины)
	if (!flow)
		return ERR_PTR(-ENOMEM);

	expr = nft_expr_first(rule);
	// ctx->num_actions инициализируется 0 ↓
	ctx = kzalloc(sizeof(struct nft_offload_ctx), GFP_KERNEL);
	if (!ctx) {
		err = -ENOMEM;
		goto err_out;
	}
	ctx->net = net;
	ctx->dep.type = NFT_OFFLOAD_DEP_UNSPEC;

	while (nft_expr_more(rule, expr)) {
		if (!expr->ops->offload) {// вызов offload по количеству правил
			err = -EOPNOTSUPP;
			goto err_out;
		}
		err = expr->ops->offload(ctx, flow, expr);// вызов уязвимой функции
		if (err < 0)
			goto err_out;

		expr = nft_expr_next(expr);
	}
	··· ···
    ··· ···
}

Видно, что nft_flow_rule_create выделяет структуру flow на основе количества правил из пользовательского пространства. Для подсчёта используется переменная num_actions, но подсчёт ведётся только для правил с флагом NFT_OFFLOAD_F_ACTION. На их основе выделяется память. При последующей обработке offload цикл выполняется не по num_actions, а по тому же первоначальному количеству правил. Однако здесь уже не проверяется флаг NFT_OFFLOAD_F_ACTION. То есть, если среди переданных правил есть такие, у которых нет флага NFT_OFFLOAD_F_ACTION, то количество вызовов offload будет больше, чем выделено под flow->rule->action.entries. Внутри offload вызывается уязвимая функция nft_fwd_dup_netdev_offload, которая каждый раз увеличивает ctx->num_actions, изначально равный 0. В итоге ctx->num_actions превышает размер массива flow->rule->action.entries, что приводит к выходу за границы.

Некоторые структуры:

struct nft_flow_rule {
	__be16			proto;
	struct nft_flow_match	match;
	struct flow_rule	*rule;
};

struct flow_rule {
	struct flow_match	match;
	struct flow_action	action;
};

struct flow_action {
	unsigned int			num_entries;
	struct flow_action_entry	entries[];
};

struct flow_action_entry {
	enum flow_action_id		id;
	enum flow_action_hw_stats	hw_stats;
	action_destr			destructor;
	void				*destructor_priv;
	union {
		u32			chain_index;	/* FLOW_ACTION_GOTO */
		struct net_device	*dev;		/* FLOW_ACTION_REDIRECT */
		··· ···
	};
	struct flow_action_cookie *cookie; /* user defined action cookie */
};

struct nft_offload_ctx {
	struct {
		enum nft_offload_dep_type	type;
		__be16				l3num;
		u8				protonum;
	} dep;
	unsigned int				num_actions;
	struct net				*net;
	struct nft_offload_reg			regs[NFT_REG32_15 + 1];
};

Стек вызовов:

  • nft_flow_rule_create
    • nft_dup_netdev_offload/nft_fwd_netdev_offload
      • nft_fwd_dup_netdev_offload

Использование netfilter и триггер

Ссылка: https://www.openwall.com/lists/oss-security/2022/02/21/2

В этом письме объясняется, как использовать netfilter с помощью библиотек C libmnl и libnftnl. Ключевой момент для триггера уязвимости — наличие флага NFT_OFFLOAD_F_ACTION у добавляемых правил. Только правила, добавленные через nftnl_expr_alloc("immediate");, имеют этот флаг:

for(int i = 0; i < legit_writes; i++) {// добавление expr не вызовет выход за границы
    exprs[exprid] = nftnl_expr_alloc("immediate");
    nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_IMM_DREG, NFT_REG_1);
    nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_IMM_DATA, 1);
    nftnl_rule_add_expr(rule, exprs[exprid]);
    exprid++;
    exprs[exprid] = nftnl_expr_alloc("dup");
    nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_DUP_SREG_DEV, NFT_REG_1);
    nftnl_rule_add_expr(rule, exprs[exprid]);
    exprid++;
}
// следующее добавление вызовет выход за границы
for (int unaccounted_dup = 0; unaccounted_dup < oob_writes; unaccounted_dup++) {
    exprs[exprid] = nftnl_expr_alloc("dup");
    nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_DUP_SREG_DEV, NFT_REG_1);
    nftnl_rule_add_expr(rule, exprs[exprid]);
    exprid++;
}

Эксплуатация уязвимости

Эксплуатация не очень стабильна, но техника изящна. Уязвимость позволяет записать по фиксированному смещению за границей неконтролируемый указатель. Личный анализ показывает очень высокую сложность эксплуатации. Простой анализ технического приёма. Согласно коду уязвимости, при каждом выходе за границы записывается целое число (id, фиксированно равно 4 или 5) и указатель (*dev), где указатель указывает на структуру struct net_device. Здесь сосредоточимся только на записи указателя dev:

int nft_fwd_dup_netdev_offload(struct nft_offload_ctx *ctx,
			       struct nft_flow_rule *flow,
			       enum flow_action_id id, int oif)
{
	··· ···
	entry = &flow->rule->action.entries[ctx->num_actions++];// выход за границы
	entry->id = id;
	entry->dev = dev; // запись адреса кучи по фиксированному смещению, dev — struct net_device
	··· ···
}

Что касается структуры struct flow_rule, так как она переменной длины, размер выделяемой памяти определяет возможность эксплуатации (успех).

Скачать инструмент