AF_UNIX MSG_OOB UAF & SKB-based primitives za kernel

Tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Jifunze na fanya mazoezi ya Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

Muhtasari

  • Linux >=6.9 ilileta refactor yenye kasoro ya manage_oob() (5aa57d9f2d53) kwa usimamizi wa AF_UNIX MSG_OOB. Stacked zero-length SKBs ziliepuka mantiki inayofuta u->oob_skb, hivyo recv() ya kawaida inaweza kuachilia SKB ya out-of-band wakati pointer ilibaki hai, ikasababisha CVE-2025-38236.
  • Kuanzisha tena recv(..., MSG_OOB) kunafanya dereference ya struct sk_buff iliyotelekezwa. Kwa MSG_PEEK, njia unix_stream_recv_urg() -> __skb_datagram_iter() -> copy_to_user() inakuwa stable 1-byte arbitrary kernel read; bila MSG_PEEK primtive huongeza UNIXCB(oob_skb).consumed kwa offset 0x44, yaani inaongeza +4 GiB kwenye dword ya juu ya thamani yoyote ya 64-bit iliyowekwa kwenye offset 0x40 ndani ya object iliyorekebishwa tena.
  • Kwa kuisafisha order-0/1 unmovable pages (page-table spray), kulazimisha kuifree tena SKB slab page ndani ya buddy allocator, na kisha kutumia physical page hiyo kama pipe buffer, exploit inaunda metadata za SKB katika memory inayodhibitiwa ili kutambua ukurasa uliotelekezwa na kubadili read primitive kuwa kwenye .data, vmemmap, per-CPU, na maeneo ya page-table licha ya usercopy hardening.
  • Ukurasa uleule unaweza kutumika tena baadaye kama ukurasa wa juu wa kernel-stack wa thread mpya iliyochonwa. CONFIG_RANDOMIZE_KSTACK_OFFSET inakuwa oracle: kwa kuchunguza muundo wa stack wakati pipe_write() inashikilia, mshambulizi anasubiri mpaka urefu uliotelekezwa wa copy_page_from_iter() (R14) uje kwenye offset 0x40, kisha anafyatua kuongeza +4 GiB ili kuharibu thamani ya stack.
  • skb_shinfo()->frag_list inayojizungusha yenyewe huweka UAF syscall ikizunguka ndani ya kernel hadi thread inayoishirikiana ikasimamisha copy_from_iter() (kwa mprotect() juu ya VMA yenye tundu moja la MADV_DONTNEED). Kuvunja loop hutoa increment wakati huo husahihi wakati target ya stack iko hai, ikiongeza bytes argument ili copy_page_from_iter() iandike zaidi ya pipe buffer page mpaka kwenye physical page inayofuata.
  • Kwa kufuatilia pipe-buffer PFNs na page tables kwa kutumia read primitive, mshambulizi anahakikisha kuwa ukurasa unaofuata ni PTE page, anakamilisha OOB copy kuwa arbitrary PTE writes, na kupata kernel read/write/execute bila vikwazo. Chrome ilipunguza ufikiaji kwa kuzuia MSG_OOB kutoka kwa renderers (6711812), na Linux ilirekebisha kasoro ya mantiki katika 32ca245464e1 pamoja na kuanzisha CONFIG_AF_UNIX_OOB kufanya kipengele kuwa hiari.

Chanzo cha mzizi: manage_oob() inadhania SKB moja tu ya urefu sifuri

unix_stream_read_generic() inatarajia kila SKB iliyorejeshwa na manage_oob() kuwa na unix_skb_len() > 0. Baada ya 93c99f21db36, manage_oob() iliruka njia ya usafishaji skb == u->oob_skb kila ilipoiondoa kwanza SKB ya urefu sifuri iliyosalia baada ya recv(MSG_OOB). Rekebisho lililofuata (5aa57d9f2d53) bado liliendelea kutoka SKB ya kwanza ya urefu sifuri hadi skb_peek_next() bila kukagua tena urefu. Kwa SKB mbili mfululizo zenye urefu sifuri, kazi ilirudisha SKB ya pili tupu; unix_stream_read_generic() kisha iliruka bila kuita tena manage_oob(), hivyo SKB halisi ya OOB ilitolewa kwenye queue na kuachiliwa wakati u->oob_skb bado ilielekeza kwake.

