svcudp_reply gadget¶
glibc'nin Sun RPC
svcudp_reply'ı içinde,rdikontrolü verildiğinde iki memory dereference'ı dolaylı bircalliçine zincirleyen sabit-offset'li bir gadget — leakless ret2dlresolve ve FSOP chain'lerinde kullanılan controllable call / stack-pivot primitive'i.
Mechanism¶
Invariant
svcudp_reply sıradan kütüphane kodudur, ama birkaç byte içeride kısa bir
instruction penceresi (yaygın glibc build'lerinde svcudp_reply+26) güçlü
bir gadget oluşturur: rdi'da köklenen bir pointer chain'i dolaşır ve dolaylı
bir call ile biter. libc'de kararlı bir offset'te yaşadığı için, libc base'ini
bilen (ve rdi'ı kontrol eden) bir attacker, temiz bir pop güdümlü gadget'a
ihtiyaç duymadan bir controllable call elde eder — modern libc'de aksi
halde kıt olan türden bir primitive.
Temsili sekans (herkese açık pwn writeup'larına göre) şöyledir:
mov rbp, [rdi+0x48] ; rbp := *(rdi+0x48) (attacker-influenced)
mov rax, [rbp+0x18] ; rax := *(rbp+0x18)
lea r13, [rbp+0x10]
mov dword [rbp+0x10], 0
mov rdi, r13
call [rax+0x28] ; indirect call through a chosen pointer
rdi'ın gerçek bir RPC transport handle'ına işaret
ettiğini asla doğrulamaz. Attacker özel hazırlanmış bir structure sağlarsa
(veya rdi'ı _IO_2_1_stdout_ gibi kontrol edilen bir libc objesine
yöneltirse), her dereference attacker'ın yerleştirdiği pointer'lara düşer ve
son call [rax+0x28] kontrolü seçtikleri bir hedefe aktarır — sıklıkla
stack'i bir ROP chain'e pivot etmek için bir leave; ret'e (bkz.
stack-pivoting).
Bu not, genel stack pivot primitive'inden ayrıdır: orası
pivot'un kendisini (RSP'yi taşıyan gadget'lar) anlatır; bu not ise spesifik,
libc-sürümüne bağlı svcudp_reply gadget'ının nasıl bir controllable call
sağlayıp o pivot'a köprü kurduğunu anlatır.
Walkthrough¶
Herkese açık dl_runtime_resolve + svcudp_reply writeup'ını takip eden kavramsal
yeniden üretim. Gadget, attacker'ın bir call site'ında rdi'ı kontrol ettiği ama
register yükleyen gadget'lardan yoksun olduğu yerlerde kullanılır:
- Pointer chain'i kur.
[rdi+0x48]'e bir değer yerleştir kirbp, attacker'ın kontrol ettiği bir region olsun (örneğin bir fake structure ya da daha önceki bir write ile doldurulmuş bilinen bir libc objesi). - Call hedefini yerleştir.
[rbp+0x18]'e öyle birraxpointer'ı koy ki[rax+0x28]istenen bir sonraki adresi tutsun — yaygın olarakleave; ret'in adresi. - Tetikle. Hazırlanmış
rdiilesvcudp_reply+26'yı çağırmak chain'i çalıştırır vecall [rax+0x28]execute olur. Orada birleave; retvarsa,rspattacker'ın fake stack'ine migrate eder ve tam bir ROP chain (örneğinsystem'inret2dlresolvetarzı bir resolve'u) çalışır.
Neden tam olarak bu gadget
leakless senaryolarda değer taşır: ret2dlresolve ile birleştiğinde,
yalnızca .text'i ve uzun bir yazılabilir region'ı kontrol eden bir
attacker'ın, önce bir libc adresi leak'lemeden bir dolaylı call ve stack
pivot sürmesine olanak tanır. Tam offset (+26) ve alan offset'leri (0x48,
0x18, 0x28) glibc-sürümüne özgüdür; savunmacılar bunları evrensel değil,
örnekleyici olarak ele almalıdır.
Detection¶
- Sun RPC /
librpcsvckullanmayan bir process'tesvcudp_replyiçinden kaynaklanan bircallanormaldir; bu girişi gösteren sembolize edilmiş stack trace'leri veyaperf/EDR call-graph'ları güçlü bir sinyaldir. rsp'yi hemen bir heap/bssregion'ına pivot eden (eşlenmiş stack dışındaki stack-pointer) libc içindeki bir dolaylı call hedefi, gadget'ı tipik devamcısıyla eşleştirir.call [rax+0x28]site'ındaki CFI/shadow-stack fault'ları forge edilmiş bir call hedefine işaret eder.
Mitigation¶
- Clang CFI / forward-edge control-flow
integrity, dolaylı
call [rax+0x28]'i tip-eşleşmeyen bir hedefe reddeder. - Intel CET shadow stack return
address uyuşmadığında sonraki
leave; retstack pivot'unu yakalar. - libc'yi legacy Sun RPC kodu olmadan derlemek (modern glibc RPC'yi ayrı
libtirpc'ye taşıdı vesvcudp_reply'ı libc'den kaldırdı) gadget'ı ortadan kaldırır; libc'yi güncel tut. - Genel hardening — ASLR ve Full RELRO — libc'yi bulmanın ve chain'in sıklıkla hedeflediği GOT'u suistimal etmenin maliyetini yükseltir.