CVE-2017-2372
An exploitable out of bounds write vulnerability exists in the parsing of saved files in Apple’s GarageBand version 10.1.4. A specially crafted project file can cause an out of bounds write resulting in an exploitable condition. An attacker can deliver a project file via other means to trigger this vulnerability.
Apple GarageBand 10.1.4
http://www.apple.com/mac/garageband/
8.8 – CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE-123: Write-what-where Condition
Garageband is a music creation tool used to create new and original music easily from your computer. GarageBand comes installed for free with all new Mac purchases, meaning there is a large market of people who have this software installed on there computer. The file format used by GarageBand is a proprietary .band file. There exists a vulnerability in the parsing of this format. The format is broken into chunks each with a length field at the beginning of the chunk. This length is controllable by the user and no validation checks are done to ensure this length is in bounds thus leading to an exploitable condition.
The initial crash is shown below:
[rax: 0x00000001010f6f01] [rbx: 0x00007fff5fbfdb68] [rcx: 0x000000000000ffff]
[rdx: 0x0000000000000000] [rsi: 0x000000024ce301fe] [rdi: 0x00007fff5fbfdb68]
[rsp: 0x00007fff5fbee230] [rbp: 0x00007fff5fbee250] [ pc: 0x0000000100b4333d]
[ r8: 0x0000000000000002] [ r9: 0x0000000000000000] [r10: 0x000000018e041fa0]
[r11: 0x00007ffd12dbe040] [r12: 0x0000000000000003] [r13: 0x00007fff5fbfdb68]
[r14: 0x000000024e7ad9f8] [r15: 0x0000000100f4571a] [efl: 0x0000000000010202]
stop reason = EXC_BAD_ACCESS (code=1, address=0x24e7bd9f7)
GarageBand`___lldb_unnamed_symbol32314$$GarageBand + 125
GarageBand`___lldb_unnamed_symbol32314$$GarageBand:
-> 0x100b4333d <+125>: mov byte ptr [r14 + rcx], 0x0
0x100b43342 <+130>: test cl, 0x1
0x100b43345 <+133>: je 0x100b4334d ; <+141>
0x100b43347 <+135>: inc ecx
Shown above we can see a null byte being written out of bounds due to an invalid calculation of R14 and RCX. Looking through the current function we can see where these values come from. Starting with R14 it can be seen that this is a buffer on the heap. We run malloc history on it and the output is shown below:
ALLOC 0x25386f990-0x25386ffff [size=1648]: thread_7fff755a2000 openDocumentWithContentsOfURL:display:error:] | 0x10063c300 | -[NSDocumentController makeDocumentWithContentsOfURL:ofType:error:] | -[NSDocument initWithContentsOfURL:ofType:error:] | -[NSDocument _initWithContentsOfURL:ofType:error:] | 0x10057cfff | 0x10057cd55 | 0x1005b5cb1 | 0x100b5fc36 | 0x100b5c2c6 | 0x100b59528 | MAMem::Alloc(unsigned long) | malloc | malloc_zone_malloc
This is a buffer created for holding the data from our opened document. This means that RCX must be an index into this buffer. Looking where RCX comes from we are led a few lines above:
__text:0000000100B4331F lea rsi, [rbp+var_12] [0]
__text:0000000100B43323 mov rdi, rbx
__text:0000000100B43326 call qword ptr [rax+70h] ; 0x100af96d0 [1]
__text:0000000100B43329 mov rax, [rbx]we
__text:0000000100B4332C mov rdi, rbx
__text:0000000100B4332F call qword ptr [rax+90h]
__text:0000000100B43335 movzx ecx, word ptr [rbp+var_12] [2]
At, [2], we can see var_12 being loaded into ECX only a few lines above our vulnerability. looking further we see this same variable, [0], passed in as the second argument to a dynamic function call. Tracing our input further, we follow it into the dynamic call below:
__text:0000000100AF96D0 read_bytes proc near ; DATA XREF: __const:00000001010F6FF0o
__text:0000000100AF96D0 push rbp
__text:0000000100AF96D1 mov rbp, rsp
...
__text:0000000100AF96DA mov r14, rsi [0]
...
__text:0000000100AF9732 mov word ptr [r14], 0
__text:0000000100AF9738 mov rdi, [rbx+10h]
__text:0000000100AF973C mov rsi, [rbx+18h]
__text:0000000100AF9740 mov edx, 2
__text:0000000100AF9745 mov rcx, r14 [1]
__text:0000000100AF9748 call _CFDataGetBytes [2]
As can be seen,[0], our buffer is moved into R14. It is then zeroed out, moved into the 4th argument, [1], for CFDataGetBytes,[2]. This function gets data from a buffer for a range, designated by RSI and EDX, and stores it into RCX. In this case the range it is extracting is 2 bytes. This extracted data is then used in our original calculation above to index into the original data buffer. The problem arises in the fact that the buffer that data being is extracted from, [2], is user controlled and no input validation is done on the bytes read in. This means that RCX is user controlled and can be any arbitrary 2 byte value. This leads to an exploitable null byte write anywhere.
Crashed thread log =
: Dispatch queue: com.apple.main-thread
0 com.apple.garageband10 0x000000010735d33d 0x10681a000 + 11809597
1 com.apple.garageband10 0x000000010735d24a 0x10681a000 + 11809354
2 com.apple.garageband10 0x0000000107373574 0x10681a000 + 11900276
3 com.apple.garageband10 0x00000001073762c6 0x10681a000 + 11911878
4 com.apple.garageband10 0x0000000107379c36 0x10681a000 + 11926582
5 com.apple.garageband10 0x0000000106dcfcb1 0x10681a000 + 5987505
6 com.apple.garageband10 0x0000000106d96d55 0x10681a000 + 5754197
7 com.apple.garageband10 0x0000000106d96fff 0x10681a000 + 5754879
8 com.apple.AppKit 0x00007fff8bf11b5a -[NSDocument _initWithContentsOfURL:ofType:error:] + 171
9 com.apple.AppKit 0x00007fff8bf11a46 -[NSDocument initWithContentsOfURL:ofType:error:] + 230
10 com.apple.AppKit 0x00007fff8bffd6c2 -[NSDocumentController makeDocumentWithContentsOfURL:ofType:error:] + 627
11 com.apple.garageband10 0x0000000106e56300 0x10681a000 + 6537984
12 com.apple.AppKit 0x00007fff8c23dedf -[NSDocumentController(NSDeprecated) openDocumentWithContentsOfURL:display:error:] + 798
13 com.apple.garageband10 0x0000000106dc2b5b 0x10681a000 + 5933915
...
36 libdyld.dylib 0x00007fff82b345ad start + 1
log name is: ./crashlogs/5.crashlog.txt
---
exception=EXC_BAD_ACCESS:signal=11:is_exploitable=yes:instruction_disassembly=movb $CONSTANT,(%r14,%rcx):instruction_address=0x000000010735d33d:access_type=write:access_address=0x0000000254b5d9f7:
2016-12-15 - Vendor Disclosure
2017-02-14 - Public Release
Discovered by Tyler Bohan of Cisco Talos.