NGS00062 Technical Advisory: Apple OSX / iPhone ImageIO TIFF getBandProcTIFF TileWidth Heap Overflow

2011-10-16T00:00:00
ID SECURITYVULNS:DOC:27160
Type securityvulns
Reporter Securityvulns
Modified 2011-10-16T00:00:00

Description

======= Summary ======= Name: Apple OSX / iPhone iOS ImageIO TIFF getBandProcTIFF TileWidth Heap Overflow Reference: NGS00062 Discoverer: Dominic Chell <dominic.chell@ngssecure.com> Vendor: Apple Vendor Reference: 145575681 Systems Affected: Apple OSX / iPhone iOS / Possibly others using LibTiff Risk: High Status: Fixed

======== TimeLine ======== Discovered: 27 February 2011 Released: 27 February 2011 Approved: 29 March 2011 Reported: 29 March 2011 Fixed: 23 June 2011 Published: 10 October 2011

=========== Description =========== Heap overflow caused by overly large tilewidth image tag in getBandProcTiff()

================= Technical Details ================= The Offset 8BE6 is changed from 17 to 42. This field is the tiff tag StripByteCounts. Valid value is 1701 which signifies the StripByteCounts tiff tag Flipping the stripbytescount field to 4201 causes the

stripbytescount tag to be removed for the first page in the tiff image and be replaced with the tilewidth image tag. The definition of this image tag can be found here: http://www.awaresystems.be/imaging/tiff/tifftags/tilewidth.html

The value for the tilewidth tag is read from 8BEE to 8BF1 inclusive. Setting the tilewidth to 00800000 (8388608) causes the following crash:

Program received signal EXC_BAD_ACCESS, Could not access memory. Reason: KERN_INVALID_ADDRESS at address: 0x00000001007ca000 [Switching to process 2342] 0x00007fffffe00847 in __memcpy () (gdb) i r rax 0xffffffffeb790000 -344391680 rbx 0x10078c000 4302880768 rcx 0xfffffffffff3e000 -794624 rdx 0x0 0 rsi 0x1150fc000 4648321024 rdi 0x10088c000 4303929344 rbp 0x102ed7790 0x102ed7790 rsp 0x102ed7790 0x102ed7790 r8 0x15dafbfff 5866766335 r9 0x7 7 r10 0x10340ddf0 4349550064 r11 0x10078c000 4302880768 r12 0x1 1 r13 0x100000 1048576 r14 0x0 0 r15 0x0 0 rip 0x7fffffe00847 0x7fffffe00847 <__memcpy+167> eflags 0x10286 66182 cs 0x27 39 ss 0x0 0 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (gdb) x/i $rip 0x7fffffe00847 <__memcpy+167>: movdqa XMMWORD PTR [rdi+rcx],xmm0 (gdb)

Reducing the tilewidth to 0000FF00 or 65280 we get a different crash:

Program received signal EXC_BAD_ACCESS, Could not access memory. Reason: KERN_INVALID_ADDRESS at address: 0x00000001007c7000 [Switching to process 2379] 0x00007fffffe007c5 in __memcpy () (gdb) i r rax 0xffffffff 4294967295 rbx 0x1007c5030 4303114288 rcx 0x4 4 rdx 0x20 32 rsi 0x1159c4194 4657529236 rdi 0x1007c7000 4303122432 rbp 0x10067d790 0x10067d790 rsp 0x10067d790 0x10067d790 r8 0x1159f3e9f 4657725087 r9 0x7 7 r10 0x100122cc0 4296158400 r11 0x1007c5030 4303114288 r12 0x473 1139 r13 0x1fe0 8160 r14 0x0 0 r15 0x0 0 rip 0x7fffffe007c5 0x7fffffe007c5 <__memcpy+37> eflags 0x10202 66050 cs 0x27 39 ss 0x0 0 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (gdb) x/i $rip 0x7fffffe007c5 <__memcpy+37>: mov DWORD PTR [rdi],eax (gdb) (gdb) bt