Mfuatano mdogo wa kusababisha

char byte;
int socks[2];
socketpair(AF_UNIX, SOCK_STREAM, 0, socks);
for (int i = 0; i < 2; ++i) {
send(socks[1], "A", 1, MSG_OOB);
recv(socks[0], &byte, 1, MSG_OOB);
}
send(socks[1], "A", 1, MSG_OOB);   // SKB3, u->oob_skb = SKB3
recv(socks[0], &byte, 1, 0);         // normal recv frees SKB3
recv(socks[0], &byte, 1, MSG_OOB);   // dangling u->oob_skb

Primitives exposed by unix_stream_recv_urg()

  1. 1-byte arbitrary read (repeatable): state->recv_actor() mwisho wake hufanya copy_to_user(user, skb_sourced_addr, 1). Ikiwa SKB iliyobaki (dangling SKB) itareallocated ndani ya kumbukumbu inayodhibitiwa na mshambulizi (au kwa alias iliyodhibitiwa kama pipe page), kila recv(MSG_OOB | MSG_PEEK) inakopa baiti kutoka anwani yoyote ya kernel inayoruhusiwa na __check_object_size() hadi user space bila kusababisha crash. Kuacha MSG_PEEK kuwekwa kunahifadhi pointer iliyobaki kwa usomaji usio na kikomo.
  2. Constrained write: Wakati MSG_PEEK imezimwa, UNIXCB(oob_skb).consumed += 1 inaongeza sehemu ya 32-bit kwenye offset 0x44. Kwa allocations za SKB zilizo aligned kwa 0x100 hii iko bajeti nne juu ya neno lililopangwa kwa 8-byte, ikibadilisha primitive kuwa increment ya +4 GiB kwenye neno lililohifadhiwa kwenye offset 0x40. Kuibadilisha kuwa kernel write kunahitaji kuweka thamani nyeti ya 64-bit kwenye offset hiyo.

Reallocating the SKB page for arbitrary read

  1. Drain order-0/1 unmovable freelists: Map VMA kubwa isomeka tu (read-only anonymous VMA) na kusababisha fault kila ukurasa ili kulazimisha allocation ya page-table (order-0 unmovable). Kujaza ~10% ya RAM na page tables kunahakikisha allocations za baadaye za skbuff_head_cache zitachukua buddy pages safi mara list za order-0 zinapofungika.
  2. Spray SKBs and isolate a slab page: Tumia stream socketpairs kadhaa na queue ujumbe wadogo mia kadhaa kwa socket (~0x100 bytes kwa SKB) ili kujaza skbuff_head_cache. Free SKBs zilizochaguliwa ili kusukuma target slab page kabisa chini ya udhibiti wa mshambulizi na fuatilia struct page refcount yake kupitia primitive ya kusoma iliyojitokeza.
  3. Return the slab page to the buddy allocator: Free kila object kwenye page, kisha fanya allocations/frees za ziada vya kutosha kuisukuma page kutoka SLUB per-CPU partial lists na per-CPU page lists ili iwe order-1 page kwenye buddy freelist.
  4. Reallocate as pipe buffer: Tengeneza mizinga mingi ya pipes; kila pipe inahifadhi angalau pages mbili za data za 0x1000-byte (PIPE_MIN_DEF_BUFFERS). Wakati buddy allocator inapotenganisha order-1 page, nusu moja inareuse freed SKB page. Ili kupata ni pipe gani na offset gani inalia alias oob_skb, andika bait maalum za marker ndani ya fake SKBs zilizohifadhiwa kote kwenye pipe pages na fanya recv(MSG_OOB | MSG_PEEK) mara kwa mara hadi marker irudishwe.
  5. Forge a stable SKB layout: Jaza aliased pipe page na fake struct sk_buff ambayo data/head pointers na muundo wa skb_shared_info vinaonyesha anwani za kernel zinazovutia. Kwa sababu x86_64 inadhibiti SMAP ndani ya copy_to_user(), anwani za user-mode zinaweza kutumika kama staging buffers hadi kernel pointers zijulikane.
  6. Respect usercopy hardening: Nakala inafanikiwa dhidi ya .data/.bss, vmemmap entries, per-CPU vmalloc ranges, stacks za thread nyingine za kernel, na direct-map pages ambazo hazivuki mipaka ya higher-order folio. Kusoma dhidi ya .text au caches maalum zinazokataliwa na __check_heap_object() tu hurudisha -EFAULT bila kuua mchakato.

