Skip to content
KitploitKITPLOIT
FerramentasBlog
Log in
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-2017-5123 — PoC CVE-2017-5123 - LPE - Contornando SMEP/SMAP. Sem KASLR | Kitploit
Ferramentas/GitHubGitHub/c3r34lk1ll3r/cve-2017-5123
Escalada de PrivilégiosExploraçãoAprendizado e EducaçãoExploração de BináriosLabs e Prática
GitHubc3r34lk1ll3r/cve-2017-5123

CVE-2017-5123

PoC CVE-2017-5123 - LPE - Contornando SMEP/SMAP. Sem KASLR

Ver Repositório
33411há 6 anosRevisado pelo Kitploit

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-2017-5123

Prova de Conceito CVE-2017-5123 - EPL - Contornando SMEP/SMAP. Sem KASLR

A implementação waitid em kernels upstream não restringia o destino alvo para copiar informações de resultados. Isso pode permitir que usuários locais escrevam em memória do kernel protegida, levando à escalação de privilégios.

Introdução

Neste pequeno writeup, analisarei uma vulnerabilidade do kernel que nos permite obter privilégio root.

Este arquivo está dividido em quatro partes:

  1. Configuração da VM;
  2. Análise da vulnerabilidade;
  3. Exploração;
  4. PoC.

Quero destacar que existem muitas maneiras melhores de explorar este CVE (de fato, isso é apenas um PoC para aprender o kernel, não pode ser usado in the wild), mas acredito que esta metodologia pode ser útil como uma introdução à exploração do kernel.

Configuração da VM

Compilação do Kernel

Esta vulnerabilidade foi introduzida em 4c48abe91be0, então precisamos compilar essa versão do kernel.

Isso pode ser um pouco complicado porque é uma versão antiga e o código deve ser corrigido. Criei um repositório com um código de kernel já corrigido e um arquivo .config para que você possa clonar e compilar.

git clone https://github.com/c3r34lk1ll3r/kernel_mirror.git
cd kernel_mirror
git checkout origin/modified_v4.14
wget https://gist.githubusercontent.com/c3r34lk1ll3r/c9c34ae86140cc7a24d0d90141686ee8/raw/52431b577a71e3fe8f89d6ce355ce9c1c54c53b6/.config
make -j 8 --output-sync=recurse

Observe que este kernel será compilado com drivers virtio para que você possa usar virtio disk para compartilhar arquivos de/para a VM.

Configuração do Rootfs

Agora, criaremos o rootfs inicial:

qemu-img create -f raw hda.raw 10G
# Formata o disco para ext4
mkfs.ext4 ./hda.raw 
# Cria um ponto de montagem para a imagem
mkdir /tmp/mount1
# Monta o disco
sudo mount -o loop ./hda.raw /tmp/mount1

Em seguida, devemos instalar uma distribuição Linux básica, por exemplo usando pacstrap ou debootstrap.

sudo pacstrap /tmp/mount1 base base-devel vim

Finalmente, podemos modificar o sistema:

# Adiciona um usuário 'test'
echo 'test:x:1000:1000::/home/test:/bin/bash' | sudo tee -a /tmp/mount1/etc/passwd
# Sem senha
echo 'test::14871::::::' | sudo tee -a /tmp/mount1/etc/shadow 
# Podemos montar um disco virtio para compartilhar arquivos entre host e convidado
echo '/transient /home/test/shared 9p trans=virtio,version=9p2000.L,rw,user,exec 0 0' | sudo tee -a /tmp/mount1/etc/fstab
sudo mkdir -p /tmp/mount1/home/test/shared 
# É útil ter permissão sudo
echo '%wheel ALL=(ALL) NOPASSWD: ALL' | sudo tee -a /tmp/mount1/etc/sudoers
echo 'wheel:x:998:test' | sudo tee -a /tmp/mount1/etc/group

sudo chown -R 1000:1000 /tmp/mount1/home/test
sudo umount /tmp/mount1

Se tudo estiver em ordem, podemos testar nosso sistema com qemu:

