
pedit COW
CVE-2026-46331 (별명 “pedit COW”)은 트래픽 제어 하위 시스템의 로컬 Linux 커널 권한 상승 결함입니다. 권한이 없는 사용자(권한이 없는 네트워크 네임스페이스)는 act_pedit (패킷 편집기) 필터를 구성하여 부분적인 copy-on-write (COW) 쓰기를 페이지 캐시에 트리거할 수 있습니다. 결과적으로 커널은 공격자가 제어하는 데이터를 파일의 메모리 내 이미지에 페이지를 프라이빗으로 표시하지 않고 기록하여 해당 파일의 캐시된 복사본을 손상시킵니다. 결정적으로, 이 익스플로잇은 CAP_NET_ADMIN만 필요하며 (사용자 네임스페이스에서 얻을 수 있음) 디스크 상의 파일을 수정하지 않습니다. 실제로, packet_edit_meme이라는 작업 개념 증명(PoC)이 2026년 6월 17일에 공개되어 setuid 바이너리(예: /bin/su)의 페이지 캐시 이미지를 덮어써서 루트 셸을 생성하는 방법을 보여주었습니다. 이 취약점은 **tcf_pedit_act()**에서 잘못된 COW 범위 계산으로 인해 발생하며, 각 키 루프 내로 쓰기 가능 영역 검사를 이동하여 업스트림에서 수정되었습니다(2026년 6월 4일).
act_pedit가 있는 Linux 커널 (약 v5.18 ~ 7.1-rc6). 패치되지 않은 안정 릴리스 (많은 배포판 커널 포함)는 취약합니다.tc pedit 필터를 설정한 후 메모리 내 setuid 바이너리의 ELF 진입점을 셸코드로 덮어씁니다.skb_ensure_writable()을 키 루프 내부로 이동). 임시 조치로 act_pedit 모듈을 차단하거나 언로드하거나 권한이 없는 사용자 네임스페이스를 비활성화 (예: sysctl user.max_user_namespaces=0). 완화 후 캐시를 삭제하여 (echo 3 > /proc/sys/vm/drop_caches) 오염된 페이지를 제거합니다.이 보고서는 CVE-2026-46331에 대한 상세한 기술 분석(원인, 익스플로잇, 탐지 및 완화 전략)을 제공하며, 공급업체 권고, CVE 및 공개 익스플로잇에 대한 참조를 포함합니다.
정의: CVE-2026-46331은 Linux 커널의 트래픽 제어 (net/sched) 하위 시스템, 특히 act_pedit (패킷 편집기) 액션에서의 out-of-bounds 쓰기 버그입니다. 함수 **tcf_pedit_act()**는 정적 힌트 tcfp_off_max_hint를 사용하여 typed 키를 반복하기 전에 패킷 편집 작업을 위한 "copy-on-write" 범위를 계산합니다. 그러나 일부 키(예: TCP/UDP 헤더 편집)는 런타임에만 최종 바이트 오프셋을 결정합니다. 코드는 이러한 동적 오프셋에 대해 쓰기 가능성을 다시 확인하지 않습니다. 결과적으로 사전 COW'd 영역 외부에서 쓰기가 발생할 수 있습니다. 패킷 쓰기의 일부가 프라이빗으로 설정되지 않아 부분적 COW가 발생합니다. 이 잘못된 쓰기는 (패킷 버퍼가 우연히 파일 페이지를 참조하는 경우) 파일의 공유 페이지 캐시 메모리로 전파되어 캐시된 파일 이미지를 손상시킵니다.
배경: Linux 패킷 편집기 (pedit) 액션을 사용하면 관리자가 구성된 tc 필터를 통과하는 패킷의 패킷 헤더(링크, 네트워크 또는 전송 계층) 내에서 임의의 바이트를 다시 쓸 수 있습니다. 이는 오프셋(헤더에 고정될 수 있음)과 32비트 값/마스크를 지정하여 작동합니다. 내부적으로 pedit는 소켓 버퍼(sk_buff)에서 작동하며 수정 전에 대상 패킷 메모리를 쓰기 가능하게 만들어야 합니다(COW 방식으로 skb_ensure_writable()을 통해). 이상적으로 커널은 공유 페이지를 쓰기 전에 복제(프라이빗 복사)하여 다른 곳에서 사용되는 메모리 변경을 방지해야 합니다.
근본 원인: tcf_pedit_act()에서 코드는 tcfp_off_max_hint(최대 정적 오프셋)를 사용하여 쓰기 가능 범위를 한 번만 미리 계산합니다. 이 힌트는 typed 키가 패킷 처리 중에 추가하는 런타임 헤더 오프셋을 포함하지 않습니다. TCP 또는 UDP와 같은 키는 런타임 시 IP 헤더의 위치를 기반으로 오프셋을 계산할 수 있습니다(예: 이전 키가 네트워크 헤더를 이동시키는 경우). 따라서 키별 루프 중에 키의 실제 오프셋이 사전 할당된 쓰기 가능 범위를 초과할 수 있습니다. 그런 다음 코드는 skb_store_bits()를 통해 패킷 메모리에 쓰지만, 사전 COW'd 영역 너머의 페이지가 프라이빗으로 설정되지 않았기 때문에 쓰기는 여전히 페이지 캐시와 공유되는 페이지를 손상시킵니다. 요약하면, "쓰기 가능 패킷 범위를 너무 일찍 계산" 하여 범위를 벗어난 교차 페이지 쓰기가 발생합니다. 음수 오프셋(예: 수신 시 이더넷 헤더 편집)도 잘못 처리되며, 심지어 offset_valid()도 INT_MIN에 대한 보호 장치가 없어 결함을 악화시켰습니다.
발생 이유: 이 버그는 본질적으로 copy-on-write 범위 계산의 논리 오류입니다. 커널은 정적 최대 오프셋(로드 시 알려짐)이 모든 편집에 충분하다고 가정했습니다. 동적 오프셋이 있는 키가 실제로 적용될 때 COW 범위를 업데이트하지 못했습니다. 일련의 대기 중인 편집 후 최종 쓰기는 사전 확인된 영역 밖에 있을 수 있습니다. 패킷 버퍼가 메모리 매핑된 파일 페이지(예: 제로 카피 메커니즘을 통해)를 참조할 수 있기 때문에 이 "부분적 COW" 쓰기는 디스크에 있는 파일의 페이지 캐시에 도달할 수 있습니다. 실제로 패킷 편집기 액션은 sendfile 또는 splice에서 페이지를 수신할 수 있습니다. 따라서 단일 패킷 필터 작업이 간접적으로 공격자가 선택한 데이터를 파일의 메모리 내 이미지에 기록할 수 있으며, 디스크는 변경되지 않습니다.
구성 요소 및 데이터 흐름: 취약한 코드는 Linux net/sched 하위 시스템(act_pedit.c)에 있습니다. 패킷이 구성된 pedit 규칙과 일치하면 tcf_pedit_act()가 호출됩니다. 내부적으로 정확히 한 번 skb_ensure_writable(skb, X)를 호출하며, 여기서 X = tcfp_off_max_hint입니다. 이렇게 하면 패킷의 처음 X 바이트가 프라이빗(COW'd)이 됩니다. 그런 다음 각 키(편집 작업)에 대한 루프에서 키의 런타임 헤더 오프셋을 키의 지정된 오프셋에 추가하여 키의 실제 쓰기 오프셋을 계산하고 32비트 값을 패킷에 씁니다. 의사 코드에서:```c
u32 off_max = action->tcfp_off_max_hint;
skb_ensure_writable(skb, off_max);
for (i = 0; i < num_keys; i++) {
u32 hdr_off = compute_header_offset(skb, key[i].hdr_type);
u32 write_off = hdr_off + key[i].offset;
skb_store_bits(skb, write_off, &key[i].value, 4);
}
`hdr_off`가 각 키를 처리할 때만 계산되기 때문에, 초기 `skb_ensure_writable()` 호출은 이를 고려하지 않았습니다. `hdr_off + key[i].offset`이 `off_max`를 초과하면, 코드는 메인 선형 영역 대신 조각(fragments)에 대해 `skb_store_bits()`로 폴백(fallback)하며, 이는 비공개로 설정되지 않은 페이지에 쓰기를 수행함을 의미합니다. 이것이 실패 지점입니다.
**공격 표면(Attack Surface):** 필요한 유일한 인터페이스는 `pedit` 액션이 있는 **tc 필터**이며, 이는 일반적으로 **CAP_NET_ADMIN** 역량이 필요합니다. 그러나 일반 사용자는 실제 권한 없이 개인 네트워크 네임스페이스(사용자 네임스페이스 클로닝) 내에서 CAP_NET_ADMIN을 획득할 수 있습니다. 따라서 권한이 없는 사용자는 user+net 네임스페이스에 진입하여 루프백(loopback)에 `tc pedit` 규칙을 생성할 수 있습니다. 쓰기는 패킷이 처리될 때 발생하며(공격자는 일반적으로 이를 트리거하기 위해 루프백에서 트래픽을 생성합니다). 사용자와 커널 간의 신뢰 경계(trust boundary)는 커널이 자체 COW 설정을 신뢰했지만, 사용자가 제공한 오프셋이 그 가정을 깨뜨렸기 때문에 위반됩니다.
**내부 메커니즘(Internal Mechanism):** 커널 측에서 이 취약점은 **범위를 벗어난 쓰기(out-of-bounds write)**(CWE-787)로 나타납니다. 이는 사용자 공간에 매핑된 커널 메모리(파일 페이지 캐시)를 손상시킵니다. 구체적으로, 소켓 버퍼에 매핑된 모든 파일 페이지의 내용을 덮어쓸 수 있습니다. 개념 증명(proof-of-concept)에서 `/bin/su`는 소켓 버퍼로 전송되어 mmap되므로, 익스플로잇(exploit)은 메모리에서 해당 엔트리 포인트 바이트를 뒤집습니다. 이는 디스크 상의 파일을 수정하지 않지만, 이후 해당 바이너리를 실행할 때마다 캐시에서 감염된 이미지를 읽습니다. 블로그 분석에서는 다음과 같이 언급합니다:
> "skb가 sendfile을 통해 가져온 제로 카피 페이지를 참조할 수 있기 때문에, 그 범위를 벗어난 쓰기는 실제 파일을 뒷받침하는 공유 페이지 캐시 메모리에 도달할 수 있습니다. 커널은 패킷 메모리를 수정해도 안전하게 만들었다고 믿었습니다. 그러나 실제로는 이후의 쓰기가 실제로 비공개화한 영역 밖에 도달합니다."
**신뢰 경계(Trust Boundaries):** 커널은 `skb_ensure_writable()`(고속 경로 COW)이 이후 모든 쓰기에 대해 안전을 보장할 것이라고 잘못 가정했습니다. 각 키에 대해 다시 확인하지 않았습니다. 사용자는 패킷 필터 구성과 패킷 내용만 제어하며, 커널이 (네트워크 네임스페이스를 통해) 이를 허용했습니다. 일단 그 신뢰가 침해되면, 쓰기는 보호되어야 했던 파일 지원 메모리로 탈출했습니다.
## 근본 원인 분석(Root Cause Analysis)
근본 원인은 **pedit 액션에서 잘못된 COW 범위 계산**입니다. 코드 측면에서, `tcfp_off_max_hint`를 기반으로 한 길이로 `skb_ensure_writable()`이 한 번 호출되었고, 루프 내에서 실제 오프셋이 이를 초과할 수 있었습니다. 2026년 5월의 작은 패치는 이를 수정하여, 실제 오프셋이 알려진 후 `skb_ensure_writable()`을 루프 *내부*로 이동하고, 음수 오프셋에 대한 검사와 특수 처리를 추가했습니다. 다시 말해:
- **버그 코드(buggy code):** ```c
skb_ensure_writable(skb, action->tcfp_off_max_hint);
for each key:
// compute offset (hdr_off + key_offset)
skb_store_bits(skb, write_off, ...);
Additionally, the fix ensures that for negative offsets (Ethernet header edits) it uses skb_cow() on headroom, and guards against INT_MIN cases. The commit message (stack.watch summary) states: “Fix by moving skb_ensure_writable() inside the per-key loop where the actual write offset is known, and add overflow checking on the offset arithmetic.”.
Thus, why it exists: during code review or design, the per-key re-calculation was overlooked. The static hint optimization bypassed the need to re-evaluate per key. It appears to be an honest bug rather than a malicious oversight, but its effect is severe because it violates the COW assumption. As TuxCare notes, this bug was merged under the guise of a routine “data corruption” fix, without immediate security context.
이 취약점은 커널 커밋 8b796475fd78(2022년 5월)에 의해 도입되었으며, 2026년 초까지 발견되지 않고 남아 있었습니다. 소스에 따르면, 수정(커밋 899ee91156e5, 2026년 5월 31일)은 일반적인 데이터 손상(data-corruption) 패치로 netdev 메일링 리스트에 제출되었습니다. 커널 관리자들은 2026년 6월 4일 net-7.1-rc7에 해당 수정을 병합했습니다. CVE-2026-46331이 공식적으로 할당된 것은 2026년 6월 16일이었습니다(패치가 나타난 후 약 2주 후). 완전히 무기화된 공개 익스플로잇은 2026년 6월 17일에 등장했습니다(packet_edit_meme PoC).
실제로 순서는 다음과 같았습니다:
여러 관계자가 공개된 패치를 통해 이 버그를 알아챘습니다. 예를 들어, Massimiliano Oldani(사이버보안 연구원)는 이후 상세한 보고서와 익스플로잇을 게시하며 *“CVE 할당 후 24시간 이내에 packet_edit_meme이라는 공개된 작동하는 개념 증명 익스플로잇이 GitHub에 나타났습니다”*라고 언급했습니다. CloudLinux, TuxCare, SentinelOne은 PoC가 공개되고 CVE가 할당된 후 분석을 발표했습니다. Debian 보안 추적기와 PT DBugs도 문제와 사용 가능한 권고 사항을 요약했습니다(참고 자료 참조).
현실적인 공격은 최소한의 사전 조건만 필요합니다:
공격자 역량: 대상 머신의 로컬 비특권 사용자. 사용자는 새로운 사용자 네임스페이스와 네트워크 네임스페이스를 생성할 수 있어야 합니다 (unshare(CLONE_NEWUSER|CLONE_NEWNET) 사용). 이는 실제 루트 권한 없이도 해당 네임스페이스 내에서 CAP_NET_ADMIN을 부여합니다. 비특권 사용자 네임스페이스는 많은 커널(예: RHEL, Debian)에서 기본적으로 활성화되어 있으며, Ubuntu에서는 aa-exec 우회 방법을 사용하여 다시 활성화할 수 있습니다.
대상 조건: 대상은 취약한 Linux 커널(약 5.18–7.1-rc6)에서 act_pedit 모듈을 사용할 수 있어야 합니다. act_pedit가 내장되었거나 이미 로드된 경우 즉시 익스플로잇이 가능합니다. 모듈인 경우 tc pedit 규칙이 구성될 때 자동으로 로드됩니다. 대상은 업스트림 패치를 적용하지 않은 상태여야 합니다. 특히 공격자가 어떤 파일에 대해 쓰기 접근 권한을 가질 필요가 없습니다. 익스플로잇은 패킷 필터를 통해 쓰기 작업을 수행합니다.
공격 체인:
unshare --map-root-user --net --pid bash와 같은 명령을 실행하여 새로운 사용자+네트워크 네임스페이스를 생성합니다. 이렇게 하면 해당 네임스페이스(내부에서 사용자가 루트로 매핑됨)에 CAP_NET_ADMIN이 부여됩니다.ifconfig lo up)하고 선택적으로 리스너(예: nc -l 127.0.0.1 9999)를 띄웁니다. 이렇게 하면 TC 액션에 사용할 패킷 흐름이 제공됩니다.tc 명령 또는 netlink를 사용하여 공격자는 lo에 qdisc와 필터를 생성하여 모든 패킷과 일치시키고(예: ) 특별히 조작된 키를 가진 액션을 연결합니다. 각 키는 동적 헤더 유형(예: L4 오프셋에 대한 IP 헤더)과 실제 쓰기 위치(헤더 시작 + 오프셋)가 이 처리하는 범위 바로 밖에 있도록 선택된 오프셋을 가집니다.영향: 성공하면 공격자는 로컬에서 완전한 루트 권한을 얻습니다. 익스플로잇은 한 번의 명령으로 수행 가능하며 결정적입니다. 또한 임의의 파일 지원 페이지 손상은 다르게 사용될 경우 서비스 거부(시스템 충돌)를 유발할 수 있습니다. 공개된 PoC는 특히 /bin/su의 진입점을 셸코드로 덮어썼지만, 공격자가 매핑할 수 있는 모든 파일이 대상이 될 수 있습니다. 이 체인은 특별한 타이밍이나 경쟁 조건이 필요 없으며 많은 배포판(RHEL, Ubuntu, Debian 등)에서 시연되었습니다.
공개된 익스플로잇인 packet_edit_meme은 GitHub(sgkdev/packet_edit_meme)에서 사용할 수 있으며 /bin/su를 대상으로 합니다. 우리는 파괴적인 페이로드 없이 필수 로직을 설명합니다:```c
/* Pseudocode outline of the exploit (simplified) /
int main() {
/ 1. Identify a setuid binary (su) and its ELF entry offset */
int fd = open("/bin/su", O_RDONLY);
long entry = elf_entry_offset(fd);
if (entry < 0) abort();
printf("Target %s (UID=%d), entry offset 0x%lx\n", "/bin/su", getuid(), entry);
/* 2. Unshare user+net namespace to get CAP_NET_ADMIN locally */
if (unshare(CLONE_NEWUSER | CLONE_NEWNET) < 0) abort();
/* Map UID/GID to root (handled via /proc/self/uid_map, /gid_map) */
// (omit details: write "0 <uid> 1" to /proc/self/uid_map and gid_map, and deny setgroups)
/* 3. Setup environment: bring up loopback and listener */
if (system("ip link set lo up") < 0) abort();
if (system("nc -l 127.0.0.1 9999 &") < 0) abort();
/* 4. Configure a tc pedit action via netlink (simplified) */
// Assume 'pedit_write' sends a packet-edit command to the kernel.
// The key offsets below are chosen such that they exceed the initial COW range.
char shellcode[/*size=48*/] = {
// (assembly for setgid(0); setuid(0); execve("/bin/sh").., padded to 36 or 48 bytes)
};
size_t total = sizeof(shellcode), sent = 0;
while (sent < total) {
int chunk = min(PEDIT_MAX_WRITE, total - sent);
/* Issue TC pedit action to write next chunk */
if (pedit_write(fd, entry + sent, &shellcode[sent], chunk) != 0) {
fprintf(stderr, "pedit_write failed\n");
exit(1);
}
sent += chunk;
}
/* 5. Trigger execution of su (in original namespace) */
execl("/bin/su", "su", NULL); // This will run the poisoned binary as root
return 0;
}
이 의사 코드는 흐름을 설명합니다: `/bin/su`를 열고, 네임스페이스를 분리(unshare)하여 CAP_NET_ADMIN을 획득하고, 루프백과 TC pedit 규칙을 구성한 다음, `pedit_write(fd, offset, data, len)` 함수(실제 PoC에서는 내부적으로 netlink 호출을 사용)를 호출하여 대상의 페이지 캐시를 덮어씁니다. 마지막으로 바이너리가 실행되어 루트 셸이 생성됩니다.
실제 PoC는 더 복잡하지만(UID/GID 맵, 네트워크 수신, 시스템콜 수준의 셸코드 바이트 처리), 핵심 개념은 위와 같습니다. **안전한 테스트 환경 외에는 이 익스플로잇을 실행하지 말 것**과 실제 시스템을 대상으로 하지 말 것을 강조합니다. 위 내용은 데모 목적으로만 제공됩니다.
**참고:** 공개된 안전한 PoC가 존재하지 않았다면, 우리는 명시적으로 그렇게 명시했을 것입니다. 이 경우 PoC는 공개되어 있으며, 개념적으로 설명합니다. 간결함과 안전을 위해 원시 셸코드 바이트와 실제 netlink 세부 정보는 생략했습니다.
## 익스플로잇 흐름
1. **진입점:** 공격자는 먼저 CAP_NET_ADMIN을 획득해야 합니다. 일반적으로 권한이 없는 프로세스에서 `unshare`를 통해 사용자+네트워크 네임스페이스를 생성하여 네임스페이스-로컬 CAP_NET_ADMIN을 얻습니다.
2. **초기 접근:** 이 네임스페이스 내에서 공격자는 일반 도구(`ip`, `tc`)를 사용하여 트래픽 제어를 구성할 수 있습니다. 이제 커널의 `act_pedit` 코드 경로가 패킷에 대해 접근 가능해집니다.
3. **트리거:** 공격자는 루프백 인터페이스에 `tc filter ... action pedit`을 설정합니다. 이 필터는 패킷(예: 0-매치)을 일치시키고 헤더 유형(IP, TCP)과 오프셋이 있는 하나 이상의 **typed keys**를 지정합니다. 오프셋은 *커널이 루프 내에서 헤더 베이스를 계산한 후* 최종 쓰기 오프셋이 초기 COW 범위를 초과하도록 선택됩니다.
4. **익스플로잇:** 필터와 일치하는 패킷이 처리될 때 커널은 `tcf_pedit_act()`를 호출합니다. 이 함수는 *불충분한* `skb_ensure_writable()`을 수행한 후 키를 반복합니다. 적어도 하나의 키에 대해 쓰기는 *개인 복사본으로 복제되지 않은* 페이지에 도달합니다. 이로 인해 공유 페이지 캐시로 **범위를 벗어난 쓰기(out-of-bounds write)**가 발생합니다. 소켓 버퍼가 (sendfile/splice를 통해) 파일의 페이지를 참조하도록 준비되었다면, 해당 쓰기는 그 파일 페이지를 손상시킵니다.
5. **익스플로잇 후:** 공격자의 셸코드가 대상 바이너리(예: `/bin/su`)의 페이지 캐시에 기록되었습니다. 공격자(원래 네임스페이스)는 `/bin/su`를 실행합니다. 커널은 메모리 내 이미지(주입된 페이로드 포함)를 읽고 셸코드를 실행하여 공격자에게 루트 셸을 제공합니다. 이 시점에서 시스템이 완전히 손상되었습니다.
6. **영향:** 공격자는 루트 권한을 획득합니다. 기밀 데이터는 덮어쓸 수 있지만 직접 유출되지는 않습니다. 무결성은 완전히 손상됩니다(공격자는 모든 파일의 메모리 이미지를 변경할 수 있음). 가용성에도 영향을 줄 수 있습니다(중요한 페이지를 잘못 쓰면 프로세스나 시스템이 충돌할 수 있음). CVSS 메트릭: 전체적으로 중간(CVSS 3.1=6.0)이지만 실제 영향은 심각한 로컬 루트입니다.
이 흐름은 다이어그램으로 요약됩니다:```mermaid
flowchart LR
A[Attacker (unprivileged user)] --> B[Unshare into user+net namespace<br>(gains CAP_NET_ADMIN)]
B --> C[Configure TC pedit filter on lo]
C --> D{Packet processing by kernel}
D --> E[act_pedit computes wrong COW range]
E --> F[skb_store_bits writes beyond COW'd region]
F --> G[Page cache of target file is corrupted]
G --> H[Attacker executes poisoned setuid binary]
H --> I[Root shell obtained]
act_pedit 모듈이 lsmod에 예기치 않게 나타나는 경우 (예: 웹 서버에서 lsmod | grep act_pedit 결과가 비어 있지 않음).tc 사용: 권한이 없는 프로세스의 비정상적인 tc 명령어 또는 netlink 메시지. 감사 로그에서 비루트 프로세스에 CAP_NET_ADMIN이 부여된 것을 확인할 수 있음.netstat -tulnp에서 127.0.0.1에 nc 또는 사용자 정의 리스너가 표시되는 경우 징후일 수 있음.tcf_pedit_act, skb_ensure_writable 관련 Oops 또는 경고, 루프백의 과도한 트래픽 중 소프트 락업, tc 처리 오류 (이러한 현상은 비정상적이며 손상을 나타냄).auditd)에서 프로그램이 userns를 통해 CAP_NET_ADMIN을 획득하거나 에 쓰는 것을 보여줌.예를 들어, 하나의 공격 지표(IOA)는 페이지 캐시 내 손상된 파일입니다. 분류 체크리스트에는 특히 과도한 tc 활동 후 setuid 바이너리의 메모리 내 파일 내용을 디스크와 비교하는 것이 포함될 수 있습니다. 또 다른 지표는 새로운 네임스페이스 생성입니다. unshare(CLONE_NEWUSER|CLONE_NEWNET) 호출을 모니터링하는 것이 플래그될 수 있습니다. 간단히 말해, 방어자는 act_pedit 사용, userns 사용, RAM 내 실행 파일의 갑작스러운 수정 등 어느 것이든 주시해야 합니다.
익스플로잇 시도를 탐지하려면:
tc 구성 또는 act_pedit 필터를 추가하는 netlink 메시지에 대해 경고합니다. 예를 들어 Sigma 규칙은 TCA_ACT_KIND: pedit 또는 유사한 내용을 포함하는 이벤트를 찾을 수 있습니다. 비루트 프로세스의 capset CAP_NET_ADMIN 또는 /proc/*/uid_map 쓰기에 대한 감사 로그를 모니터링하십시오./bin/su(또는 기타 민감한 바이너리)를 읽고 네임스페이스/unshare 시스템 콜과 함께 갑자기 실행하는 프로세스를 감시합니다. setuid 바이너리를 열고 userns를 생성하는 모든 프로세스에 대해 경고합니다.skb_ensure_writable()이 속지 않도록 강제합니다(알려진 내장 검사는 없음).요약하면, 방어자는 사용자 네임스페이스 사용, tc 명령, 모듈 로드를 기록하고 감사해야 합니다. 핵심 접근 방식: 신뢰할 수 없는 사용자의 tc pedit 호출을 거부하거나 기록하는 것입니다. 손상된 호스트에서는 /etc/modprobe.d/disable-act_pedit.conf가 적용되었는지 확인하십시오(사전에 적용되어 있어야 합니다).
패치 적용: 주요 수정 사항은 커널 업데이트입니다. 2026년 6월에 모든 주요 배포판이 업데이트를 출시했습니다. 패치된 커널(Linux 7.1.0 이상 또는 배포판 백포트)로 업그레이드하는 것이 확실한 해결책입니다.
구성 변경: 즉시 패치가 불가능한 경우, 완화 조치를 구현하십시오:
act_pedit 비활성화: 워크로드에 tc pedit가 필요하지 않다면, 모듈을 블랙리스트에 추가하십시오. 예를 들어: ```
echo 'install act_pedit /bin/true' | sudo tee /etc/modprobe.d/disable-act_pedit.conf
lsmod | grep -w act_pedit && sudo rmmod act_pedit
이렇게 하면 해당 액션을 로드할 수 없습니다. (CloudLinux와 TuxCare에서 권장합니다.) 합법적으로 tc pedit를 사용하는 호스트에는 적용하지 마십시오.
Ubuntu 22.04+에서: ``` sudo sysctl -w kernel.unprivileged_userns_clone=0 echo 'kernel.unprivileged_userns_clone = 0' | sudo tee /etc/sysctl.d/99-pedit-cow.conf
이는 권한이 없는 사용자가 CAP_NET_ADMIN을 얻기 위해 필요한 사용자 네임스페이스를 생성하는 것을 방지합니다. 참고: 네임스페이스를 비활성화하면 루트리스 컨테이너 및 일부 샌드박스 애플리케이션이 손상될 수 있습니다.
- **페이지 캐시 삭제 (격리):** 익스플로잇이 실행되었다고 의심되면, 메모리 내 바이너리 복사본이 오염되었을 수 있습니다. 즉시 캐시를 삭제하여 제거하십시오: ```
sudo sh -c "echo 3 > /proc/sys/vm/drop_caches"
이는 디스크에서 페이지를 강제로 다시 로드합니다. 주의사항: 공격자가 이미 루트 권한을 가지고 있었다면, 캐시를 삭제해도 설치된 지속성 메커니즘은 제거되지 않습니다. 이러한 호스트는 손상된 것으로 간주하십시오.
최소 권한: tc를 사용할 수 있는 사용자를 감사하고 제한합니다. 익스플로잇에는 CAP_NET_ADMIN만 필요합니다. 신뢰할 수 있는 관리자만 이 권한을 가지도록 하십시오. RBAC 또는 컨테이너화를 사용하여 권한 부여를 제한하십시오.
네트워크 제어: 직접 네트워크를 통해 액세스할 수는 없지만, 루프백 사용을 모니터링해야 합니다. 127.0.0.1을 방화벽으로 차단하는 것은 비현실적이지만, TC 조작에는 로컬호스트 트래픽만 사용되도록 하십시오.
벤더 권고: 해당 OS의 공식 권고를 참조하십시오. Red Hat은 RHEL 8/9/10용 RHSA-2026:27354(및 관련)를 제공했으며, Debian은 DSA-6355-1, Ubuntu의 CVE 페이지는 수정된 커널을 나열합니다. (참고문헌 참조.)
장기적인 해결 방법은 영향을 받는 모든 시스템이 업데이트된 커널을 사용하도록 하는 것입니다. 수정 사항이 포함된 커널 패키지를 설치하고 시스템을 재부팅해야 합니다. 재부팅할 수 없는 컨테이너나 시스템의 경우, 패치를 준비한 라이브패치 솔루션(예: KernelCare)을 고려하십시오.
또한, 시스템 설계는 사용자 공간에서 접근 가능한 커널 인터페이스가 시간이 지남에 따라 변경될 수 있다고 가정해야 합니다. CAP_NET_ADMIN을 제한하고 tc 사용을 필터링하는 것은 이 버그 외에도 좋은 관행입니다.
침해가 발생한 경우 시스템을 재구축하십시오. 이 취약점은 페이지 캐시만 오염시키지만, 루트 권한을 가진 공격자가 다른 악의적인 행위를 했을 수 있습니다. 포렌식 검증이 필요합니다. 익스플로잇 이후 파일 무결성 검사에 의존하지 마십시오. PoC가 디스크 상의 파일을 그대로 남겨두기 때문입니다. 재부팅 및 패치 적용이 안전한 해결 방법입니다.
이러한 요소를 고려할 때, 일반적인 CVSS v3.1 벡터는 AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:H이며, **기본 점수 6.0(중간)**을 산출합니다. 그러나 CVSS는 이 취약점이 루트로의 권한 상승을 허용한다는 점을 포착하지 못하는데, 이는 실제로 심각합니다. (일부 소스는 유사한 버그에 대해 CVSSv4를 계산했습니다. 예: PT DBugs는 CVSSv4에서 8.5를 나열합니다.)
심각도는 종종 벤더에 의해 중요/심각으로 평가됩니다. Red Hat은 이 CVE에 대한 권고에서 중요로 표시하고, AWS는 중간(CVSS 6.0)으로 표시합니다. 어쨌든 루트를 획득할 수 있기 때문에, 실질적인 위험은 다중 사용자 또는 공유 시스템에서 가장 높습니다.
이 취약점은 페이지 캐시 오염 버그 계열에 속합니다. 다른 주목할 만한 CVE는 다음과 같습니다:
splice()가 COW 경계를 넘어 페이지 캐시에 쓸 수 있었습니다. 또한 메모리 내 파일을 덮어쓸 수 있었습니다(디스크 변경 없음)./proc/self/mem의 copy-on-write에서 발생한 오래된 결함으로, 읽기 전용 매핑에 대한 로컬 쓰기를 허용했습니다.이 각각은 커널이 독점적으로 소유하고 있다고 믿었던 메모리에 커널 고속 경로가 쓰는 것을 포함하지만, 실제로는 그렇지 않았습니다. CVE-2026-46331은 net/sched pedit 액션에서 발생하고 사용자 네임스페이스를 활용하여 권한 제한을 우회한다는 점에서 독특합니다. DirtyPipe나 Dirty COW와 달리 보조 권한 프로세스(예: 잘못된 시스템)가 필요하지 않습니다. 단일 비권한 사용자가 트리거할 수 있습니다.
모든 참고문헌은 평판이 좋은 출처(벤더 권고, 공개 분석, CVE/NVD 항목)에서 가져왔습니다.
act_pedit에서 쓰기 가능성을 너무 일찍 계산하면 페이지 캐시 손상이 가능해졌습니다.match u32 0 0peditskb_ensure_writable()echo '' > /dev/udp/127.0.0.1/53)를 전송하여 필터를 트리거합니다. 커널은 tcf_pedit_act()를 호출하고, COW 범위를 할당한 후 키를 반복합니다. 적어도 하나의 키 쓰기가 사전 COW된 영역 밖에 있으므로 쓰기가 공유 페이지 캐시(shared pagecache)로 들어가게 됩니다.sendfile 또는 유사한 방법을 통해 /bin/su를 소켓에 mmap하여 패킷 버퍼가 해당 파일의 페이지를 참조하도록 합니다. 그런 다음 범위를 벗어난 쓰기가 /bin/su의 인메모리 복사본(특히 ELF 진입점)을 손상시킵니다./bin/su)를 실행합니다. 커널이 setgid(0); setuid(0); execve("/bin/sh")를 수행하는 셸코드를 의도치 않게 주입했기 때문에 su를 실행하면 루트 셸이 생성됩니다. 디스크의 파일은 절대 변경되지 않았으므로 온디스크 파일 무결성 도구는 변경 사항을 표시하지 않습니다./proc/[pid]/uid_map