Introspecting allocators with the read primitive

  • Break KASLR: Soma descriptor yoyote ya IDT kutoka fixed mapping kwenye CPU_ENTRY_AREA_RO_IDT_VADDR (0xfffffe0000000000) na toa offset ya handler inayojulikana kupata kernel base.
  • SLUB/buddy state: Symbols za global .data zinaonyesha misingi ya kmem_cache, wakati vmemmap entries zinafunua flags za aina ya kila ukurasa, pointer ya freelist, na cache inayomiliki. Kukagua per-CPU vmalloc segments kunaonyesha struct kmem_cache_cpu ili anwani ya allocation inayofuata ya caches muhimu (kwa mfano, skbuff_head_cache, kmalloc-cg-192) iweze kutabirika.
  • Page tables: Badala ya kusoma mm_struct (ambacho kinakatazwa na usercopy), tembea pgd_list (struct ptdesc) na linganisha mm_struct ya sasa kupitia cpu_tlbstate.loaded_mm. Mara pgd ya mizizi inajulikana, primitive inaweza kutembea kila page table ili kuona PFNs za pipe buffers, page tables, na kernel stacks.

Recycling the SKB page as the top kernel-stack page

  1. Free pipe page iliyo chini ya udhibiti tena na thibitisha kupitia vmemmap kwamba refcount yake inarudi sifuri.
  2. Mara moja allocate pages nne za msaada za pipe kisha uzifute kwa mpangilio ulio kinyume ili tabia ya LIFO ya buddy allocator iwe ya hakika.
  3. Piga clone() kuanzisha thread msaada; Linux stacks ni pages nne kwenye x86_64, hivyo pages nne zilizofutwa hivi karibuni zitakuwa stack yake, na page iliyofutwa ya mwisho (formerly SKB page) itakuwa kwenye anwani za juu.
  4. Thibitisha kupitia page-table walk kwamba PFN ya top stack ya thread msaada inalingana na recycled SKB PFN.
  5. Tumia arbitrary read kuangalia layout ya stack huku ukielekeza thread ndani ya pipe_write(). CONFIG_RANDOMIZE_KSTACK_OFFSET inatoa random 0x0–0x3f0 (aligned) kutoka RSP kwa kila syscall; maandishi ya kurudia pamoja na poll()/read() kutoka thread nyingine yanafunua wakati writer anasubiri kwa offset inayotakiwa. Wakati mkono, hoja copy_page_from_iter() bytes (R14) inaweza kuwa kwenye offset 0x40 ndani ya recycled page.

Placing fake SKB metadata on the stack

  • Tumia sendmsg() kwenye AF_UNIX datagram socket: kernel inakopa user sockaddr_un ndani ya sockaddr_storage iliyoko kwenye stack (hadi 108 bytes) na data ya ancillary kwenye buffer nyingine ya stack kabla ya syscall kusubiri nafasi ya queue. Hii inawezesha kuweka fake SKB sahihi kwenye memory ya stack.
  • Gundua wakati nakala imekamilika kwa kutoa control message ya 1-baiti iliyoko kwenye ukurasa wa user usiopangwa; ____sys_sendmsg() itasababisha fault ili kuileta, hivyo thread msaada inayo poll() mincore() juu ya anwani hiyo inajua wakati ukurasa wa marudio uko.
  • Padding zilizo zero-initialized kutoka CONFIG_INIT_STACK_ALL_ZERO zinajaa vitengo visivyotumika, zikikamilisha header halali ya SKB bila maandishi zaidi.

