Monday, February 24, 2014

Fun With HP Data Protector EXEC_BAR Remote Command Execution

Deep Dive Analysis Of CVE-2013-2347

Chris Graham

One of the benefits our clients have when using our vulnerability scanner is that many of the vulnerability checks we write are non-authenticated. This means that we do not require credentials to authenticate to hosts over the network in order to check for vulnerabilities. Instead, our team of researchers frequently reverse engineers software to identify unique methods of remotely detecting both newly-reported and undisclosed vulnerabilities. Since we essentially exploit the vulnerability to determine if a host is susceptible to a particular flaw, this provides our clients with an added benefit of reduced false positives and a clearer view of what an attacker would see on their network.

Since many of the vulnerabilities we see these days are either web-centric or client-side, it's very exciting when we find any sort of server-side remote arbitrary command execution vulnerability. When I saw that HP Data Protector had several new vulnerabilities reported early this year, I jumped at the opportunity to write a test for the EXEC_BAR remote command execution flaw. 

To be fair, Data Protector has had a large number of similar vulnerabilities discovered and reported over the years so this new one is not exactly ground breaking. Most of the disclosed issues exist in version 6.10, 6.11, and 6.20. Even though Data Protector is now on version 7 and 8, a lot of people surprisingly still run the older version. Although our scanning engine already discovers and reports on the other vulnerabilities in Data Protector, this newly disclosed EXEC_BAR flaw has great potential for pen-testers since it provides an easy way to compromise a server.. 

So let's get to the technical details...

HP Data Protector utilizes an agent called omniinet.exe, which runs as a SYSTEM level service on Windows systems. When setting up Data Protector, you can designate a server as a cell manager which can then communicate with the remote agent that would be installed on any other servers that you want to perform backup operations on. These servers that are running the agent would then be part of a cell. 

The cell manager communicates with the agent using a custom packet structure that will be discussed below. Here is a sample hexdump of a typical packet:

 0000  00 00 00 64 ff fe 32 00 00 00 20 00 68 00 70 00 ...d..2... .h.p.  
 0010  64 00 70 00 31 00 00 00 20 00 30 00 00 00 20 00 d.p.1... .0... .  
 0020  53 00 59 00 53 00 54 00 45 00 4d 00 00 00 20 00 S.Y.S.T.E.M... .  
 0030  4e 00 54 00 20 00 41 00 55 00 54 00 48 00 4f 00 N.T. .A.U.T.H.O.  
 0040  52 00 49 00 54 00 59 00 00 00 20 00 45 00 4e 00 R.I.T.Y... .E.N.  
 0050  55 00 00 00 20 00 30 00 00 00 20 00 49 00 4e 00 U... .0... .I.N.  
 0060  46 00 4f 00 00 00 00 00                         F.O.....  

The first 4 bytes of the packet indicate the total length of the packet minus that header. In this case, the packet length is 0x64 or 100 bytes. Following the packet length header, there is a Unicode byte order marker 0xFFFE indicating the endianness that will be used in the packet.

From an exploitation standpoint, there are two important points to remember when sending these packets: 

  • The first is that every field is Unicode. 
  • The second is that you separate packet arguments by essentially using a "space" character (0x20 hex). 
With that in mind, you can begin to see a pattern in the above packet. If you look at the argument immediately following the string "ENU", you can see this is a hex representation of the ASCII character 0. This single Unicode value is the opcode of the packet (\x30\x00\x00\x00). Immediately after the opcode, you see a string that identifies the type of packet this is. In our case, it is an INFO packet. Armed with this knowledge, it is possible to begin figuring out what the agent does with these packets. 

The specific vulnerability that I was interested in was the remote command execution flaw that was reportedly triggerable via a malicious EXEC_BAR packet. This was disclosed via HP Tipping Point's Zero Day Initiative by 

Here is the flow of omniinet from the application entry point to the function that eventually processes the opcode:

When omniinet receives a packet from the cell manager, it will eventually end up in the ProcessConnect function where it will grab the opcode in the packet and perform a lookup to determine what operation is being requested. Since the opcode being sent in the packet is a Unicode string, it must be converted to an integer:

The function, which I renamed to LookupOpcode, accepts an opcode as a parameter and returns a pointer to a record in a data structure. This data structure contains multiple records with each entry being twelve bytes and containing an opcode, a function pointer, and a pointer to a Unicode string indicating the type of operation. 

Each entry might be represented by a structure that looks something like this:
 typedef struct OPENTRY {  
       DWORD dwOpcode;  
       VOID __cdecl * lpOpHandlerFunc;  
       LPWSTR pwszOpType;  
 } OpEntry, *pOpEntry;  

In the code you can see how omniinet searches the table and compares the opcode received in the packet to each entry's opcode until it finds one that matches or does not:

After the lookup is complete, in the ProcessConnect function, omniinet will call the function pointer in the OpEntry struct for the associated opcode:

This EXEC_BAR function handler is where the vulnerability lies. If we take a look at the beginning of the EXEC_BAR handler function, you can see that a comparison is done on the number of packet arguments to determine if it is greater than eighteen. If it is not, you get an error:

Assuming you sent a packet with the correct number of arguments, omniinet will take the eighteenth and nineteenth argument, allocate string buffers for them in memory and pass them along in a structure that can be accessed by a function in a new thread. The problem here is that no checking is ever done to ensure that the command being used as the executable to launch is within the scope of what the application intended. As a result, sending a string like 'c:\windows\system32\cmd.exe' will result in omniinet calling cmd.exe. In addition, because this function is actually designed to launch an executable that accepts command line arguments, anything after the eighteenth string in the packet can be conveniently used as a command line argument for cmd.exe.

So to sum things up, once I figured out where in the assembly that omniinet was processing my packets, it was trivial to build one that would trigger this vulnerability. If you were to follow the rest of the ExecBarFunc, you would see that it literally passes on the two strings mentioned above to a new thread which ultimately calls CreateProcessW with the two arguments combined as the lpCommandLine parameter such that you could end up with: “’c:\windows\system32\cmd.exe’ ‘/c net user usr p@ss!23 /add’”.  This would cause omniinet to create a new windows user called ‘usr’ with a password of ‘p@ss!23’.