OS X Mavericks 10.9.5 – out of bound read/write in memmove()

Posted by Ajin Abraham on Sep 9 2015

TL;DR

Running cat command on a malformed file in OSX Maverick's Terminal.app results in crash. This post explains the crash analysis. Code execution was not achieved due to limited buffer.

While Fuzzing the Android's installd daemon, accidentally I did a cat on the fuzzer generated APK and OS X Mavericks's Terminal.app crashed. Shown below is the crash report.

So I thought to investigate further on this.

Register Dump


(lldb) register read

General Purpose Registers:
rax = 0x000000010c15b264
rbx = 0x0000000100457690
rcx = 0x0000000000000003
rdx = 0xfffffffffffa4d7c
rdi = 0x000000010c100020
rsi = 0x000000010c100018
rbp = 0x00007fff5fbfdc10
rsp = 0x00007fff5fbfdc10
r8 = 0x0000000000000000
r9 = 0x0000000000000009
r10 = 0x0000000101046880
r11 = 0x000000010c15b263
r12 = 0x0000000000000001
r13 = 0x0000000000000008
r14 = 0x0000000000000008
r15 = 0x000000000000000c
rip = 0x00007fff8bbced10  libsystem_platform.dylib`_platform_memmove$VARIANT$Unknown + 528
rflags = 0x0000000000010202
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x000000000c150000

Stack Trace


* thread #1: tid = 0x4bd5, 0x00007fff8bbced10 libsystem_platform.dylib`_platform_memmove$VARIANT$Unknown + 528, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x10c0ffff8)
* frame #0: 0x00007fff8bbced10 libsystem_plaform.dylib`_platform_memmove$VARIANT$Unknown + 528
frame #1: 0x000000010002945d Terminal`___lldb_unnamed_function445$$Terminal + 96
frame #2: 0x00000001000293ca Terminal`___lldb_unnamed_function444$$Terminal + 632
frame #3: 0x000000010002876a Terminal`___lldb_unnamed_function438$$Terminal + 265
frame #4: 0x00000001000272dd Terminal`___lldb_unnamed_function433$$Terminal + 16104
frame #5: 0x0000000100023075 Terminal`___lldb_unnamed_function429$$Terminal + 114
frame #6: 0x0000000100022c5e Terminal`___lldb_unnamed_function426$$Terminal + 449
frame #7: 0x00007fff8e76075e Foundation`__NSThreadPerformPerform + 229
frame #8: 0x00007fff8982a5b1 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
frame #9: 0x00007fff8981bc62 CoreFoundation`__CFRunLoopDoSources0 + 242
frame #10: 0x00007fff8981b3ef CoreFoundation`__CFRunLoopRun + 831
frame #11: 0x00007fff8981ae75 CoreFoundation`CFRunLoopRunSpecific + 309
frame #12: 0x00007fff8bdf0a0d HIToolbox`RunCurrentEventLoopInMode + 226
frame #13: 0x00007fff8bdf07b7 HIToolbox`ReceiveNextEventCommon + 479
frame #14: 0x00007fff8bdf05bc HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 65
frame #15: 0x00007fff8cc4f24e AppKit`_DPSNextEvent + 1434
frame #16: 0x00007fff8cc4e89b AppKit`-[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 122
frame #17: 0x00007fff8cc4299c AppKit`-[NSApplication run] + 553
frame #18: 0x00007fff8cc2d783 AppKit`NSApplicationMain + 940
frame #19: 0x00007fff874fa5fd libdyld.dylib`start + 1
frame #20: 0x00007fff874fa5fd libdyld.dylib`start + 1
(lldb)

Disassembly


