Skip to content

one_gadget

Bir execution target olarak ulaşıldığında, küçük bir register/memory constraint kümesi zaten sağlanıyorsa execve("/bin/sh", NULL, NULL) doğuran tek bir libc adresi — david942j'nin one_gadget aracı tarafından otomatik bulunur.

Mechanism

Note

Glibc, kısa instruction dizileri içerir — tipik olarak exec*/do_system path'leri gibi helper'ların içinde — bunlar execve("/bin/sh", NULL, NULL) için sabitleri yükler ve syscall'u çağırır. Bir one-gadget (namı diğer magic gadget / one-shot gadget), böyle bir diziye doğrudan jump etmenin hiçbir ROP chain olmadan bir shell verdiği tek adrestir, yalnızca ve yalnızca o andaki CPU/memory state'i gadget'ın ön koşullarını (onun constraint'lerini) zaten sağlıyorsa. Güvenlik açısından önemi, control flow'u seçilmiş tek bir libc adresine yönlendirebilen herhangi bir primitive'in — bir GOT/function-pointer overwrite, bozulmuş bir return address, hijack edilmiş bir hook — tek adımda tam code execution'a dönüşebilmesidir; bu da olağan çok aşamalı argument-setup problemini tek bir write'a indirger.

Walkthrough

Üst düzey kullanım ve fikir:

  1. Gadget'ları bul. Aracı hedef libc'e yönelt; execve("/bin/sh",...)'e ulaşan adresleri bulmak için symbolic execution kullanır ve her birini constraint'leriyle raporlar.
    $ one_gadget ./libc.so.6
    0x........ execve("/bin/sh", rsp+0x..., environ)
    constraints:
      [rsp+0x..] == NULL || ...
      rsp & 0xf == 0   # stack alignment
    
  2. Sağlanabilir constraint'lere göre seç. Her gadget, NULL tutan bir register, geçerli bir argv/envp olan bir pointer ya da rsp & 0xf == 0 gibi gereksinimleri listeler. Constraint'leri corruption state'ine zaten uyanı seç.
  3. Kontrolü seçilen adrese yönlendir. Mevcut primitive'i (return-address overwrite, got-overwrite.md, function-pointer-overwrite.md ya da hijack edilmiş bir hook) kullanarak kontrolü gadget adresine aktar.

Warning

One-gadget'lar libc-build'ine özgüdür (offset'ler sürüme/dağıtıma göre değişir) ve constraint ile geçitlenmiştir: yanlış-state'li bir jump basitçe crash eder. Hiçbir gadget'ın constraint'leri sağlanmadığında, attacker'lar ret2libc.md / setcontext-magic-gadget-pivot.md gibi argument-setup chain'lerine geri döner.

Neden chain olmadan çalışır

Gadget zaten execve argümanlarını kuran bir code path'in içindedir; attacker'ın yalnızca kontrolün oraya düşmesine ihtiyacı vardır, argümanların kendisini kurmaya değil.

Detection

  • Process-execution telemetry: bir network/parser servisinin aniden /bin/sh doğurması (asla fork etmemesi gereken bir parent'tan bir shell'in EDR execve'si) yüksek-sinyalli bir anomalidir.
  • Control-flow-integrity / shadow-stack fault'ları ya da libc iç adreslerine çözülen crash'ler, denenmiş bir one-shot yönlendirmesine işaret eder.
  • Bir filo genelinde sabit libc offset'lerinde tekrarlı SIGSEGV'ler, başarılı bir isabetten önce constraint-uyumsuzluğu denemelerini düşündürür.

Mitigation

  • Control-Flow Integrity'yi (CET/IBT, Clang CFI) ve shadow stack'leri etkinleştir, böylece arbitrary libc içlerine indirect jump'lar reddedilir.
  • Full RELRO + non-writable GOT ve hook'lar için pointer mangling, bir one-gadget'ı besleyen yazılabilir control-flow target'larını ortadan kaldırır.
  • ASLR/PIE gadget'ın runtime adresini bilmenin maliyetini yükseltir; libc'i güncel tut, böylece bilinen offset'ler kayar.
  • Seccomp/execve allow-list'leme, kontrol hijack edilse bile shell doğmasını engeller.

References