( Hunger | 2012. 06. 13., sze – 16:46 )

Details from the reporter, Rafal Wojtczuk

Attack steps (done by ring3 attacker)

  1. Map a frame at virtual address
    (1<<47)-4096
  2. Any method to set the target of
    sysret

    to a non-canonical address can potentially be used. This includes

    ptrace

    ,

    sys_sigreturn

    ,

    sigaction

    ,

    execve

    , possibly others. The best solution is to add a check for the address being non-canonical close before executing

    sysret

    . Note if the

    syscall

    handler ends with

    iret

    , then even if

    iret

    throws

    #GP

    ,

    rsp

    is not controlled by the attacker, and such the situation can be handled safely.

  3. Place a
    syscall

    instruction at address

    (1<<47)-2
  4. Place SOMETHING_MALICIOUS in general purpose registers
  5. Set
    rsp

    to AROUND_SOME_IMPORTANT_RING0_STRUCTURE

  6. Other scenarios are possible. Whenever the
    #GP

    handler runs with usermode

    rsp

    , or does not do

    swapgs

    correctly, code execution may be possible.

  7. Jump to
    syscall

    instruction at

    (1<<47)-2

At the

syscall

handler entry,

rcx

will be set to

(1<<47)-2+instruction_len(syscall) = 1<<47

, which is non-canonical. Therefore, when the

syscall

handler terminates with

sysret

,

#GP 

will be raised. This fault will be handled without a stack switch (assuming

#GP

entry in

IDT

does not include a nonzero IST index), as the faulting instruction is in ring0. Only Intel CPUs are affected. On AMD CPUs,

sysret

completes the switch to ring3 before throwing

#GP

, so the stack switch occurs. Also, immediately before

sysret

, the

syscall

handler must restore

rsp

to the value set by ring3 (because

syscall/sysret

do not set

rsp

). Therefore, the

#GP

handler will execute with

rsp

chosen by the attacker, so when

GPRs

are pushed on the stack in the

#GP

handler prologue, SOMETHING_MALICIOUS will be placed at AROUND_SOME_IMPORTANT_RING0_STRUCTURE. This write-anything-anywhere primitive could be enough to hijack execution in ring0. Additionally, in many cases,

gs

base is not swapped in the

#GP

prologue (as the fault originates in ring0), which may make the exploitation quite reliable and stable - overwrite

#PF IDT

entry via stack push, trigger

#PF

by

gs

access, repair IDT (from IDT table of other cpu) in the shellcode, return to usermode.

(azért másoltam be ide, mert a CERT eltávolította az oldaláról időközben ezt a leírást... ;)