(lldb) di
libsystem_platform.dylib`_platform_memmove$VARIANT$Unknown:
   0x7fff8bbceb00:  push   rbp
   0x7fff8bbceb01:  mov    rbp, rsp
   0x7fff8bbceb04:  mov    r11, rdi
   0x7fff8bbceb07:  sub    r11, rsi
   0x7fff8bbceb0a:  mov    rax, rdi
   0x7fff8bbceb0d:  cmp    r11, rdx
   0x7fff8bbceb10:  jb     0x7fff8bbceb2d            ; _platform_memmove$VARIANT$Unknown + 45
   0x7fff8bbceb12:  cmp    rdx, 0x60
   0x7fff8bbceb16:  jbe    0x7fff8bbceb47            ; _platform_memmove$VARIANT$Unknown + 71
   0x7fff8bbceb18:  cmp    rdx, 0x20000
   0x7fff8bbceb1f:  jb     0x7fff8bbcebe0            ; _platform_memmove$VARIANT$Unknown + 224
   0x7fff8bbceb25:  mov    rcx, rdx
   0x7fff8bbceb28:  cld    
   0x7fff8bbceb29:  rep    
   0x7fff8bbceb2a:  movsb  
   0x7fff8bbceb2b:  pop    rbp
   0x7fff8bbceb2c:  ret    
   0x7fff8bbceb2d:  cmp    rsi, rdi
   0x7fff8bbceb30:  je     0x7fff8bbceb2b            ; _platform_memmove$VARIANT$Unknown + 43
   0x7fff8bbceb32:  add    rsi, rdx
   0x7fff8bbceb35:  add    rdi, rdx
   0x7fff8bbceb38:  cmp    rdx, 0x60
   0x7fff8bbceb3c:  jb     0x7fff8bbcec9e            ; _platform_memmove$VARIANT$Unknown + 414
   0x7fff8bbceb42:  jmp    0x7fff8bbcecc0            ; _platform_memmove$VARIANT$Unknown + 448
   0x7fff8bbceb47:  cmp    rdx, 0x10
   0x7fff8bbceb4b:  jbe    0x7fff8bbceb97            ; _platform_memmove$VARIANT$Unknown + 151
   0x7fff8bbceb4d:  movups xmm4, xmmword ptr [rsi + rdx - 0x10]
   0x7fff8bbceb52:  sub    rdx, 0x20
   0x7fff8bbceb56:  jbe    0x7fff8bbceb85            ; _platform_memmove$VARIANT$Unknown + 133
   0x7fff8bbceb58:  vmovups ymm1, ymmword ptr [rsi]
   0x7fff8bbceb5c:  vmovups ymmword ptr [rdi], ymm1
   0x7fff8bbceb60:  add    rsi, 0x20
   0x7fff8bbceb64:  add    rdi, 0x20
   0x7fff8bbceb68:  sub    rdx, 0x20
   0x7fff8bbceb6c:  jb     0x7fff8bbceb82            ; _platform_memmove$VARIANT$Unknown + 130
   0x7fff8bbceb6e:  vmovups ymm2, ymmword ptr [rsi]
   0x7fff8bbceb72:  vmovups ymmword ptr [rdi], ymm2
   0x7fff8bbceb76:  add    rsi, 0x20
   0x7fff8bbceb7a:  add    rdi, 0x20
   0x7fff8bbceb7e:  sub    rdx, 0x20
   0x7fff8bbceb82:  vzeroupper 
   0x7fff8bbceb85:  add    rdx, 0x10
   0x7fff8bbceb89:  jle    0x7fff8bbceb91            ; _platform_memmove$VARIANT$Unknown + 145
   0x7fff8bbceb8b:  movups xmm3, xmmword ptr [rsi]
   0x7fff8bbceb8e:  movups xmmword ptr [rdi], xmm3
   0x7fff8bbceb91:  movups xmmword ptr [rdi + rdx], xmm4
   0x7fff8bbceb95:  pop    rbp
   0x7fff8bbceb96:  ret    
   0x7fff8bbceb97:  sub    rdx, 0x8
   0x7fff8bbceb9b:  jb     0x7fff8bbcebad            ; _platform_memmove$VARIANT$Unknown + 173
   0x7fff8bbceb9d:  mov    rcx, qword ptr [rsi]
   0x7fff8bbceba0:  mov    r8, qword ptr [rsi + rdx]
   0x7fff8bbceba4:  mov    qword ptr [rdi], rcx
   0x7fff8bbceba7:  mov    qword ptr [rdi + rdx], r8
   0x7fff8bbcebab:  pop    rbp
   0x7fff8bbcebac:  ret    
   0x7fff8bbcebad:  add    rdx, 0x8
   0x7fff8bbcebb1:  je     0x7fff8bbcebd8            ; _platform_memmove$VARIANT$Unknown + 216
   0x7fff8bbcebb3:  xor    r8, r8
   0x7fff8bbcebb6:  mov    cl, byte ptr [rsi + r8]
   0x7fff8bbcebba:  mov    byte ptr [rdi + r8], cl
   0x7fff8bbcebbe:  sub    rdx, 0x1
   0x7fff8bbcebc2:  je     0x7fff8bbcebd8            ; _platform_memmove$VARIANT$Unknown + 216
   0x7fff8bbcebc4:  mov    cl, byte ptr [rsi + r8 + 0x1]
   0x7fff8bbcebc9:  mov    byte ptr [rdi + r8 + 0x1], cl
   0x7fff8bbcebce:  add    r8, 0x2
   0x7fff8bbcebd2:  sub    rdx, 0x1
   0x7fff8bbcebd6:  jne    0x7fff8bbcebb6            ; _platform_memmove$VARIANT$Unknown + 182
   0x7fff8bbcebd8:  pop    rbp
   0x7fff8bbcebd9:  ret    
   0x7fff8bbcebda:  nop    word ptr [rax + rax]
   0x7fff8bbcebe0:  vmovups ymm0, ymmword ptr [rsi]
   0x7fff8bbcebe4:  add    rdi, 0x20
   0x7fff8bbcebe8:  and    rdi, -0x20
   0x7fff8bbcebec:  mov    rcx, rdi
   0x7fff8bbcebef:  sub    rcx, rax
   0x7fff8bbcebf2:  add    rsi, rcx
   0x7fff8bbcebf5:  sub    rdx, rcx
   0x7fff8bbcebf8:  vmovups ymm1, ymmword ptr [rsi]
   0x7fff8bbcebfc:  vmovups ymmword ptr [rax], ymm0
   0x7fff8bbcec00:  vmovups ymm2, ymmword ptr [rsi + 0x20]
   0x7fff8bbcec05:  add    rsi, 0x40
   0x7fff8bbcec09:  sub    rdx, 0x80
   0x7fff8bbcec10:  jbe    0x7fff8bbcec60            ; _platform_memmove$VARIANT$Unknown + 352
   0x7fff8bbcec12:  test   rsi, 0x1f
   0x7fff8bbcec19:  je     0x7fff8bbcec40            ; _platform_memmove$VARIANT$Unknown + 320
   0x7fff8bbcec1b:  vmovaps ymmword ptr [rdi], ymm1
   0x7fff8bbcec1f:  vmovaps ymmword ptr [rdi + 0x20], ymm2
   0x7fff8bbcec24:  add    rdi, 0x40
   0x7fff8bbcec28:  vmovups ymm1, ymmword ptr [rsi]
   0x7fff8bbcec2c:  vmovups ymm2, ymmword ptr [rsi + 0x20]
   0x7fff8bbcec31:  add    rsi, 0x40
   0x7fff8bbcec35:  sub    rdx, 0x40
   0x7fff8bbcec39:  ja     0x7fff8bbcec1b            ; _platform_memmove$VARIANT$Unknown + 283
   0x7fff8bbcec3b:  jmp    0x7fff8bbcec60            ; _platform_memmove$VARIANT$Unknown + 352
   0x7fff8bbcec3d:  nop    dword ptr [rax]
   0x7fff8bbcec40:  vmovaps ymmword ptr [rdi], ymm1
   0x7fff8bbcec44:  vmovaps ymmword ptr [rdi + 0x20], ymm2
   0x7fff8bbcec49:  add    rdi, 0x40
   0x7fff8bbcec4d:  vmovaps ymm1, ymmword ptr [rsi]
   0x7fff8bbcec51:  vmovaps ymm2, ymmword ptr [rsi + 0x20]
   0x7fff8bbcec56:  add    rsi, 0x40
   0x7fff8bbcec5a:  sub    rdx, 0x40
   0x7fff8bbcec5e:  ja     0x7fff8bbcec40            ; _platform_memmove$VARIANT$Unknown + 320
   0x7fff8bbcec60:  vmovups ymm3, ymmword ptr [rsi + rdx]
   0x7fff8bbcec65:  vmovups ymm4, ymmword ptr [rsi + rdx + 0x20]
   0x7fff8bbcec6b:  vmovaps ymmword ptr [rdi], ymm1
   0x7fff8bbcec6f:  vmovaps ymmword ptr [rdi + 0x20], ymm2
   0x7fff8bbcec74:  vmovups ymmword ptr [rdi + rdx + 0x40], ymm3
   0x7fff8bbcec7a:  vmovups ymmword ptr [rdi + rdx + 0x60], ymm4
   0x7fff8bbcec80:  pop    rbp
   0x7fff8bbcec81:  vzeroupper 
   0x7fff8bbcec84:  ret    
   0x7fff8bbcec85:  nop    word ptr cs:[rax + rax]
   0x7fff8bbcec90:  sub    rsi, 0x8
   0x7fff8bbcec94:  mov    rcx, qword ptr [rsi]
   0x7fff8bbcec97:  sub    rdi, 0x8
   0x7fff8bbcec9b:  mov    qword ptr [rdi], rcx
   0x7fff8bbcec9e:  sub    rdx, 0x8
   0x7fff8bbceca2:  jae    0x7fff8bbcec90            ; _platform_memmove$VARIANT$Unknown + 400
   0x7fff8bbceca4:  add    rdx, 0x8
   0x7fff8bbceca8:  je     0x7fff8bbcecbc            ; _platform_memmove$VARIANT$Unknown + 444
   0x7fff8bbcecaa:  sub    rsi, 0x1
   0x7fff8bbcecae:  mov    cl, byte ptr [rsi]
   0x7fff8bbcecb0:  sub    rdi, 0x1
   0x7fff8bbcecb4:  mov    byte ptr [rdi], cl
   0x7fff8bbcecb6:  sub    rdx, 0x1
   0x7fff8bbcecba:  jne    0x7fff8bbcecaa            ; _platform_memmove$VARIANT$Unknown + 426
   0x7fff8bbcecbc:  pop    rbp
   0x7fff8bbcecbd:  ret    
   0x7fff8bbcecbe:  nop    
   0x7fff8bbcecc0:  vmovups ymm0, ymmword ptr [rsi - 0x20]
   0x7fff8bbcecc5:  mov    r11, rdi
   0x7fff8bbcecc8:  sub    rdi, 0x1
   0x7fff8bbceccc:  and    rdi, -0x20
   0x7fff8bbcecd0:  mov    rcx, r11
   0x7fff8bbcecd3:  sub    rcx, rdi
   0x7fff8bbcecd6:  sub    rsi, rcx
   0x7fff8bbcecd9:  sub    rdx, rcx
   0x7fff8bbcecdc:  vmovups ymm1, ymmword ptr [rsi - 0x20]
   0x7fff8bbcece1:  vmovups ymmword ptr [r11 - 0x20], ymm0
   0x7fff8bbcece7:  vmovups ymm2, ymmword ptr [rsi - 0x40]
   0x7fff8bbcecec:  sub    rsi, 0x40
   0x7fff8bbcecf0:  sub    rdx, 0x80
   0x7fff8bbcecf7:  jbe    0x7fff8bbced62            ; _platform_memmove$VARIANT$Unknown + 610
   0x7fff8bbcecf9:  test   rsi, 0x1f
   0x7fff8bbced00:  je     0x7fff8bbced40            ; _platform_memmove$VARIANT$Unknown + 576
   0x7fff8bbced02:  vmovaps ymmword ptr [rdi - 0x20], ymm1; memory write!!
   0x7fff8bbced07:  vmovaps ymmword ptr [rdi - 0x40], ymm2
   0x7fff8bbced0c:  sub    rdi, 0x40
-> 0x7fff8bbced10:  vmovups ymm1, ymmword ptr [rsi - 0x20]; underflow read
   0x7fff8bbced15:  vmovups ymm2, ymmword ptr [rsi - 0x40]
   0x7fff8bbced1a:  sub    rsi, 0x40
   0x7fff8bbced1e:  sub    rdx, 0x40
   0x7fff8bbced22:  ja     0x7fff8bbced02            ; _platform_memmove$VARIANT$Unknown + 514
   0x7fff8bbced24:  jmp    0x7fff8bbced62            ; _platform_memmove$VARIANT$Unknown + 610
   0x7fff8bbced26:  nop    word ptr cs:[rax + rax]
   0x7fff8bbced35:  nop    
   0x7fff8bbced36:  nop    
   0x7fff8bbced37:  nop    
   0x7fff8bbced38:  nop    
   0x7fff8bbced39:  nop    
   0x7fff8bbced3a:  nop    
   0x7fff8bbced3b:  nop    
   0x7fff8bbced3c:  nop    
   0x7fff8bbced3d:  nop    
   0x7fff8bbced3e:  nop    
   0x7fff8bbced3f:  nop    
   0x7fff8bbced40:  vmovaps ymmword ptr [rdi - 0x20], ymm1
   0x7fff8bbced45:  vmovaps ymmword ptr [rdi - 0x40], ymm2
   0x7fff8bbced4a:  sub    rdi, 0x40
   0x7fff8bbced4e:  vmovaps ymm1, ymmword ptr [rsi - 0x20]
   0x7fff8bbced53:  vmovaps ymm2, ymmword ptr [rsi - 0x40]
   0x7fff8bbced58:  sub    rsi, 0x40
   0x7fff8bbced5c:  sub    rdx, 0x40
   0x7fff8bbced60:  ja     0x7fff8bbced40            ; _platform_memmove$VARIANT$Unknown + 576
   0x7fff8bbced62:  sub    rsi, rdx
   0x7fff8bbced65:  vmovups ymm3, ymmword ptr [rsi - 0x20]
   0x7fff8bbced6a:  vmovups ymm4, ymmword ptr [rsi - 0x40]
   0x7fff8bbced6f:  vmovaps ymmword ptr [rdi - 0x20], ymm1
   0x7fff8bbced74:  vmovaps ymmword ptr [rdi - 0x40], ymm2
   0x7fff8bbced79:  vmovups ymmword ptr [rax + 0x20], ymm3
   0x7fff8bbced7e:  vmovups ymmword ptr [rax], ymm4
   0x7fff8bbced82:  pop    rbp
   0x7fff8bbced83:  vzeroupper 
   0x7fff8bbced86:  ret    
(lldb)

This appears to be a possible out of bound read/write in memmove() .As per the memmove source code available here: http://www.opensource.apple.com/source/ntp/ntp-13/ntp/libntp/memmove.c memmove() takes three parameters the destination, source and size. Here I suspect that the crash happens during a backward copy from destination to source, resulting in an underflow read. In real world this is difficult to exploit due to limited buffer space.

Crash PoC : Download To trigger the crash, Open your OS X Mavericks Terminal and do a cat on the PoC file.

cat terminal-poc
The issue was reported to Apple Product Security on 28th June 2015 and after so much follow up from both sides they finally concluded that they won't fix it as the crash is not reproducible on OS X Yosemite.  I would like to thank my friend Dhanesh Kizhakkinan for helping me with the crash analysis.

  • Tags: 
  • OSX 10.9.5 out of bound read/write
  • OSX Mavericks memory corruption
  • out of bound read/write in memmove()

Ajin Abraham

  • |
  • |
  • |

Ajin Abraham is a Security Engineer with 10+ years of experience in Application Security, Research and Engineering. He is passionate about building and maintaining open source security tools and communities. Some of his contributions to Hacker's arsenal include Mobile Security Framework (MobSF), nodejsscan, OWASP Xenotix, etc. Areas of interest include runtime security instrumentation, offensive security, web and mobile application security, code and architectural reviews, cloud-native runtime security, security tool development, security automation, breaking and fixing security products, reverse engineering, and exploit development.