Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2022-2590-analysis — Análise aprofundada do CVE-2022-2590, uma variante do Dirty COW no shmem do kernel Linux, incluindo causa raiz, condição de corrida e exploit de prova de conceito. | Kitploit
Ferramentas/GitHubGitHub/moonnull/cve-2022-2590-analysis
Análise de VulnerabilidadesExploraçãoExploração de Binários
GitHubmoonnull/cve-2022-2590-analysis

CVE-2022-2590-analysis

Análise aprofundada do CVE-2022-2590, uma variante do Dirty COW no shmem do kernel Linux, incluindo causa raiz, condição de corrida e exploit de prova de conceito.

Ver Repositório
há 22h 56mAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2022-2590, Dirty COW restrito a shmem

versão do kernel Linux: Linux/x86 6.0.0-rc1 (commit 37887783b3fef877bf34b8992c9199864da4afcb)

Introdução:

esta vulnerabilidade permite que o atacante escreva conteúdo arbitrário em uma página de memória compartilhada somente leitura, satisfazendo a função can_follow_write_pte, que verifica FOLL_FORCE, FOLL_COW e pte_dirty, usando UFFDIO_CONTINUE.

Análise:

root@kitploit:~
/*
 * FOLL_FORCE can write to even unwritable pte's, but only
 * after we've gone through a COW cycle and they are dirty.
 */
static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
{
	return pte_write(pte) ||
		((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte));
}

A função acima determina se uma pte é gravável.

Uma pte é considerada gravável se atender a uma das seguintes condições:

  1. Os flags da pte incluem o flag de escrita.
  2. A variável de flags contém os flags FOLL_FORCE e FOLL_COW, e os flags da pte incluem o flag dirty.

Para satisfazer a condição 2, os seguintes três flags precisam ser definidos:

  1. FOLL_FORCE

    root@kitploit:~
