A reliable unprivileged container jail escape proof of concept for CentOs/RHEL

eyberg1 pts0 comments

GitHub - sgkdev/ipv6_frag_escape: Linux LPE - Reliable Jail/Container Escape · GitHub

/" data-turbo-transient="true" />

Skip to content

Search or jump to...

Search code, repositories, users, issues, pull requests...

-->

Search

Clear

Search syntax tips

Provide feedback

--><br>We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Cancel

Submit feedback

Saved searches

Use saved searches to filter your results more quickly

-->

Name

Query

To see all available qualifiers, see our documentation.

Cancel

Create saved search

Sign in

/;ref_cta:Sign up;ref_loc:header logged out"}"<br>Sign up

Appearance settings

Resetting focus

You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

{{ message }}

sgkdev

ipv6_frag_escape

Public

Notifications<br>You must be signed in to change notification settings

Fork

Star<br>11

main

BranchesTags

Go to file

CodeOpen more actions menu

Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit

History<br>1 Commit<br>1 Commit

IPV6_FRAG_ESCAPE.c

IPV6_FRAG_ESCAPE.c

Makefile

Makefile

README.md

README.md

kallsysms.c

kallsysms.c

pagemap.c

pagemap.c

pagemap.h

pagemap.h

View all files

Repository files navigation

IPV6_FRAG_ESCAPE

A reliable unprivileged container / jail escape proof of concept for CentOS / RHEL 10.

It rides a now fixed IPv6 fragmentation bug in __ip6_append_data() (closed upstream by<br>38becddc, no CVE), an in-slab linear overflow into the skb_shared_info at the tail of a<br>packet's own head object. This README documents the exploitation chain only. It does not<br>cover the trigger.

Scope

Target: CentOS / RHEL 10 (kernel 6.12.x, e.g. 6.12.0-242.el10).

Start: an unprivileged process inside a network isolated container, with access to<br>unprivileged user namespaces.

Result: an interactive root shell in the host's initial namespaces and root filesystem.

Notes

This is a proof of concept, deliberately not a turnkey weapon. The reliability scaffolding<br>is intentionally left out: no per-CPU PCP grooming, no cross-cache SLUB armoring, and the<br>skb head is placed in a shared, not so quiet cache. What ships fires often enough to<br>prove the chain, and not much more. It is scoped to CentOS / RHEL 10 only.

Requirements

CONFIG_INIT_ON_ALLOC_DEFAULT_ON off, the RHEL / CentOS default. This PoC plants a stale<br>pointer in uninitialised slab bytes; with init_on_alloc=1 that slot is zeroed and this<br>particular technique only crashes the kernel (a NULL deref). That is a limit of the<br>technique, not of the bug: a full exploit that also covers those kernels, with a<br>different technique, will follow once the fix and CVE are public.

5-level paging (LA57, 57-bit linear addresses). The page table walk is wired for five<br>levels and a startup check refuses to run without it. A 4-level CPU would need the walk<br>refactored.

/sys/kernel/btf/vmlinux present and world readable (stock on RHEL / CentOS).

Tested kernels

Distro<br>Kernel<br>Result

CentOS Stream 10<br>6.12.0-242.el10<br>root, container escape

RHEL 10<br>6.12.0-228.el10<br>httpd_t context escape

Exploitation chain

In-slab overflow to a self-UAF. The bug yields control of the single nr_frags<br>byte in skb_shared_info. The free path (skb_release_data()) walks<br>frags[0 .. nr_frags) and put_page()s each entry, and frags[] is never initialised.<br>We pre-plant a struct page * for a pipe buffer page into that slab slot through<br>controlled cache reuse, then set nr_frags to 1, so the teardown drops a reference on a<br>page we still own. The linear overflow becomes a page use-after-free. The overflow never<br>touches frags[0], so it need not be timed against the spray, which is most of what<br>makes it forgiving.

Page UAF to Dirty-Pagetable. The freed pipe page is reclaimed as a last-level page<br>table by faulting a fresh anonymous mapping. One physical page is now both a live leaf<br>page table and the page the pipe still reads and writes. Writing eight bytes to the pipe<br>installs a forged PTE; reading the pipe reads the table back. This is a finite arbitrary<br>physical read/write, on the order of 460 PTE windows per table.

Defeat KASLR. With the physical read we scan the fixed low-memory SMP trampoline<br>page table, which KASLR never relocates; its kernel half entry points at<br>level4_kernel_pgt, the kernel's physical base. From there init_top_pgt (recognisable<br>by its self-referencing entry 511) is a universal virtual to physical translator,<br>recovering the kernel virtual base and tying our address space to physical memory.

Finite to infinite read/write. We forge one PTE in the leaf table that points at the<br>table's own physical address. The matching virtual window then aliases the page table<br>itself, so PTEs become plain memory: unlimited, random access kernel read/write, with no<br>pipe in the loop. Ring 3...

page table kernel centos rhel physical

Related Articles