Note: This article is outdated. It only worked for a specific version of SQL Developer. We’re keeping the article around for historic reasons.
Recently, while at one of our customers’ site, the customer and I needed to get access to a database. On my machine, I had stored the password, but the customer obviously didn’t want to rely on my machine, and the password itself is hashed, so we couldn’t guess it. But guess what? Yes we can! I googled a bit, and incredibly, I found instructions to write the following little utility programme, which I’m licensing to you under the terms of the
ASL 2.0:
DISCLAIMER: This program is BY NO MEANS intended for you to do any harm. You could have found this information anywhere else on the web. Please use this ONLY to recover your own “lost” passwords. Like I did.
Note also, this only works with SQL Developer versions less than 4.
import java.io.File;
import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class SQLDeveloperDecrypter {
public static void main(String[] args) throws Exception {
if (args.length == 0) {
System.err.println(" Usage 1: " + SQLDeveloperDecrypter.class.getName() + " 0501F83890..... (a single encrypted password)");
System.err.println(" Usage 2: " + SQLDeveloperDecrypter.class.getName() + " C:\\Users\\...... (the path to the connections.xml file)");
System.err.println();
System.err.println(" Pass the password hash code from your connections.xml file. The file might be located at (example)");
System.err.println(" C:\\Users\\[User]\\AppData\\Roaming\\SQL Developer\\system2.1.1.64.45\\o.jdeveloper.db.connection.11.1.1.2.36.55.30");
System.exit(-1);
}
if (args[0].startsWith("05")) {
System.out.println(decryptPassword(args[0]));
}
else {
File file = new File(args[0]);
if (file.isDirectory())
file = new File(file, "connections.xml");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(file.toURI().toString());
// The relevant structure is:
//
// <Reference name="connection name">
// <RefAddresses>
// <StringRefAddr addrType="password">
// <Contents>057D3DE2...
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("//StringRefAddr[@addrType='password']/Contents");
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
Element e = (Element) nodes.item(i);
System.out.println("Connection name : " +
((Element) e.getParentNode().getParentNode().getParentNode()).getAttribute("name")
);
System.out.println("Password (encrypted): " +
e.getTextContent()
);
System.out.println("Password (decrypted): " +
decryptPassword(e.getTextContent())
);
System.out.println();
}
}
}
// From: https://stackoverflow.com/a/140861
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
// From: https://stackoverflow.com/a/3109774
public static String decryptPassword(String result) throws GeneralSecurityException {
return new String(decryptPassword(hexStringToByteArray(result)));
}
public static byte[] decryptPassword(byte[] result) throws GeneralSecurityException {
byte constant = result[0];
if (constant != 5) {
throw new IllegalArgumentException();
}
byte[] secretKey = new byte[8];
System.arraycopy(result, 1, secretKey, 0, 8);
byte[] encryptedPassword = new byte[result.length - 9];
System.arraycopy(result, 9, encryptedPassword, 0, encryptedPassword.length);
byte[] iv = new byte[8];
for (int i = 0; i < iv.length; i++) {
iv[i] = 0;
}
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secretKey, "DES"), new IvParameterSpec(iv));
return cipher.doFinal(encryptedPassword);
}
}
Parts of the source code were borrowed, from
here and
here. In other words, virtually any hacker could’ve come up with the above programme. And the output? This:
Connection name : SAKILA
Password (encrypted): 0517CB1A41E3C2CC3A3163234A6A8E92F8
Password (decrypted): SAKILA
Connection name : TEST
Password (encrypted): 05B03F45511F83F6CD4D322C9E173B5A94
Password (decrypted): TEST
Wonderful! All the passwords on my machine are now recovered in constant time (no brute force).
Does this make you think? I hope that your DBA doesn’t store their passwords in SQL Developer. On a laptop. Which they forget in the train. With access to your customers’ credit card information.
In the meantime, though, I’m glad I could recover the “lost” password for my client ;-)
Like this:
Like Loading...
Published by lukaseder
I made jOOQ
View all posts by lukaseder
I think they changed the encryption in SQLDeveloper v4. The passwords have a different format.
Interesting. Time to upgrade, I guess!
For sql developer > 4
Interesting, thanks for sharing. What library is
oracle.jdevimpl.db.adapter.ReferenceWorker
contained in?You need to include adf-share-ca.jar in your classpath
Hi, I’m looking encryption method for this sqldeveloper > 4.0. I have to use that method in powershell and generate the connections.xml. Any one help me on this? Thanks in advance.
Hey, no, no help here. But let us know if you find any!