Timing the +4 GiB increment with a self-looping frag list

  • Forge skb_shinfo(fakeskb)->frag_list ili itoje kwa fake SKB ya pili (iliyo kwenye user memory inayodhibitiwa) ambayo ina len = 0 na next = &self. Wakati skb_walk_frags() inapotembea orodha hii ndani ya __skb_datagram_iter(), utekelezaji unaendelea kwa mzunguko bila kikomo kwa sababu iterator hairudi NULL na loop ya nakala haifanyi maendeleo.
  • Weka recv syscall ikitembea ndani ya kernel kwa kuacha fake SKB ya pili iwe self-loop. Wakati ni wakati wa kuwasha increment, badilisha tu next pointer ya SKB ya pili kutoka user space kwenda NULL. Loop itaisha na unix_stream_recv_urg() mara moja itatekeleza UNIXCB(oob_skb).consumed += 1, ikigharibu chochote kinachoshikiliwa kwa sasa kwenye recycled stack page kwenye offset 0x40.

Stalling copy_from_iter() without userfaultfd

  • Map VMA kubwa anonymous RW na uiweke faults kabisa.
  • Tengeneza hole la ukurasa mmoja kwa madvise(MADV_DONTNEED, hole, PAGE_SIZE) na weka anwani hiyo ndani ya iov_iter inayotumika kwa write(pipefd, user_buf, 0x3000).
  • Sambamba, piga mprotect() kwenye VMA nzima kutoka thread nyingine. Syscall inachukua mmap write lock na kutembea kila PTE. Wakati pipe writer anafika hole, page fault handler inasubiri mmap lock iliyoshikiliwa na mprotect(), ikizuia copy_from_iter() kwenye point inayotabirika wakati thamani iliyotupwa ya bytes iko kwenye segment ya stack iliyohifadhiwa kwenye recycled SKB page.

Turning the increment into arbitrary PTE writes

  1. Fire the increment: Acha frag loop wakati copy_from_iter() imebanwa ili increment ya +4 GiB ianguke kwenye variable bytes.
  2. Overflow the copy: Mara fault iendelee, copy_page_from_iter() itaamini inaweza kunakili >4 GiB ndani ya current pipe page. Baada ya kujaza 0x2000 bytes halali (buffers mbili za pipe), itaendelea kwa iteration nyingine na kuandika data ya ziada ya user kwenye physical page yoyote inayofuata pipe buffer PFN.
  3. Arrange adjacency: Kwa kutumia telemetry ya allocator, lazimisha buddy allocator kuweka PTE page inayomilikiwa na process mara moja baada ya pipe buffer page lengwa (kwa mfano, badilisha kati ya allocating pipe pages na kugusa virtual ranges mpya ili kusababisha page-table allocation hadi PFNs ziwe ndani ya block ya 2 MiB).
  4. Overwrite page tables: Encode entries za PTE zinazotakiwa kwenye ziada ya 0x1000 bytes za user data ili OOB copy_from_iter() ijaze page jirani na entries zilizochaguliwa na mshambulizi, ikitoa mappings za RW/RWX za user za kernel physical memory au kurekebisha entries zilizopo kuzima SMEP/SMAP.

Mitigations / hardening ideas

  • Kernel: Apply 32ca245464e1479bfea8592b9db227fdc1641705 (properly revalidates SKBs) na fikiria kuzima AF_UNIX OOB kabisa isipokuwa inapohitajika kwa njia ya CONFIG_AF_UNIX_OOB (5155cbcdbf03). Harden manage_oob() kwa ukaguzi wa ziada wa sanity (kwa mfano, loop hadi unix_skb_len() > 0) na audit protocols nyingine za socket kwa assumptions zinazofanana.
  • Sandboxing: Filter MSG_OOB/MSG_PEEK flags katika seccomp profiles au broker APIs za juu (mabadiliko ya Chrome 6711812 sasa yanazuia MSG_OOB upande wa renderer).
  • Allocator defenses: Kuimarisha randomization ya SLUB freelist au kutekeleza per-cache page coloring kutafanya kuwa ngumu kunakili ukurasa kwa njia ya deterministic; kupunguza idadi ya pipe buffers pia kupunguza uaminifu wa reallocation.
  • Monitoring: Onyesha allocations za kiwango-kikubwa za page-table au matumizi ya pipe isiyo ya kawaida kupitia telemetry—exploit hii inatumia kiasi kikubwa cha page tables na pipe buffers.

References

Tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Jifunze na fanya mazoezi ya Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks