Skip to content
KitploitKITPLOIT
StrumentiExploitsBlog
Log in
Invia
StrumentiExploitsBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2012-0056 — elevazione dei privilegi linux | Kitploit
Strumenti/GitHubGitHub/pythonone/cve-2012-0056
Escalation di PrivilegiAnalisi delle VulnerabilitàExploitShellcodeApprendimento e FormazioneBinary Exploitation
GitHubpythonone/cve-2012-0056

CVE-2012-0056

elevazione dei privilegi linux

Vedi Repository
161310 anni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

Escalation locale dei privilegi in Linux tramite scrittura su SUID /proc/pid/mem

Mempodipper

Presentazione di Mempodipper, un exploit per CVE-2012-0056. /proc/pid/mem è un'interfaccia per leggere e scrivere direttamente la memoria di un processo, spostandosi con gli stessi indirizzi dello spazio di memoria virtuale del processo. Nella versione 2.6.39, le protezioni contro l'accesso non autorizzato a /proc/pid/mem sono state ritenute sufficienti, e quindi il precedente #ifdef che impediva il supporto alla scrittura su memoria arbitraria di un processo è stato rimosso. Chiunque avesse i permessi corretti poteva scrivere nella memoria di un processo. Ovviamente, si è scoperto che il controllo dei permessi era implementato male. Ciò significa che tutti i kernel Linux >=2.6.39 sono vulnerabili, fino al commit di correzione di un paio di giorni fa. Esaminiamo passo dopo passo il vecchio codice del kernel e scopriamo qual è il problema.

Quando /proc/pid/mem viene aperto, viene chiamato questo codice del kernel:

static int mem_open(struct inode* inode, struct file* file)
{
	file->private_data = (void*)((long)current->self_exec_id);
	/* OK to pass negative loff_t, we can catch out-of-range */
	file->f_mode |= FMODE_UNSIGNED_OFFSET;
	return 0;
}

Non ci sono restrizioni all'apertura; chiunque può aprire il /proc/pid/mem fd per qualsiasi processo (soggetto alle normali restrizioni VFS). Semplicemente prende nota del self_exec_id del processo originale con cui è stato aperto e lo memorizza per controlli successivi durante letture e scritture.

Le scritture (e le letture), tuttavia, hanno restrizioni di controllo dei permessi. Diamo un'occhiata alla funzione di scrittura:

static ssize_t mem_write(struct file * file, const char __user *buf,
			 size_t count, loff_t *ppos)
{

/* unimportant code removed for blog post */	

	struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
	
/* unimportant code removed for blog post */

	mm = check_mem_permission(task);
	copied = PTR_ERR(mm);
	if (IS_ERR(mm))
		goto out_free;

/* unimportant code removed for blog post */	

	if (file->private_data != (void *)((long)current->self_exec_id))
		goto out_mm;

/* unimportant code removed for blog post
 * (the function here goes onto write the buffer into the memory)
 */	

Quindi ci sono due controlli rilevanti in atto per prevenire scritture non autorizzate: check_mem_permission e self_exec_id. Facciamo prima il primo e poi il secondo.

Il codice di check_mem_permission chiama semplicemente __check_mem_permission, quindi ecco il codice di quest'ultimo:

static struct mm_struct *__check_mem_permission(struct task_struct *task)
{
	struct mm_struct *mm;

	mm = get_task_mm(task);
	if (!mm)
		return ERR_PTR(-EINVAL);

	/*
	 * A task can always look at itself, in case it chooses
	 * to use system calls instead of load instructions.
	 */
	if (task == current)
		return mm;

	/*
	 * If current is actively ptrace'ing, and would also be
	 * permitted to freshly attach with ptrace now, permit it.
	 */
	if (task_is_stopped_or_traced(task)) {
		int match;
		rcu_read_lock();
		match = (ptrace_parent(task) == current);
		rcu_read_unlock();
		if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH))
			return mm;
	}

	/*
	 * No one else is allowed.
	 */
	mmput(mm);
	return ERR_PTR(-EPERM);
}

Ci sono due modi in cui la scrittura in memoria è autorizzata. O task == current, cioè il processo a cui si scrive è lo stesso che scrive, oppure current (il processo che scrive) ha permessi esoterici a livello ptrace per giocare con task (il processo a cui si scrive). Forse pensi di poter ingannare il codice ptrace? È tentante. Ma non lo so. Cerchiamo invece di capire come possiamo far sì che un processo scriva memoria arbitraria su se stesso, così che task == current.

Ora, naturalmente, vogliamo scrivere nella memoria dei processi suid, perché così possiamo ottenere root. Dai un'occhiata a questo:

$ su "yeeeee haw I am a cowboy"
Unknown id: yeeeee haw I am a cowboy

su sputerà su stderr qualsiasi testo tu voglia, preceduto da "Unknown id:". Quindi, possiamo aprire un fd verso /proc/self/mem, fare lseek alla posizione giusta in memoria per la scrittura (ne parleremo più avanti), usare dup2 per accoppiare stderr e il fd di mem, e poi exec verso su $shellcode per scrivere uno spawner di shell nella memoria del processo, e poi abbiamo root. Davvero? Non così facile.

Qui entra in gioco l'altra restrizione. Dopo aver superato il test task == current, controlla se il self_exec_id corrente corrisponde al self_exec_id con cui è stato aperto il fd. Che diavolo è self_exec_id? È referenziato solo in pochi punti del kernel. Il più importante si trova all'interno di exec:

void setup_new_exec(struct linux_binprm * bprm)
{
/* massive amounts of code trimmed for the purpose of this blog post */

	/* An exec changes our domain. We are no longer part of the thread
	   group */

	current->self_exec_id++;
			
	flush_signal_handlers(current, 0);
	flush_old_files(current->files);
}
EXPORT_SYMBOL(setup_new_exec);

self_exec_id viene incrementato ogni volta che un processo fa exec. Quindi in questo caso funziona in modo che tu non possa aprire il fd in un processo non-suid, fare dup2, e poi exec verso un processo suid... che è esattamente ciò che stavamo cercando di fare sopra. Un modo piuttosto intelligente di scoraggiare il nostro attacco, eh?

Scarica lo strumento