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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
n_gsm_exploit — استغلال use-after-free في ioctl الخاص بـ n_gsm TTY في نواة Linux (PoC): تحليل حالة التسابق، وتسريب عنوان قاعدة النواة، ورشّ الكومة (heap spray)، واختطاف مؤشر التعليمات (RIP)، والكتابة العشوائية، وتصعيد الامتيازات عبر modprobe_path. | Kitploit
أدوات/GitHubGitHub/gmh5225/n_gsm_exploit
تصعيد الامتيازاتتحليل الذاكرة الجنائيتحليل الثغرات الأمنيةالاستغلالاستغلال الملفات الثنائية
GitHubgmh5225/n_gsm_exploit

n_gsm_exploit

استغلال use-after-free في ioctl الخاص بـ n_gsm TTY في نواة Linux (PoC): تحليل حالة التسابق، وتسريب عنوان قاعدة النواة، ورشّ الكومة (heap spray)، واختطاف مؤشر التعليمات (RIP)، والكتابة العشوائية، وتصعيد الامتيازات عبر modprobe_path.

عرض المستودع
1منذ 2 سنواتلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

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

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

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

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

يبدو أن هذه لا تزال ثغرة يوم-صفر. لم تكن لديّ أي نية لنشر هذا الاستغلال قبل ترقيع الثغرة، لكن باحثًا آخر اكتشف الثغرة نفسها ونشر استغلالًا لها، لذا نشرت شفرتي أيضًا. يُرجى استخدام هذا لأغراض البحث فقط.

RCA

  • يدعم TTY في نواة Linux بروتوكول التعددية GSM 07.10.
    • https://docs.kernel.org/driver-api/tty/n_gsm.html
    • https://github.com/torvalds/linux/blob/master/drivers/tty/n_gsm.c
  • عند طلب ioctl لـ GSM، تُنفَّذ الدوال التالية في النواة:

[1] GSMIOC_SETCONF: يعيد ضبط إعدادات GSM.

[2] GSMIOC_GETCONF_DLCI: يسترجع إعدادات DLCI المرتبطة بـ GSM.

[3] GSMIOC_SETCONF_DLCI: يغيّر إعدادات DLCI المرتبطة بـ GSM.

static int gsmld_ioctl(struct tty_struct *tty, unsigned int cmd,
		       unsigned long arg)
{
...
	case GSMIOC_SETCONF:
		if (copy_from_user(&c, (void __user *)arg, sizeof(c)))
			return -EFAULT;
		return gsm_config(gsm, &c);//[1]
....
	case GSMIOC_GETCONF_DLCI:
		if (copy_from_user(&dc, (void __user *)arg, sizeof(dc)))
			return -EFAULT;
		if (dc.channel == 0 || dc.channel >= NUM_DLCI)
			return -EINVAL;
		addr = array_index_nospec(dc.channel, NUM_DLCI);
		dlci = gsm->dlci[addr];
		if (!dlci) {
			dlci = gsm_dlci_alloc(gsm, addr);
			if (!dlci)
				return -ENOMEM;
		}
		gsm_dlci_copy_config_values(dlci, &dc);//[2]
		if (copy_to_user((void __user *)arg, &dc, sizeof(dc)))
			return -EFAULT;
		return 0;
	case GSMIOC_SETCONF_DLCI:
		if (copy_from_user(&dc, (void __user *)arg, sizeof(dc)))
			return -EFAULT;
		if (dc.channel == 0 || dc.channel >= NUM_DLCI)
			return -EINVAL;
		addr = array_index_nospec(dc.channel, NUM_DLCI);
		dlci = gsm->dlci[addr];
		if (!dlci) {
			dlci = gsm_dlci_alloc(gsm, addr);
			if (!dlci)
				return -ENOMEM;
		}
		return gsm_dlci_config(dlci, &dc, 0);//[3]
	default:
		return n_tty_ioctl_helper(tty, cmd, arg);
	}
}
  • لنبدأ أولاً بفحص GSMIOC_SETCONF، الذي يغيّر إعدادات GSM.

  • [1] إذا اختلف الإعداد الحالي لـ GSM عن الإعداد الجديد، فسيتم تعليم need_restart على أنه true.

    [2] إذا كانت need_restart تساوي true، فسيتم إنهاء GSM الحالي عبر gsm_cleanup_mux.

static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
{
	int need_close = 0;
	int need_restart = 0;

...
	if (c->mtu != gsm->mtu)//[1]
		need_restart = 1;

	/*
	 * Close down what is needed, restart and initiate the new
	 * configuration. On the first time there is no DLCI[0]
	 * and closing or cleaning up is not necessary.
	 */
	if (need_close || need_restart)
		gsm_cleanup_mux(gsm, true);//[2]

...
	return 0;
}

[1] يتم تحرير جميع DLCIs المملوكة لـ GSM عبر gsm_dlci_release.

static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
{
	int i;
	struct gsm_dlci *dlci;
	struct gsm_msg *txq, *ntxq;

	gsm->dead = true;
	mutex_lock(&gsm->mutex);

...
	for (i = NUM_DLCI - 1; i >= 0; i--)
		if (gsm->dlci[i]){
			gsm_dlci_release(gsm->dlci[i]);//[1]
		}

...
}
  • بعد ذلك، تُستدعى الدوال بالترتيب التالي:

    • gsm_dlci_release → dlci_put → gsm_dlci_free

    [1] يتم إسناد NULL إلى gsm->dlci[addr] لمنع الاستخدام بعد التحرير (UAF).

    [2] بعد ذلك، يتم تحرير gsm->dlci[addr] باستخدام kfree.

