|
| 1 | +# Commvault Communications Service execCmd Vulnerability |
| 2 | + |
| 3 | +## Introduction |
| 4 | + |
| 5 | +Commvault is a data protection and information management software; an enterprise-level data |
| 6 | +platform that contains modules to back up, restore, archive, replicate, and search data. |
| 7 | + |
| 8 | +According to public documentation, the data is protected by installing agent software on the |
| 9 | +physical or virtual hosts, which use the OS or application native APIs to protect data in a |
| 10 | +consistent state. Production data is processed by the agent on client computers and backed |
| 11 | +up through a data manager (the MediaAgent) to disk, tape, or cloud storage. All data |
| 12 | +management activity in the environment is tracked by a centralized server (called CommServe), |
| 13 | +and can be managed by administrators through a central user interface. End users can access |
| 14 | +protected data using web browsers or mobile devices. |
| 15 | + |
| 16 | +One of the base services of Commvault is vulnerable to a remote command injection attack, |
| 17 | +specifically the cvd service. |
| 18 | + |
1 | 19 | ## Vulnerable Application
|
2 | 20 |
|
| 21 | +Commvault v11 SP5 or prior are vulnerable to this vulnerability. The specific vulnerable |
| 22 | +version I tested was 11.0.80.0. |
3 | 23 |
|
4 |
| -This module exploits a remote command injection vulnerability in the Commvault Communications service (cvd.exe). Exploitation of this vulnerability can allow for remote command execution as SYSTEM. |
| 24 | +The version of the vulnerable DLL is: |
5 | 25 |
|
| 26 | +``` |
| 27 | + Image path: C:\Program Files\Commvault\ContentStore\Base\CVDataPipe.dll |
| 28 | + Image name: CVDataPipe.dll |
| 29 | + Timestamp: Wed Dec 21 11:59:21 2016 (585AC2F9) |
| 30 | + CheckSum: 002ED404 |
| 31 | + ImageSize: 002F0000 |
| 32 | + File version: 11.80.50.60437 |
| 33 | + Product version: 11.0.0.0 |
| 34 | + File flags: 1 (Mask 3F) Debug |
| 35 | + File OS: 40004 NT Win32 |
| 36 | + File type: 1.0 App |
| 37 | + File date: 00000000.00000000 |
| 38 | + Translations: 0409.04b0 |
| 39 | + CompanyName: Commvault |
| 40 | + ProductName: Commvault |
| 41 | + InternalName: CVDataPipe |
| 42 | + OriginalFilename: CVDataPipe.dll |
| 43 | + ProductVersion: 11.0.0.0 |
| 44 | + FileVersion: 11.80.50.60437 |
| 45 | + PrivateBuild: |
| 46 | + SpecialBuild: |
| 47 | + FileDescription: |
| 48 | + LegalCopyright: Copyright (c) 2000-2016 |
| 49 | + LegalTrademarks: |
| 50 | + Comments: |
| 51 | +``` |
6 | 52 |
|
7 |
| -Additional information can be found [here](https://www.securifera.com/advisories/sec-2017-0001/) |
| 53 | +## Root Cause Analysis |
8 | 54 |
|
| 55 | +Usually, there are two ways to execute a command in a C/C++ application, one of them is ```WinExec()```, |
| 56 | +and the other one is ```CreateProcess()```: |
9 | 57 |
|
| 58 | +``` |
| 59 | +BOOL WINAPI CreateProcess( |
| 60 | + _In_opt_ LPCTSTR lpApplicationName, |
| 61 | + _Inout_opt_ LPTSTR lpCommandLine, |
| 62 | + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, |
| 63 | + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, |
| 64 | + _In_ BOOL bInheritHandles, |
| 65 | + _In_ DWORD dwCreationFlags, |
| 66 | + _In_opt_ LPVOID lpEnvironment, |
| 67 | + _In_opt_ LPCTSTR lpCurrentDirectory, |
| 68 | + _In_ LPSTARTUPINFO lpStartupInfo, |
| 69 | + _Out_ LPPROCESS_INFORMATION lpProcessInformation |
| 70 | +); |
10 | 71 |
|
11 |
| -## Verification Steps |
| 72 | +``` |
12 | 73 |
|
13 |
| -1. Start msfconsole |
| 74 | +Since ```CreateProcess()``` is meant to replace ```WinExec()``` according to Microsoft, we can create a |
| 75 | +breakpoint there first in our debugger (WinDBG), and we hit it: |
14 | 76 |
|
15 |
| -2. `use exploit/windows/misc/commvault_cmd_exec` |
| 77 | +``` |
| 78 | +0:044> g |
| 79 | +Breakpoint 3 hit |
| 80 | +kernel32!CreateProcessA: |
| 81 | +00000000`76fe8730 4c8bdc mov r11,rsp |
| 82 | +``` |
16 | 83 |
|
17 |
| -3. `set RHOST [ip]` |
| 84 | +Looking at the callstack of this ```kernel32!CreateProcessA```, we already have a pretty good idea |
| 85 | +locating the vulnerability: |
18 | 86 |
|
19 |
| -4. `exploit` |
| 87 | +``` |
| 88 | +0:044> k |
| 89 | +Child-SP RetAddr Call Site |
| 90 | +00000000`11a36b78 000007fe`f378a40f kernel32!CreateProcessA |
| 91 | +00000000`11a36b80 000007fe`f377714e CVDataPipe!execCmd+0x7af |
| 92 | +00000000`11a3f340 000007fe`f3777a69 CVDataPipe!CVDMessageHandler+0x78e |
| 93 | +00000000`11a3fbd0 000007fe`f9cdc58d CVDataPipe!CVDMessageHandler+0x10a9 |
| 94 | +00000000`11a3fd40 000007fe`f9cdc1b1 CvBasicLib!CvThreadPool::th_defaultWorkerObj+0x3cd |
| 95 | +00000000`11a3fe40 000007fe`f9cd2073 CvBasicLib!CvThreadPool::th_defaultWorker+0x51 |
| 96 | +00000000`11a3fe90 000007fe`f9a84f7f CvBasicLib!CvThread::~CvThread+0x63 |
| 97 | +00000000`11a3fee0 000007fe`f9a85126 MSVCR120!_callthreadstartex+0x17 [f:\dd\vctools\crt\crtw32\startup\threadex.c @ 376] |
| 98 | +00000000`11a3ff10 00000000`76f6f56d MSVCR120!_threadstartex+0x102 [f:\dd\vctools\crt\crtw32\startup\threadex.c @ 354] |
| 99 | +00000000`11a3ff40 00000000`770a3281 kernel32!BaseThreadInitThunk+0xd |
| 100 | +00000000`11a3ff70 00000000`00000000 ntdll!RtlUserThreadStart+0x1d |
| 101 | +``` |
| 102 | + |
| 103 | +There are two things that are interesting. One of them is ```CVDataPipe!CVDMessageHandler```, and the |
| 104 | +other one is ```CVDataPipe!execCmd```. |
| 105 | + |
| 106 | +```CVDataPipe!CVDMessageHandler``` is basically a function that handles our packet's message type. |
| 107 | +The Metasploit exploit specifically sends a code of ```9h```, which is the message type for ```execCmd```: |
| 108 | + |
| 109 | +``` |
| 110 | +.text:0000000180147103 loc_180147103: ; CODE XREF: CVDMessageHandler(int,selectStruct_t *,CQiSocket,void *):loc_180146D78j |
| 111 | +.text:0000000180147103 lea rax, [rsp+888h+var_220] ; jumptable 0000000180146D78 case 9 |
| 112 | +.text:000000018014710B mov [rsp+888h+var_600], rax |
| 113 | +.text:0000000180147113 mov rdx, [rsp+888h+sock] |
| 114 | +.text:000000018014711B mov rcx, [rsp+888h+var_600] |
| 115 | +.text:0000000180147123 call cs:??0CQiSocket@@QEAA@AEBV0@@Z ; CQiSocket::CQiSocket(CQiSocket const &) |
| 116 | +.text:0000000180147129 mov [rsp+888h+var_5F0], rax |
| 117 | +.text:0000000180147131 mov r8, [rsp+888h+arg_18] |
| 118 | +.text:0000000180147139 mov rdx, [rsp+888h+var_5F0] |
| 119 | +.text:0000000180147141 mov rcx, [rsp+888h+structSelect] |
| 120 | +.text:0000000180147149 call ?execCmd@@YAXPEAUselectStruct_t@@VCQiSocket@@PEAX@Z ; execCmd(selectStruct_t *,CQiSocket,void *) |
| 121 | +``` |
| 122 | + |
| 123 | +If we take a closer look at the ```execCmd``` function, we can tell the purpose of it is for processes such as: |
| 124 | + |
| 125 | +* ifind (For restoring purposes) |
| 126 | +* BackupShadow.exe (For archiving) |
| 127 | +* Pub (Map file) |
| 128 | +* createIndex (A Commvault process for building index) |
20 | 129 |
|
| 130 | + |
| 131 | +``` |
| 132 | +.text:0000000180159F1B loc_180159F1B: ; CODE XREF: execCmd(selectStruct_t *,CQiSocket,void *)+261j |
| 133 | +.text:0000000180159F1B ; DATA XREF: .rdata:0000000180286258o |
| 134 | +.text:0000000180159F1B lea rdx, aIfind ; "ifind" |
| 135 | +.text:0000000180159F22 lea rcx, [rsp+87B8h+ApplicationName] ; Str |
| 136 | +.text:0000000180159F2A call cs:strstr |
| 137 | +.text:0000000180159F30 test rax, rax |
| 138 | +.text:0000000180159F33 jnz short loc_180159F6D |
| 139 | +.text:0000000180159F35 lea rdx, aBackupshadow_e ; "BackupShadow.exe" |
| 140 | +.text:0000000180159F3C lea rcx, [rsp+87B8h+ApplicationName] ; Str |
| 141 | +.text:0000000180159F44 call cs:strstr |
| 142 | +.text:0000000180159F4A test rax, rax |
| 143 | +.text:0000000180159F4D jnz short loc_180159F6D |
| 144 | +.text:0000000180159F4F lea rdx, aPub ; "Pub" |
| 145 | +.text:0000000180159F56 lea rcx, [rsp+87B8h+ApplicationName] ; Str |
| 146 | +.text:0000000180159F5E call cs:strstr |
| 147 | +... |
| 148 | +.text:000000018015A0BA loc_18015A0BA: ; CODE XREF: execCmd(selectStruct_t *,CQiSocket,void *)+307j |
| 149 | +.text:000000018015A0BA lea rdx, aCreateindex ; "createIndex" |
| 150 | +.text:000000018015A0C1 lea rcx, [rsp+87B8h+ApplicationName] ; Str |
| 151 | +.text:000000018015A0C9 call cs:strstr |
| 152 | +.text:000000018015A0CF test rax, rax |
| 153 | +.text:000000018015A0D2 jz loc_18015A220 |
| 154 | +``` |
| 155 | + |
| 156 | +However, if you don't call one of these processes, the ```execCmd``` will assume you want to run your |
| 157 | +custom process, and pass it to ```CreateProcess``` anyway: |
| 158 | + |
| 159 | +``` |
| 160 | +.text:000000018015A361 loc_18015A361: ; CODE XREF: execCmd(selectStruct_t *,CQiSocket,void *)+675j |
| 161 | +.text:000000018015A361 call cs:GetEnvironmentStrings |
| 162 | +.text:000000018015A367 mov [rsp+87B8h+var_86A8], rax |
| 163 | +.text:000000018015A36F lea rax, [rsp+87B8h+StartupInfo] |
| 164 | +.text:000000018015A377 mov rdi, rax |
| 165 | +.text:000000018015A37A xor eax, eax |
| 166 | +.text:000000018015A37C mov ecx, 68h |
| 167 | +.text:000000018015A381 rep stosb |
| 168 | +.text:000000018015A383 mov [rsp+87B8h+StartupInfo.cb], 68h |
| 169 | +.text:000000018015A38E lea rax, [rsp+87B8h+ProcessInformation] |
| 170 | +.text:000000018015A396 mov rdi, rax |
| 171 | +.text:000000018015A399 xor eax, eax |
| 172 | +.text:000000018015A39B mov ecx, 18h |
| 173 | +.text:000000018015A3A0 rep stosb |
| 174 | +.text:000000018015A3A2 mov [rsp+87B8h+StartupInfo.dwFlags], 1 |
| 175 | +.text:000000018015A3AD xor eax, eax |
| 176 | +.text:000000018015A3AF mov [rsp+87B8h+StartupInfo.wShowWindow], ax |
| 177 | +.text:000000018015A3B7 lea rax, [rsp+87B8h+ProcessInformation] |
| 178 | +.text:000000018015A3BF mov [rsp+87B8h+lpProcessInformation], rax ; lpProcessInformation |
| 179 | +.text:000000018015A3C4 lea rax, [rsp+87B8h+StartupInfo] |
| 180 | +.text:000000018015A3CC mov [rsp+87B8h+lpStartupInfo], rax ; lpStartupInfo |
| 181 | +.text:000000018015A3D1 mov [rsp+87B8h+lpCurrentDirectory], 0 ; lpCurrentDirectory |
| 182 | +.text:000000018015A3DA mov [rsp+87B8h+lpEnvironment], 0 ; lpEnvironment |
| 183 | +.text:000000018015A3E3 mov [rsp+87B8h+dwCreationFlags], 10h ; dwCreationFlags |
| 184 | +.text:000000018015A3EB mov [rsp+87B8h+bInheritHandles], 0 ; bInheritHandles |
| 185 | +.text:000000018015A3F3 xor r9d, r9d ; lpThreadAttributes |
| 186 | +.text:000000018015A3F6 xor r8d, r8d ; lpProcessAttributes |
| 187 | +.text:000000018015A3F9 lea rdx, [rsp+87B8h+CommandLine] ; lpCommandLine |
| 188 | +.text:000000018015A401 lea rcx, [rsp+87B8h+ApplicationName] ; lpApplicationName |
| 189 | +.text:000000018015A409 call cs:CreateProcessA |
| 190 | +``` |
| 191 | + |
| 192 | +It is unclear whether allowing an arbitrary custom process is intentional or not, it is unsafe |
| 193 | +anyway considering the cvd process binds to 0.0.0.0, so anybody can gain access to it under the |
| 194 | +context of SYSTEM. |
| 195 | + |
| 196 | +## Using the Metasploit Module |
| 197 | + |
| 198 | +1. Start msfconsole |
| 199 | +2. `use exploit/windows/misc/commvault_cmd_exec` |
| 200 | +3. `set RHOST [ip]` |
| 201 | +4. `exploit` |
21 | 202 | 5. shellz :)
|
| 203 | + |
| 204 | + |
| 205 | +## References |
| 206 | + |
| 207 | +* https://en.wikipedia.org/wiki/Commvault |
| 208 | +* https://www.securifera.com/advisories/sec-2017-0001/ |
0 commit comments