ReversingLabs

How to defend ARM64 cloud infrastructure from ITScape

ITScape (CVE-2026-46316) is a guest-to-host escape vulnerability in the vGIC-ITS (Interrupt Translation Service) emulation within KVM/arm64, disclosed by researcher Hyunwoo Kim (V4bel) via oss-security on June 10. The root cause is a race condition in the vgic_its_invalidate_cache() function that produces a double-put use-after-free, ultimately enabling host kernel code execution. 

Because the bug lives entirely within in-kernel KVM rather than QEMU user-space, successful exploitation yields host kernel privilege rather than user-process compromise, making it a direct threat to multi-tenant arm64 cloud environments that accept untrusted guests.

In scenarios where the attacker lacks guest root, ITScape can be chained with a local privilege escalation. The vulnerability affects kernels from commit 8201d1028caa (2024-04-25) through 13031fb6b835 (2026-06-05), at which point the patch landed in mainline.

Here’s what you need to know about ITScape — including recommendations for discovery, how to detect exploits with YARA rules, and Indicators of Compromise (IoCs). 

YARA detection

Two YARA rules have been developed to detect this threat. ITScape_ExploitConstants_1 targets nine hardcoded 64-bit constants present in the PoC source: kernel symbol addresses (ORDERLY_POWEROFF, POWEROFF_CMD, NEIGH_GC_WORK_FUNC, PMU_FN_LINKED, gadget_rt), an anti-leak sentinel (LEAKLEAD), and the three packed u64 values that compose the /bin/touch /ITScape host command string. All constants are encoded little-endian as they appear in a compiled ARM64 ELF. 

Testing against the known PoC binary confirms seven of nine strings match; $pmu_fn_linked and $gadget_rt are absent from this build, most likely because gadget_rt is only ever materialized at runtime as base + voff and the linker does not emit either constant as a bare relocatable literal in this particular build. Both strings are retained in the rule defensively: a statically linked build, a differently optimized build, or a future variant may resolve these constants differently and produce hits where the known sample does not. The constants as found in the poc.c source code are shown in the figures below.

Figure 1: First set of constants defined in the exploit poc.c

Figure 2: Second set of constants

ITScape_KVM_PrivDrop_1 takes a behavioral approach, targeting a semantically unique instruction sequence in the compiled binary: a stat(2) group permission check (st_mode & 0x6 == 0x6) on /dev/kvm followed immediately by setgroups(0, NULL) / setgid(1000) / setuid(1000) with error-checked cbnz branches after each call. Branch offsets and stack frame offsets are wildcarded at the byte and nibble level using ARM64 instruction encoding semantics, making the pattern robust to recompilation while keeping all semantically meaningful immediates as exact matches. The region of disassembled code detected by this rule is shown in the next figure.

Figure 3: Privilege drop on /dev/kvm

Recommendations

Defenders running arm64 KVM hosts should prioritize applying the mainline patch at commit 13031fb6b835 and the two companion fixes for CVE-2026-46316. Organizations operating multi-tenant arm64 infrastructure, particularly public cloud providers, should closely evaluate this issue given that exploitation requires only guest kernel privilege and yields host root. Since this represents a new vulnerability class, additional variants and follow-up vulnerabilities are expected, so continued monitoring of the vgic-its code path is warranted even after patching.

IoCs

PoC SHA256

e0ab84da2d2783c8cae3624e8ce58b99ad79219753b249671ff7f743abdacc35

YARA Rules

rule ITScape_ExploitConstants_1
{
    meta:
        author = "Malware Utkonos"
        date = "2026-05-11"
        description = "Detects constants used in ITScape exploit PoC."
        reference = "https://github.com/V4bel/ITScape/blob/main/poc.c"
        poc = "e0ab84da2d2783c8cae3624e8ce58b99ad79219753b249671ff7f743abdacc35"
    strings:
        $orderly_poweroff   = { 2cf90d800080ffff }
        $poweroff_cmd       = { c803d0820080ffff }
        $neigh_gc_work_func = { 502d1d830080ffff }
        $pmu_fn_linked      = { b80e09800080ffff }
        $gadget_rt          = { dcc6d7800080ffff }

        // canary magic ("LEAKLEAD" = 0x4c45414b4c454144 byte-swapped)
        $leak_sentinel      = { 4441454c4b41454c }

        // payload: "/bin/touch /ITScape" packed as three u64s
        $sc_write_bin_tou   = { 2f62696e2f746f75 }  // /bin/tou
        $sc_write_ch_ITSc   = { 6368202f49545363 }  // ch /ITSc
        $sc_write_ape       = { 6170650000000000 }  // ape\0
    condition:
        5 of them
}

rule ITScape_KVM_PrivDrop_1
{
    meta:
        author = "Malware Utkonos"
        date = "2026-05-11"
        description = "Detects /dev/kvm group rw check and drop to setgroups/setgid/setuid(1000) used in ITScape PoC."
        reference = "https://github.com/V4bel/ITScape/blob/main/poc.c"
        poc = "e0ab84da2d2783c8cae3624e8ce58b99ad79219753b249671ff7f743abdacc35"
    strings:
        $kvm = "/dev/kvm"

        $op = { e0??4?b9 00041f12 1f180071 ?1[2]54 010080d2 000080d2 [3]9? 007d8052 [3]9? ?0[2]35 007d8052 [3]9? ?0[2]35 }
            // 004025cc  e0c340b9   ldr     w0, [sp, #0xc0 {guest_memfd.reserved[0].d}]  // load stat st_mode; offset floats
            // 004025d0  00041f12   and     w0, w0, #0x6                                 // mask S_IRGRP|S_IWGRP (0x4|0x2)
            // 004025d4  1f180071   cmp     w0, #0x6                                     // both group rw bits must be set
            // 004025d8  c1f0ff54   b.ne    0x4023f0
            // 004025dc  010080d2   mov     x1, #0                                       // setgroups(0, NULL)
            // 004025e0  000080d2   mov     x0, #0
            // 004025e4  b3feff97   bl      setgroups
            // 004025e8  007d8052   mov     w0, #0x3e8                                   // setgid(1000)
            // 004025ec  71feff97   bl      setgid
            // 004025f0  00f0ff35   cbnz    w0, 0x4023f0
            // 004025f4  007d8052   mov     w0, #0x3e8                                   // setuid(1000)
            // 004025f8  a6fdff97   bl      setuid
            // 004025fc  a0efff35   cbnz    w0, 0x4023f0

    condition:
        $kvm and $op
}

This post was assembled with assistance from generative AI.

Leave a Reply