0 0x00007fffffe007c5 in __memcpy ()

1 0x00007fff80f766ef in getBandProcTIFF ()

Disassembly of function: Breakpoint here:

0x00007fff80f765a4 <getBandProcTIFF+284>: call 0x7fff8104cade<dyld_stub__cg_TIFFGetField>

Function reads the value of the TileWidth, arguments:

rsi 0x142 322

esi contains the tiff image tag for tile width that this function extracts the value for, in this instance its 322 which is TileWidth.

0x00007fff80f765a9 <getBandProcTIFF+289>: lea rdx,[rbp-0x38] 0x00007fff80f765ad <getBandProcTIFF+293>: mov rax,QWORD PTR [rbp-0x4d8] 0x00007fff80f765b4 <getBandProcTIFF+300>: mov rdi,QWORD PTR [rax+0x38] 0x00007fff80f765b8 <getBandProcTIFF+304>: mov esi,0x143 0x00007fff80f765bd <getBandProcTIFF+309>: xor eax,eax 0x00007fff80f765bf <getBandProcTIFF+311>: call 0x7fff8104cade<dyld_stub__cg_TIFFGetField>// read tilelength field 0x00007fff80f765c4 <getBandProcTIFF+316>: mov edx,DWORD PTR [rbp-0x38] 0x00007fff80f765c7 <getBandProcTIFF+319>: mov rax,rbx 0x00007fff80f765ca <getBandProcTIFF+322>: mov rcx,rdx 0x00007fff80f765cd <getBandProcTIFF+325>: xor edx,edx 0x00007fff80f765cf <getBandProcTIFF+327>: div rcx 0x00007fff80f765d2 <getBandProcTIFF+330>: mov QWORD PTR [rbp-0x510],rax 0x00007fff80f765d9 <getBandProcTIFF+337>: xor r14d,r14d 0x00007fff80f765dc <getBandProcTIFF+340>: jmp 0x7fff80f76720<getBandProcTIFF+664> 0x00007fff80f765e1 <getBandProcTIFF+345>: mov rbx,QWORD PTR [rbp-0x4d8] 0x00007fff80f765e8 <getBandProcTIFF+352>: mov rdx,QWORD PTR [rbx+0x8] 0x00007fff80f765ec <getBandProcTIFF+356>: lea rax,[r14+0x1] 0x00007fff80f765f0 <getBandProcTIFF+360>: mov QWORD PTR [rbp-0x468],rax 0x00007fff80f765f7 <getBandProcTIFF+367>: imul rax,rdx 0x00007fff80f765fb <getBandProcTIFF+371>: mov QWORD PTR [rbp-0x4b0],rdx 0x00007fff80f76602 <getBandProcTIFF+378>: cmp QWORD PTR [rbp-0x4e8],rax 0x00007fff80f76609 <getBandProcTIFF+385>: jae 0x7fff80f76623<getBandProcTIFF+411> 0x00007fff80f7660b <getBandProcTIFF+387>: mov rax,r14 0x00007fff80f7660e <getBandProcTIFF+390>: imul rax,rdx 0x00007fff80f76612 <getBandProcTIFF+394>: mov rcx,QWORD PTR [rbp-0x4e8] 0x00007fff80f76619 <getBandProcTIFF+401>: sub rcx,rax 0x00007fff80f7661c <getBandProcTIFF+404>: mov QWORD PTR [rbp-0x4b0],rcx 0x00007fff80f76623 <getBandProcTIFF+411>: mov rax,QWORD PTR [rbp-0x4f0] 0x00007fff80f7662a <getBandProcTIFF+418>: imul rax,rdx 0x00007fff80f7662e <getBandProcTIFF+422>: imul rax,r14 0x00007fff80f76632 <getBandProcTIFF+426>: add rax,QWORD PTR [rbp-0x4f8] 0x00007fff80f76639 <getBandProcTIFF+433>: mov QWORD PTR [rbp-0x4b8],rax 0x00007fff80f76640 <getBandProcTIFF+440>: xor r15d,r15d 0x00007fff80f76643 <getBandProcTIFF+443>: jmp 0x7fff80f76709<getBandProcTIFF+641> 0x00007fff80f76648 <getBandProcTIFF+448>: mov rcx,r14 0x00007fff80f7664b <getBandProcTIFF+451>: mov rax,QWORD PTR [rbp-0x4d8] 0x00007fff80f76652 <getBandProcTIFF+458>: imul rcx,QWORD PTR [rax+0x8] 0x00007fff80f76657 <getBandProcTIFF+463>: mov rdi,QWORD PTR [rax+0x38] 0x00007fff80f7665b <getBandProcTIFF+467>: xor r9d,r9d 0x00007fff80f7665e <getBandProcTIFF+470>: xor r8d,r8d 0x00007fff80f76661 <getBandProcTIFF+473>: mov edx,r15d 0x00007fff80f76664 <getBandProcTIFF+476>: mov rsi,QWORD PTR [rbp-0x508] 0x00007fff80f7666b <getBandProcTIFF+483>: call 0x7fff8104cb08<dyld_stub__cg_TIFFReadTile> 0x00007fff80f76670 <getBandProcTIFF+488>: inc eax 0x00007fff80f76672 <getBandProcTIFF+490>: jne 0x7fff80f76680<getBandProcTIFF+504> 0x00007fff80f76674 <getBandProcTIFF+492>: mov rdi,QWORD PTR [rbp-0x508] 0x00007fff80f7667b <getBandProcTIFF+499>: jmp 0x7fff80f76917<getBandProcTIFF+1167> 0x00007fff80f76680 <getBandProcTIFF+504>: mov eax,r15d 0x00007fff80f76683 <getBandProcTIFF+507>: add eax,DWORD PTR [rbp-0x38] 0x00007fff80f76686 <getBandProcTIFF+510>: cmp QWORD PTR [rbp-0x4e0],rax 0x00007fff80f7668d <getBandProcTIFF+517>: jae 0x7fff80f7669b<getBandProcTIFF+531> 0x00007fff80f7668f <getBandProcTIFF+519>: mov rdx,QWORD PTR [rbp-0x4e0] 0x00007fff80f76696 <getBandProcTIFF+526>: sub rdx,rbx 0x00007fff80f76699 <getBandProcTIFF+529>: jmp 0x7fff80f7669e<getBandProcTIFF+534> 0x00007fff80f7669b <getBandProcTIFF+531>: mov edx,DWORD PTR [rbp-0x34] 0x00007fff80f7669e <getBandProcTIFF+534>: mov rcx,QWORD PTR [rbp-0x4d8] 0x00007fff80f766a5 <getBandProcTIFF+541>: mov rax,QWORD PTR [rcx+0x18] 0x00007fff80f766a9 <getBandProcTIFF+545>: imul rdx,rax 0x00007fff80f766ad <getBandProcTIFF+549>: lea r13,[rdx+0x7] 0x00007fff80f766b1 <getBandProcTIFF+553>: shr r13,0x3 0x00007fff80f766b5 <getBandProcTIFF+557>: imul rbx,rax 0x00007fff80f766b9 <getBandProcTIFF+561>: lea rax,[rbx+0x7] 0x00007fff80f766bd <getBandProcTIFF+565>: shr rax,0x3 0x00007fff80f766c1 <getBandProcTIFF+569>: mov rdx,QWORD PTR [rbp-0x4b8] 0x00007fff80f766c8 <getBandProcTIFF+576>: lea rbx,[rax+rdx] 0x00007fff80f766cc <getBandProcTIFF+580>: xor r12d,r12d