static ssize_t mem_rw(struct file *file, char __user *buf, size_t count, loff_t *ppos, int write) { ... flags = FOLL_FORCE | (write ? FOLL_WRITE : 0); while (count > 0) { size_t this_len = min_t(size_t, count, PAGE_SIZE); if (write && copy_from_user(page, buf, this_len)) { copied = -EFAULT; break; } this_len = access_remote_vm(mm, addr, page, this_len, flags); // __get_user_pages with FOLL_FORCE on if (!this_len) { if (!copied) copied = -EIO; break; } ... }

A função acima realiza operações de leitura/escrita em /proc/<pid>/mem.

Usando essa função, é possível alcançar a função __get_user_pages com o flag FOLL_FORCE ativado.

Embora o FOLL_FORCE seja destinado ao uso em ptrace, sua necessidade foi comprovada no seguinte commit: https://github.com/torvalds/linux/commit/f511c0b17b081562dca8ac5061dfa86db4c66cc2

  • FOLL_COW

    root@kitploit:~
    /*
    * mmap_lock must be held on entry.  If @locked != NULL and *@flags
    * does not include FOLL_NOWAIT, the mmap_lock may be released.  If it
    * is, *@locked will be set to 0 and -EBUSY returned.
    */
    static int faultin_page(struct vm_area_struct *vma,
    	unsigned long address, unsigned int *flags, bool unshare,
    	int *locked)
    {
      ...
    
      /*
      * The VM_FAULT_WRITE bit tells us that do_wp_page has broken COW when
      * necessary, even if maybe_mkwrite decided not to set pte_write. We
      * can thus safely do subsequent page lookups as if they were reads.
      * But only do so when looping for pte_write is futile: in some cases
      * userspace may also be wanting to write to the gotten user page,
      * which a read fault here might prevent (a readonly page might get
      * reCOWed by userspace write).
      */
      if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE))
        *flags |= FOLL_COW;
      return 0;
    }
    

    A operação OR com FOLL_COW na função faultin_page pode ser usada; ela faz parte do patch para o Dirty COW.

    root@kitploit:~
    static long __get_user_pages(struct mm_struct *mm,
     		unsigned long start, unsigned long nr_pages,
     		unsigned int gup_flags, struct page **pages,
     		struct vm_area_struct **vmas, int *locked)
     {
     	...
     retry:
     		/*
     		 * If we have a pending SIGKILL, don't keep faulting pages and
     		 * potentially allocating memory.
     		 */
     		if (fatal_signal_pending(current)) {
     			ret = -EINTR;
     			goto out;
     		}
     		cond_resched();
    
     		page = follow_page_mask(vma, start, foll_flags, &ctx); // can_follow_write_pte
     		if (!page || PTR_ERR(page) == -EMLINK) {
     			ret = faultin_page(vma, start, &foll_flags,
     					   PTR_ERR(page) == -EMLINK, locked); // flags |= FOLL_COW
     			switch (ret) {
     			case 0:
     				goto retry; // try follow page again
     			case -EBUSY:
     			case -EAGAIN:
     				ret = 0;
     				fallthrough;
     			case -EFAULT:
     			case -ENOMEM:
     			case -EHWPOISON:
     				goto out;
     			}
     			BUG();
     		} else if (PTR_ERR(page) == -EEXIST) {
        ...
     }
    

    Para alcançar a função can_follow_write_pte com o flag FOLL_COW ativado, é necessário chamar a função faultin_page dentro da função __get_user_pages, redirecionar para o rótulo retry e chamar a função faultin_page novamente.

  • pte_dirty

    Essa condição pode ser satisfeita devido ao seguinte commit: https://github.com/torvalds/linux/commit/9ae0f87d009ca6c4aab2882641ddfc319727e3db

    root@kitploit:~
    /*
    * Install PTEs, to map dst_addr (within dst_vma) to page.
    *
    * This function handles both MCOPY_ATOMIC_NORMAL and _CONTINUE for both shmem
    * and anon, and for both shared and private VMAs.
    */
    int mfill_atomic_install_pte(struct mm_struct *dst_mm, pmd_t *dst_pmd,
    		     struct vm_area_struct *dst_vma,
    		     unsigned long dst_addr, struct page *page,
    		     bool newly_allocated, bool wp_copy)
    {
     	...
    
     	_dst_pte = mk_pte(page, dst_vma->vm_page_prot);
     	_dst_pte = pte_mkdirty(_dst_pte); // set pte dirty unconditionally
     	if (page_in_cache && !vm_shared)
     		writable = false;
    
     	...
    }
    

    Devido ao patch acima, é possível instalar uma pte para a página de memória compartilhada somente leitura em estado sujo (dirty) incondicionalmente.

  •  

    Se esses três flags forem satisfeitos, a função can_follow_write_pte retornará true.

    root@kitploit:~
    static struct page *follow_page_pte(struct vm_area_struct *vma,
    		unsigned long address, pmd_t *pmd, unsigned int flags,
    		struct dev_pagemap **pgmap)
    {
    	...
        
    	// true && !true == false
    	if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) {
    		pte_unmap_unlock(ptep, ptl);
    		return NULL;
    	}
    
    	page = vm_normal_page(vma, address, pte); // get read-only shared memory page
    
    	...
    
    out:
    	pte_unmap_unlock(ptep, ptl);
    	return page;
    no_page:
    	pte_unmap_unlock(ptep, ptl);
    	if (!pte_none(pte))
    		return NULL;
    	return no_page_table(vma, flags);
    }
    

    A função follow_page_pte retorna a página de memória compartilhada somente leitura.

    Cenário de Corrida:

    A seguir está o cenário de corrida comprovado pelo PoC, que será apresentado mais adiante.

    madvise e leituraUFFDIO_CONTINUE ioctlpwrite
    madvise // invalida a página
    shmem_fault // falha de leitura
    handle_userfault
    userfaultfd_continue
    mcontinue_atomic_pte
    ret = shmem_getpage(inode, pgoff, &page, SGP_NOALLOC); // obtém a página
    mfill_atomic_install_pte
    _dst_pte = pte_mkdirty(_dst_pte); // torna a pte suja
    set_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte); // instala a ptemem_rw
    access_remote_vm // com FOLL_FORCE
    __get_user_pages
    can_follow_write_pte // sem FOLL_COW, retorna 0
    faultin_page
    flags
    retry:
    follow_page_pte
    madvise // invalida a página
    shmem_fault // falha de leitura
    handle_userfault
    userfaultfd_continue
    mcontinue_atomic_pte
    ret = shmem_getpage(inode, pgoff, &page, SGP_NOALLOC); // obtém a página
    mfill_atomic_install_pte
    _dst_pte = pte_mkdirty(_dst_pte); // torna a pte suja
    set_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte); // instala a pte
    can_follow_write_pte // retorna 1
    copy_to_user(buf, page, this_len) // escreve conteúdo na página somente leitura

    As rotinas madvise e leitura são executadas duas vezes; a primeira execução induz um retry de __get_user_pages, e a segunda execução faz com que follow_page_pte retorne a página apontada pela pte que foi tornada suja por mfill_atomic_install_pte.

    PoC e Patch:

    https://www.openwall.com/lists/oss-security/2022/08/15/1

    Você pode verificar o reprodutor de David Hildenbrand no link acima.

    No entanto, como o reprodutor dificulta o reconhecimento do cenário de corrida exato, modifiquei o reprodutor para favorecer uma execução mais linear e, consequentemente, também modifiquei o código-fonte do kernel Linux.

    .config:

    root@kitploit:~
    ...
    CONFIG_USERFAULTFD=y
    CONFIG_HAVE_ARCH_USERFAULTFD_WP=y
    CONFIG_HAVE_ARCH_USERFAULTFD_MINOR=y
    ...
    

    PoC: (poc.c)

    Patch: (poc_deayzl.patch)

    Para testar, as seguintes etapas preliminares devem ser realizadas. (As instruções no reprodutor do david dizem que o caminho do arquivo é /tmp/foo. Mas tmpfs não é memória compartilhada na versão atual, então o registro do userfaultfd falha)

    root@kitploit:~
    sudo -s
    echo "asdf" > /dev/shm/foo
    chmod 0404 /dev/shm/foo
    exit
    

    Após executar o PoC, você verá a seguinte tela.

    PoC-result

    Referências:

    commit: https://github.com/torvalds/linux/commit/5535be3099717646781ce1540cf725965d680e7b

    lore.kernel patch v1: https://lore.kernel.org/linux-mm/[email protected]/#r

    lore.kernel patch v2: https://lore.kernel.org/all/[email protected]/T/#u

    openwall: https://www.openwall.com/lists/oss-security/2022/08/08/1

    openwall2: https://lists.openwall.net/linux-kernel/2022/08/08/418

    Baixar ferramenta