Thursday, May 24, 2018

WindScribe VPN Privilege Escalation

The VPN component in Windscribe 1.81 uses the OpenVPN client for connections. Also, it creates a WindScribeService.exe system process that establishes a \\.\pipe\WindscribeService named pipe endpoint that allows the Windscribe VPN process to connect and execute an OpenVPN process or other processes (like taskkill, etc.). There is no validation of the program name before constructing the lpCommandLine argument for a CreateProcess call. An attacker can run any malicious process with SYSTEM privileges through this named pipe.


Named Pipe function:
HANDLE createNamedPipe()
{
  HANDLE result; // rax@2
  struct _SECURITY_ATTRIBUTES SecurityAttributes; // [sp+40h] [bp-28h]@1

  SecurityAttributes.lpSecurityDescriptor = malloc(0x28ui64);
  if ( InitializeSecurityDescriptor(SecurityAttributes.lpSecurityDescriptor, 1u)
    && SetSecurityDescriptorDacl(SecurityAttributes.lpSecurityDescriptor, 1, 0i64, 0) )
  {
    SecurityAttributes.nLength = 24;
    SecurityAttributes.bInheritHandle = 1;
    result = CreateNamedPipeW(
               L"\\\\.\\pipe\\WindscribeService",
               0x40000003u,
               6u,
               0xFFu,
               0x7D05u,
               0x7D05u,
               0,
               &SecurityAttributes);
  }
  else
  {
    result = (HANDLE)-1;
  }
  return result;
}
First NamedPipe is created and then information is waited in WindscribeService (Running in SYSTEM Privilege) from WindScribe to execute openvpn client or other commands.

Main function for creating NamedPipe:
  v5 = createNamedPipe();  < === NamedPipe is created by this function.
  if ( v5 != (HANDLE)-1 )
  {
    v6 = CreateEventW(0i64, 1, 1, 0i64);
    if ( v6 )
    {
      ServiceStatus.dwControlsAccepted = 5;
      ServiceStatus.dwCurrentState = 4;
      ServiceStatus.dwWin32ExitCode = 0;
      ServiceStatus.dwCheckPoint = 0;
      SetServiceStatus(hServiceStatus, &ServiceStatus);
      Overlapped.InternalHigh = (ULONG_PTR)v6;
      Handles = hEvent;
      v19 = v6;
      ConnectNamedPipe(v5, &Overlapped);
      for ( i = WaitForMultipleObjects(2u, &Handles, 0, 0xFFFFFFFF);
            i;
            i = WaitForMultipleObjects(2u, &Handles, 0, 0xFFFFFFFF) )
      {
        if ( i == 1 )
        {
          v8 = 32005;
          v9 = (char *)&Overlapped.hEvent;
          LODWORD(v17) = 0;
          while ( ReadFile(v5, v9, v8, (LPDWORD)&v17, 0i64) ) // Information (shellcode) sent by attacker is read and written to buffer.
          {
            v9 += (unsigned int)v17;
            v8 -= (unsigned int)v17;
            if ( !v8 ) < If data sent by attacker is 32005 byte, sendLog_and_CreateProcess functions are called and data is sent to this function.
            {
              v11 = 1;
              goto LABEL_21;
            }
          }
          v11 = 0;
LABEL_21:
          if ( v11 )
          {
            sendLog_and_CreateProcess(
              (__int64)&Buffer,
              (__int64)&Overlapped.hEvent,
              v10,
              &Uuid,
              (__int64)engineHandle,
              (__int64)&v26);
There are multiple conditions in sendLog_and_CreateProcess functions and in this functions there is validation for COMMAND_EXECUTE(to run openvpn.exe process) in which attacker should sent a byte to buffer.
Then this command line parameter(which has been sent to create process) is sent to send_log_file function for logging.

sendLog_and_CreateProcess function:
send_log_file(&File, L"AA_COMMAND_EXECUTE, blocking=%d, cmd=%s"); < === is sent to log file
if ( *(_BYTE *)(v7 + 4) )
{
  sub_13FF6E7C0(v13, v12, v14);
  v16 = create_priviliged_process(v15, (__int64)&Memory, v7); < == Information recieved by buffer is sent to CreateProcess function.
}
Then attacker information which has been sent to buffer by Named Pipe, is sent to CreateProcess function in create_priviliged_process and process is executed.

MSDN CreateProcess documentation:
CreateProcess(
  _In_opt_    LPCTSTR               lpApplicationName,
  _Inout_opt_ LPTSTR                lpCommandLine, < ===== "calc.exe"
  _In_opt_    LPSECURITY_ATTRIBUTES lpProcessAttributes,
  _In_opt_    LPSECURITY_ATTRIBUTES lpThreadAttributes,
  _In_        BOOL                  bInheritHandles,
  _In_        DWORD                 dwCreationFlags,
  _In_opt_    LPVOID                lpEnvironment,
  _In_opt_    LPCTSTR               lpCurrentDirectory,
  _In_        LPSTARTUPINFO         lpStartupInfo,
  _Out_       LPPROCESS_INFORMATION lpProcessInformation
);
create_priviliged_process function:
  if ( CreatePipe(&hReadPipe, &hWritePipe, &PipeAttributes, 0) )
  {
    sub_13FF78490(&StartupInfo, 0i64, 104i64);
    StartupInfo.cb = 104;
    StartupInfo.dwFlags |= 0x100u;
    StartupInfo.hStdInput = 0i64;
    StartupInfo.hStdError = hWritePipe;
    StartupInfo.hStdOutput = hWritePipe;
    hWritePipe = 0i64;
    hObject = 0i64;
    v15 = 0i64;
    if ( CreateProcessW(
           0i64,
           (LPWSTR)(v3 + 261), < ==== commandline parameter is sent by attacker.
           0i64,
           0i64,
           1,
           0x8000020u,
           0i64,
           0i64,
           &StartupInfo,
           (LPPROCESS_INFORMATION)&hWritePipe) )
    {
      WaitForSingleObject(hWritePipe, 0xFFFFFFFF);
      GetExitCodeProcess(hWritePipe, (LPDWORD)&hReadPipe);
      CloseHandle(hWritePipe);
      sub_13FF6E370(&Memory, hReadPipe);
      CloseHandle(hReadPipe);
      CloseHandle(hWritePipe);
      CloseHandle(hObject);
      v11[8] = 1;
      *(_DWORD *)&v11[9] = (_DWORD)hReadPipe;
      *(_DWORD *)&v11[18] = Size;
      if ( Size )
      {
        v8 = operator new(Size);
        *(_QWORD *)&v11[22] = v8;
        v9 = &Memory;
        if ( v21 >= 0x10 )
          v9 = Memory;
        sub_13FF700B0(v8, v9, Size);
      }
      if ( v21 >= 0x10 )
        j_free(Memory);
    }



Exploit code:

https://pastebin.com/eLG3dpYK

CVE Assigned:
CVE-2018-11479

No comments:

Post a Comment