Attacker Value
Unknown
(1 user assessed)
Exploitability
Unknown
(1 user assessed)
User Interaction
Unknown
Privileges Required
Unknown
Attack Vector
Unknown
0

CVE-2017-18044 - Commvault Communications Service execCmd Vulnerability

Disclosure Date: January 19, 2018
Add MITRE ATT&CK tactics and techniques that apply to this CVE.

Description

A certain message parsing function inside the Commvault service does not properly validate the input of an incoming string before passing it to CreateProcess. As a result, a specially crafted message can inject commands that will be executed on the target operating system. Exploitation of this vulnerability does not require authentication and can lead to SYSTEM level privilege on any system running the cvd daemon.

Add Assessment

2
Technical Analysis

Introduction

Commvault is a data protection and information management software; an enterprise-level data
platform that contains modules to back up, restore, archive, replicate, and search data.

According to public documentation, the data is protected by installing agent software on the
physical or virtual hosts, which use the OS or application native APIs to protect data in a
consistent state. Production data is processed by the agent on client computers and backuped
up through a data manager (the MediaAgent) to disk, tape, or cloud storage. All data
management activity in the environment is tracked by a centralized server (called CommServe),
and can be managed by administrators through a central user interface. End users can access
protected data using web browsers or mobile devices.

One of the base services of Commvault is vulnerable to a remote command injection attack,
specifically the cvd service. It was a Metasploit submission by @rwincey as PR #9340.

Vulnerable Application

According to the public advisory, Commvault v11 SP5 or prior are vulnerable to this
vulnerability.

The specific vulnerable version I tested was 11.0.80.0, and the software was obtained from
the Metasploit contributor @rwincey. The software is available from our Google Drive at:

Vulnerable Apps –> Commvault –> Commvault_R80_SP5_22September16.exe.

The version of the vulnerable DLL is:

    Image path: C:\Program Files\Commvault\ContentStore\Base\CVDataPipe.dll
    Image name: CVDataPipe.dll
    Timestamp:        Wed Dec 21 11:59:21 2016 (585AC2F9)
    CheckSum:         002ED404
    ImageSize:        002F0000
    File version:     11.80.50.60437
    Product version:  11.0.0.0
    File flags:       1 (Mask 3F) Debug
    File OS:          40004 NT Win32
    File type:        1.0 App
    File date:        00000000.00000000
    Translations:     0409.04b0
    CompanyName:      Commvault
    ProductName:      Commvault
    InternalName:     CVDataPipe
    OriginalFilename: CVDataPipe.dll
    ProductVersion:   11.0.0.0
    FileVersion:      11.80.50.60437
    PrivateBuild:
    SpecialBuild:
    FileDescription:
    LegalCopyright:   Copyright (c) 2000-2016
    LegalTrademarks:
    Comments:

Root Cause Analysis

Based on the information we have from the pull request, the vulnerability is a command injection, so
that’s where we begin reversing.

Usually, there are two ways to execute a command in a C/C++ application, one of them is WinExec(),
and the other one is CreateProcess():

BOOL WINAPI CreateProcess(
  _In_opt_    LPCTSTR               lpApplicationName,
  _Inout_opt_ LPTSTR                lpCommandLine,
  _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
);

Since CreateProcess() is meant to replace WinExec() according to Microsoft, we can create a
break point there fist in our debugger (WinDBG), and we hit it:

0:044> g
Breakpoint 3 hit
kernel32!CreateProcessA:
00000000`76fe8730 4c8bdc          mov     r11,rsp

Looking at the callstack of this kernel32!CreateProcessA, we already have a pretty good idea
locating the vulnerability:

0:044> k
Child-SP          RetAddr           Call Site
00000000`11a36b78 000007fe`f378a40f kernel32!CreateProcessA
00000000`11a36b80 000007fe`f377714e CVDataPipe!execCmd+0x7af
00000000`11a3f340 000007fe`f3777a69 CVDataPipe!CVDMessageHandler+0x78e
00000000`11a3fbd0 000007fe`f9cdc58d CVDataPipe!CVDMessageHandler+0x10a9
00000000`11a3fd40 000007fe`f9cdc1b1 CvBasicLib!CvThreadPool::th_defaultWorkerObj+0x3cd
00000000`11a3fe40 000007fe`f9cd2073 CvBasicLib!CvThreadPool::th_defaultWorker+0x51
00000000`11a3fe90 000007fe`f9a84f7f CvBasicLib!CvThread::~CvThread+0x63
00000000`11a3fee0 000007fe`f9a85126 MSVCR120!_callthreadstartex+0x17 [f:\dd\vctools\crt\crtw32\startup\threadex.c @ 376]
00000000`11a3ff10 00000000`76f6f56d MSVCR120!_threadstartex+0x102 [f:\dd\vctools\crt\crtw32\startup\threadex.c @ 354]
00000000`11a3ff40 00000000`770a3281 kernel32!BaseThreadInitThunk+0xd
00000000`11a3ff70 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

There are two things that are interesting. One of them is CVDataPipe!CVDMessageHandler, and the
other one is CVDataPipe!execCmd.

CVDataPipe!CVDMessageHandler is basically a function that handles our packet’s message type.
The Metasploit exploit specifically sends a code of 9h, which is the message type for execCmd:

.text:0000000180147103 loc_180147103:                          ; CODE XREF: CVDMessageHandler(int,selectStruct_t *,CQiSocket,void *):loc_180146D78j
.text:0000000180147103                 lea     rax, [rsp+888h+var_220] ; jumptable 0000000180146D78 case 9
.text:000000018014710B                 mov     [rsp+888h+var_600], rax
.text:0000000180147113                 mov     rdx, [rsp+888h+sock]
.text:000000018014711B                 mov     rcx, [rsp+888h+var_600]
.text:0000000180147123                 call    cs:??0CQiSocket@@QEAA@AEBV0@@Z ; CQiSocket::CQiSocket(CQiSocket const &)
.text:0000000180147129                 mov     [rsp+888h+var_5F0], rax
.text:0000000180147131                 mov     r8, [rsp+888h+arg_18]
.text:0000000180147139                 mov     rdx, [rsp+888h+var_5F0]
.text:0000000180147141                 mov     rcx, [rsp+888h+structSelect]
.text:0000000180147149                 call    ?execCmd@@YAXPEAUselectStruct_t@@VCQiSocket@@PEAX@Z ; execCmd(selectStruct_t *,CQiSocket,void *)

If we take a closer look at the execCmd function, we can tell the purpose of it is for processes such as:

  • ifind (For restoring purposes)
  • BackupShadow.exe (For archiving)
  • Pub (Map file)
  • createIndex (A Commvault process for building index)
.text:0000000180159F1B loc_180159F1B:                          ; CODE XREF: execCmd(selectStruct_t *,CQiSocket,void *)+261j
.text:0000000180159F1B                                         ; DATA XREF: .rdata:0000000180286258o
.text:0000000180159F1B                 lea     rdx, aIfind     ; "ifind"
.text:0000000180159F22                 lea     rcx, [rsp+87B8h+ApplicationName] ; Str
.text:0000000180159F2A                 call    cs:strstr
.text:0000000180159F30                 test    rax, rax
.text:0000000180159F33                 jnz     short loc_180159F6D
.text:0000000180159F35                 lea     rdx, aBackupshadow_e ; "BackupShadow.exe"
.text:0000000180159F3C                 lea     rcx, [rsp+87B8h+ApplicationName] ; Str
.text:0000000180159F44                 call    cs:strstr
.text:0000000180159F4A                 test    rax, rax
.text:0000000180159F4D                 jnz     short loc_180159F6D
.text:0000000180159F4F                 lea     rdx, aPub       ; "Pub"
.text:0000000180159F56                 lea     rcx, [rsp+87B8h+ApplicationName] ; Str
.text:0000000180159F5E                 call    cs:strstr
...
.text:000000018015A0BA loc_18015A0BA:                          ; CODE XREF: execCmd(selectStruct_t *,CQiSocket,void *)+307j
.text:000000018015A0BA                 lea     rdx, aCreateindex ; "createIndex"
.text:000000018015A0C1                 lea     rcx, [rsp+87B8h+ApplicationName] ; Str
.text:000000018015A0C9                 call    cs:strstr
.text:000000018015A0CF                 test    rax, rax
.text:000000018015A0D2                 jz      loc_18015A220

However, if you don’t call one of these processes, the exeCmd will assume you want to run your
custom process, and pass it to CreateProcess anyway:

.text:000000018015A361 loc_18015A361:                          ; CODE XREF: execCmd(selectStruct_t *,CQiSocket,void *)+675j
.text:000000018015A361                 call    cs:GetEnvironmentStrings
.text:000000018015A367                 mov     [rsp+87B8h+var_86A8], rax
.text:000000018015A36F                 lea     rax, [rsp+87B8h+StartupInfo]
.text:000000018015A377                 mov     rdi, rax
.text:000000018015A37A                 xor     eax, eax
.text:000000018015A37C                 mov     ecx, 68h
.text:000000018015A381                 rep stosb
.text:000000018015A383                 mov     [rsp+87B8h+StartupInfo.cb], 68h
.text:000000018015A38E                 lea     rax, [rsp+87B8h+ProcessInformation]
.text:000000018015A396                 mov     rdi, rax
.text:000000018015A399                 xor     eax, eax
.text:000000018015A39B                 mov     ecx, 18h
.text:000000018015A3A0                 rep stosb
.text:000000018015A3A2                 mov     [rsp+87B8h+StartupInfo.dwFlags], 1
.text:000000018015A3AD                 xor     eax, eax
.text:000000018015A3AF                 mov     [rsp+87B8h+StartupInfo.wShowWindow], ax
.text:000000018015A3B7                 lea     rax, [rsp+87B8h+ProcessInformation]
.text:000000018015A3BF                 mov     [rsp+87B8h+lpProcessInformation], rax ; lpProcessInformation
.text:000000018015A3C4                 lea     rax, [rsp+87B8h+StartupInfo]
.text:000000018015A3CC                 mov     [rsp+87B8h+lpStartupInfo], rax ; lpStartupInfo
.text:000000018015A3D1                 mov     [rsp+87B8h+lpCurrentDirectory], 0 ; lpCurrentDirectory
.text:000000018015A3DA                 mov     [rsp+87B8h+lpEnvironment], 0 ; lpEnvironment
.text:000000018015A3E3                 mov     [rsp+87B8h+dwCreationFlags], 10h ; dwCreationFlags
.text:000000018015A3EB                 mov     [rsp+87B8h+bInheritHandles], 0 ; bInheritHandles
.text:000000018015A3F3                 xor     r9d, r9d        ; lpThreadAttributes
.text:000000018015A3F6                 xor     r8d, r8d        ; lpProcessAttributes
.text:000000018015A3F9                 lea     rdx, [rsp+87B8h+CommandLine] ; lpCommandLine
.text:000000018015A401                 lea     rcx, [rsp+87B8h+ApplicationName] ; lpApplicationName
.text:000000018015A409                 call    cs:CreateProcessA

It is unclear whether allowing an arbitrary custom process is intentional or not, it is unsafe
anyway considering the cvd process binds to 0.0.0.0, so anybody can access to it.

General Information

Additional Info

Technical Analysis