static void gsm_dlci_free(struct tty_port *port)
{
	struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);

	timer_shutdown_sync(&dlci->t1);
	dlci->gsm->dlci[dlci->addr] = NULL;//[1]
	kfifo_free(&dlci->fifo);
	while ((dlci->skb = skb_dequeue(&dlci->skb_list)))
		dev_kfree_skb(dlci->skb);
	kfree(dlci);//[2]

}

GSMIOC_SETCONF_DLCI

  • لنفحص GSMIOC_SETCONF_DLCI، الذي يغيّر قيم تهيئة DLCI مملوك لـ GSM.

  • [1] يقرأ تهيئة DLCI، بما في ذلك العنوان (addr)، من المستخدم.

    [2] يشير إلى gsm->dlci[addr].

    [3] يستدعي gsm_dlci_config لتغيير تهيئة DLCI.

static int gsmld_ioctl(struct tty_struct *tty, unsigned int cmd,
		       unsigned long arg)
{
...
	case GSMIOC_SETCONF_DLCI:
		if (copy_from_user(&dc, (void __user *)arg, sizeof(dc)))//[1]
			return -EFAULT;
		if (dc.channel == 0 || dc.channel >= NUM_DLCI)
			return -EINVAL;
		addr = array_index_nospec(dc.channel, NUM_DLCI);
		dlci = gsm->dlci[addr];//[2]
		if (!dlci) {
			dlci = gsm_dlci_alloc(gsm, addr);
			if (!dlci)
				return -ENOMEM;
		}
		return gsm_dlci_config(dlci, &dc, 0);//[3]
...
}

[1] يضبط need_open على true بناءً على الخيارات التي يمررها المستخدم.

[2] ينتظر حتى تصبح dlci->state مساوية لـ DLCI_CLOSED.

[3] إذا كانت gsm->initiator فقط صحيحة، يتم استدعاء الدالة gsm_dlci_begin_open لإعادة تشغيل DLCI.

static int gsm_dlci_config(struct gsm_dlci *dlci, struct gsm_dlci_config *dc, int open)
{
	struct gsm_mux *gsm;
	bool need_restart = false;
	bool need_open = false;
	unsigned int i;

...
	if (dc->flags & GSM_FL_RESTART)
		need_restart = true;

	if ((open && gsm->wait_config) || need_restart)//[1]
		need_open = true;
	if (dlci->state == DLCI_WAITING_CONFIG) {
		need_restart = false;
		need_open = true;
	}

	/*
	 * Close down what is needed, restart and initiate the new
	 * configuration.
	 */
	if (need_restart) {
		gsm_dlci_begin_close(dlci);
		wait_event_interruptible(gsm->event, dlci->state == DLCI_CLOSED);//[2]
		if (signal_pending(current))
			return -EINTR;
	}
...
	if (need_open) {
		if (gsm->initiator)
			gsm_dlci_begin_open(dlci);//[3]
		else
			gsm_dlci_set_opening(dlci);
	}

	return 0;
}

الثغرة الأمنية

[1] يصل إلى gsm->dlci دون قفل.

[1] يصل gsm_dlci_config إلى dlci. إذا تم استدعاء gsm_cleanup_mux بسبب GSMIOC_SETCONF، فقد يؤدي وجود حالة تسابق (race condition) إلى الاستخدام بعد التحرير (Use-After-Free أو UAF).

  • في الظروف الطبيعية، يتحقق الشرط خلال فترة زمنية قصيرة جدًا، ويتم استدعاء wakeup.
  • إذا حدث UAF، فما لم يُطلب IOCTL مختلف من مستوى المستخدم لاستدعاء روتين wakeup، فإنه يدخل في انتظار لا نهائي.
  • لذلك، يمكن للمهاجم تحديد ما إذا كان قد تم إطلاق UAF من خلال قياس المدة حتى يكتمل IOCTL.
static int gsm_dlci_config(struct gsm_dlci *dlci, struct gsm_dlci_config *dc, int open)
{
...
	/*
	 * Close down what is needed, restart and initiate the new
	 * configuration.
	 */
	if (need_restart) {
		gsm_dlci_begin_close(dlci);
		wait_event_interruptible(gsm->event, dlci->state == DLCI_CLOSED);//[1]
		if (signal_pending(current))
			return -EINTR;
		}
	...
  • أثناء الانتظار في wait_event_interruptible، تتم إعادة تشغيل GSM بواسطة threadFunction2.
    • يتم تحرير DLCI المشار إليه بواسطة GSM باستخدام kfree، ويتم أيضًا تحرير DLCI المشار إليه بواسطة wait_event_interruptible باستخدام kfree.
    • في مثل هذا السيناريو، نظرًا لأن IOCTL يستغرق وقتًا طويلاً لإكماله، فمن السهل اكتشاف من مساحة المستخدم حدوث Use-After-Free (UAF).

تسريب قاعدة النواة

  • يُكتب عنوان hypercall_page الخاص بالنواة في /sys/kernel/notes، وهو قابل للقراءة من قبل المستخدمين العاديين. لذلك، يمكن للمهاجم قراءة هذا الملف لتسريب قاعدة النواة.
unsigned long get_kernel_base(){
    const char *filePath = "/sys/kernel/notes";
    const char pattern[] = "Xen\\x00";
    FILE *file;
    uint8_t buffer[1024];
    size_t bytesRead;
    int found = 0;
تنزيل الأداة