// loops copying from a ptr in to a buffer

0x00007fff80f766cf <getBandProcTIFF+583>: jmp 0x7fff80f766f6<getBandProcTIFF+622> 0x00007fff80f766d1 <getBandProcTIFF+585>: imul rax,QWORD PTR [rbp-0x510] 0x00007fff80f766d9 <getBandProcTIFF+593>: mov rcx,QWORD PTR [rbp-0x508] 0x00007fff80f766e0 <getBandProcTIFF+600>: lea rsi,[rax+rcx] 0x00007fff80f766e4 <getBandProcTIFF+604>: mov rdx,r13 0x00007fff80f766e7 <getBandProcTIFF+607>: mov rdi,rbx 0x00007fff80f766ea <getBandProcTIFF+610>: call 0x7fff8104cdb4 <dyld_stub_memcpy>//crash in memcpy 0x00007fff80f766ef <getBandProcTIFF+615>: add rbx,QWORD PTR [rbp-0x4f0] 0x00007fff80f766f6 <getBandProcTIFF+622>: mov eax,r12d 0x00007fff80f766f9 <getBandProcTIFF+625>: inc r12 0x00007fff80f766fc <getBandProcTIFF+628>: cmp QWORD PTR [rbp-0x4b0],rax 0x00007fff80f76703 <getBandProcTIFF+635>: ja 0x7fff80f766d1<getBandProcTIFF+585> 0x00007fff80f76705 <getBandProcTIFF+637>: add r15d,DWORD PTR [rbp-0x34] 0x00007fff80f76709 <getBandProcTIFF+641>: mov ebx,r15d 0x00007fff80f7670c <getBandProcTIFF+644>: cmp rbx,QWORD PTR [rbp-0x4e0] 0x00007fff80f76713 <getBandProcTIFF+651>: jb 0x7fff80f76648<getBandProcTIFF+448> 0x00007fff80f76719 <getBandProcTIFF+657>: mov r14,QWORD PTR [rbp-0x468] 0x00007fff80f76720 <getBandProcTIFF+664>: cmp r14,QWORD PTR [rbp-0x500] 0x00007fff80f76727 <getBandProcTIFF+671>: jne 0x7fff80f765e1<getBandProcTIFF+345> 0x00007fff80f7672d <getBandProcTIFF+677>: mov rdi,QWORD PTR [rbp-0x508] 0x00007fff80f76734 <getBandProcTIFF+684>: jmp 0x7fff80f76d2d<getBandProcTIFF+2213> 0x00007fff80f76739 <getBandProcTIFF+689>: mov rax,QWORD PTR [rbp-0x4d8] 0x00007fff80f76740 <getBandProcTIFF+696>: cmp BYTE PTR [rax+0x45],0x0 0x00007fff80f76744 <getBandProcTIFF+700>: je 0x7fff80f76d37<getBandProcTIFF+2223> 0x00007fff80f7674a <getBandProcTIFF+706>: mov r13,QWORD PTR [rax+0x10]

It appears as the tileWidth controls the size of the iterator in a previous loop. In turn we can control the number of times the memcpy() is called and the amount of buffer copied.

For example, tileWidth = FF00:

Breakpoint 6, 0x00007fff80f766ea in getBandProcTIFF () r12 0x473 1139 0x7fff80f766ea <getBandProcTIFF+610>: call 0x7fff8104cdb4<dyld_stub_memcpy>

The number of iterations is stored in the $r12 register.

Decreasing the tileWidth causes the loop to iterate more, tileWidth=DD00 because the value incremented is lower:

r12 0x478 1144

When we use a large value such as, 00800000 (8388608) we only call memcpy() once:

r12 0x1 1 (gdb) x/i $rip 0x7fffffe00847 <__memcpy+167>: movdqa XMMWORD PTR [rdi+rcx],xmm0 (gdb)

I believe this triggers the integer overflow and in turn an overflow in the memcpy.

=============== Fix Information ===============

Apple has released a patch that addresses the issue. The announcement of the patch can be found here:

http://support.apple.com/kb/HT4723

NGS Secure Research http://www.ngssecure.com