[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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

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

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

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:

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

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) 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

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:


NGS Secure Research