qemu-system-x86_64 \
    -kernel ./kernel_mirror/arch/x86_64/boot/bzImage \
    -hda ./hda.raw \
    -m 4G \
    -cpu "Skylake-Client-IBRS,ss=on,vmx=on,hypervisor=on,tsc-adjust=on,clflushopt=on,umip=on,md-clear=on,stibp=on,arch-capabilities=on,ssbd=on,xsaves=on,pdpe1gb=on,ibpb=on,amd-ssbd=on,skip-l1dfl-vmentry=on,hle=off,rtm=off" \
    -smp 4 \
    -vga virtio \
    -enable-kvm \
    -nographic \
    -machine type=q35,accel=kvm \
    -virtfs "fsdriver=local,id=fs.1,path=./trans_fs,security_model=mapped,writeout=immediate,mount_tag=/transient" \
    -append "root=/dev/sda rw noquiet nokaslr console=ttyS0 loglevel=5" \
    -chardev "vc,id=vc.0,cols=1920,rows=1080" \
    -net "user,hostfwd=tcp::10022-:22" \
    -net "nic" \
    -s

Vulnerabilidade

A descrição do CVE diz que há uma operação de escrita não restrita durante a chamada de sistema waitid.

Vamos abrir kernel/exit.c e olhar o código:

SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
		infop, int, options, struct rusage __user *, ru)
{
    struct rusage r;
    struct waitid_info info = {.status = 0};
    long err = kernel_waitid(which, upid, &info, options, ru ? &r : NULL);
    int signo = 0;

    if (err > 0) {
        signo = SIGCHLD;
        err = 0;
        if (ru && copy_to_user(ru, &r, sizeof(struct rusage)))
            return -EFAULT;
    }
    if (!infop)
        return err;
    user_access_begin();
    unsafe_put_user(signo, &infop->si_signo, Efault);
    unsafe_put_user(0, &infop->si_errno, Efault);
    unsafe_put_user(info.cause, &infop->si_code, Efault);
    unsafe_put_user(info.pid, &infop->si_pid, Efault);
    unsafe_put_user(info.uid, &infop->si_uid, Efault);
    unsafe_put_user(info.status, &infop->si_status, Efault);
    user_access_end();
    return err;
Efault:
    user_access_end();
    return -EFAULT;
}

Esta função é bastante direta: após algumas verificações, há várias chamadas para unsafe_put_user(...) e a função retorna.

A parte principal desta função é composta pela função unsafe_put_user(...), então vamos para lá (arch/x86/include/asm/uaccess.h):

/*
 * The "unsafe" user accesses aren't really "unsafe", but the naming
 * is a big fat warning: you have to not only do the access_ok()
 * checking before using them, but you have to surround them with the
 * user_access_begin/end() pair.
 */
#define user_access_begin()	__uaccess_begin()
#define user_access_end()	__uaccess_end()

#define unsafe_put_user(x, ptr, err_label)					\
do {										\
    int __pu_err;								\
    __typeof__(*(ptr)) __pu_val = (x);					\
    __put_user_size(__pu_val, (ptr), sizeof(*(ptr)), __pu_err, -EFAULT);	\
    if (unlikely(__pu_err)) goto err_label;					\
} while (0)

#define unsafe_get_user(x, ptr, err_label)					\
do {										\
    int __gu_err;								\  
    __inttype(*(ptr)) __gu_val;						\
    __get_user_size(__gu_val, (ptr), sizeof(*(ptr)), __gu_err, -EFAULT);	\
    (x) = (__force __typeof__(*(ptr)))__gu_val;				\
    if (unlikely(__gu_err)) goto err_label;					\
} while (0)

Há um grande aviso no comentário: se você quiser usar unsafe_put/get_user, deve primeiro chamar access_ok() e envolvê-los com user_access_begin/end().

Se observarmos o código anterior (waitid), podemos ver que access_ok() nunca é chamado, então a chamada de sistema viola este aviso.

Mas o que são essas macros?

SMAP/SMEP

SMAP e SMEP são dois recursos de segurança introduzidos no kernel para dificultar a escrita de exploits. Vale notar que esses recursos são aplicados pela CPU.

SMEP impede a execução de código do espaço do usuário enquanto a CPU está em modo supervisor; SMAP, por outro lado, bloqueia o acesso de leitura/escrita à memória do usuário.

O kernel precisa escrever/ler dados de/para a memória do usuário e isso pode ser feito de duas maneiras:

  1. existem funções (ex.: copy_from_user) que permitem copiar a memória no espaço do kernel;
  2. desabilitar temporariamente o SMAP

Como podemos ver na definição de unsafe_put_user, esta função irá apenas copiar o valor de x para a memória apontada por ptr (e pular para err_label se houver erro). Acabamos de dizer que o kernel não pode acessar o espaço do usuário por causa do SMAP, e é por isso que essas funções devem ser envolvidas por user_access_begin/end().

#define __uaccess_begin() stac()
#define __uaccess_end()   clac()

Como podemos ver, user_access_begin/end são simplesmente as instruções ASM stac e clac.

Baixar ferramenta