header-logo
Suggest Exploit
vendor:
iOS
by:
Project Zero
7,8
CVSS
HIGH
Heap Buffer Overflow
119
CWE
Product Name: iOS
Affected Version From: N/A
Affected Version To: N/A
Patch Exists: YES
Related CWE: N/A
CPE: N/A
Metasploit: N/A
Other Scripts: N/A
Tags: N/A
CVSS Metrics: N/A
Nuclei References: N/A
Nuclei Metadata: N/A
Platforms Tested: MacOS 10.12.3 (16D32)
2017

Heap Buffer Overflow in TIKeyboardLayout

Using lldb inside a simple hello_world app for iOS, it was discovered that there are over 600 classes which could be deserialized. The TextInput framework which is loaded has a class TIKeyboardLayout. The initWithCoder: implementation has code which reads binary data from the NSCoder, divides the length by 8 and passes that to ensureFrameCapacity which passes it to calloc with an item size of 8. This has the effect of mallocing the original size rounded down to the nearest multiple of 8. The memcpy then uses the original length (not rounded down) causing a controlled heap buffer overflow.

Mitigation:

Ensure that the length of the data being read is properly validated before being passed to the calloc function.
Source

Exploit-DB raw data:

Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1172

Using lldb inside a simple hello_world app for iOS we can see that there are over 600 classes which we could get deserialized
(for persistance for example.)

The TextInput framework which is loaded has a class TIKeyboardLayout. The initWithCoder: implementation has this code:

(this is the x86 code, the framework is there on both platforms.)

  mov     r15, cs:selRef_decodeBytesForKey_returnedLength_
  lea     rdx, cfstr_Frames ; "frames"
  lea     rcx, [rbp+var_40]       <-- length of serialized binary data
  mov     rdi, r14
  mov     rsi, r15
  call    r13 ; _objc_msgSend
  mov     r12, rax                <-- pointer to serialized binary data
  mov     rdx, [rbp+var_40]
  shr     rdx, 3                  <-- divide length by 8
  mov     rax, cs:_OBJC_IVAR_$_TIKeyboardLayout__count ; uint64_t _count;
  mov     [rbx+rax], rdx
  mov     rsi, cs:selRef_ensureFrameCapacity_
  mov     rdi, rbx
  call    r13 ; _objc_msgSend     <-- will calloc(len/8, 8) and assign to _frames
  mov     rax, cs:_OBJC_IVAR_$_TIKeyboardLayout__frames ; struct _ShortRect *_frames;
  mov     rdi, [rbx+rax]  ; void *
  mov     rdx, [rbp+var_40] ; size_t     <-- original length not divided by 8
  mov     rsi, r12        ; void *
  call    _memcpy                        <-- can memcpy up to 7 bytes more than was allocated

This method reads binary data from the NSCoder, it divides the length by 8 and passes that to ensureFrameCapacity
which passes it to calloc with an item size of 8. This has the effect of mallocing the original size rounded down
to the nearest multiple of 8.

The memcpy then uses the original length (not rounded down) causing a controlled heap buffer overflow.

I've created a serialized TIKeyboardLayout with a frames value which is "A"*0x107.

Use ASAN to see the crash clearly (see provided compiler invokation.)

tested on MacOS 10.12.3 (16D32)


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42051.zip