SAP Java Secure Storage
Editorial Note: This article was a collaborative effort by the ERPScan Research Team.
In general, the realization of Secure Storage in the Java stack resembles the ABAP’s one. It comes in two different types: Java Secure Storage in the file system and Java Secure Storage.
Why Can it Be Interesting?
Imagine that a strong multi-layer security of the SAP system can be evaded by obtaining just 2 files. Moreover, it leads to losing control not only of the target system but all connected systems and mail services. Want to know where this golden key to open any door is stored? In SAP systems, it is Secure Storage. This article will show you where it is located, how it’s used, and how to prevent disastrous consequences of a hacker’s attack.
What Can Be Done by Getting Access to SAP Java Secure Storage?
Java Secure Storage contains a lot of key data which can be used by attackers to escalate their privileges. The most important examples are:
- RFC destination store's credentials to connect to satellite systems.
- HTTP destinations – users and passwords to connect to satellite systems.
- Mail destinations – users and passwords to connect to mail services.
- Exchange Infrastructure (XI) contains details of connections with satellite systems connected by the SAP XI platform.
As you know, getting credentials is one of the most common and effective ways to compromise a service. Eventually, if one can get the usernames and passwords from RFC destinations, he or she can use them to access the external SAP system. An account used for remote function calling usually has special privilege permissions and it’s essential to identify these connections as the system is as secure as the least protected element.
How Can We Get Access to Java Secure Storage?
Java Secure Storage in the File System
Java Secure Storage is a well- known term, nevertheless, let’s refresh our knowledge.
The AS Java stores security-relevant information encrypted in the file system. The two most important files in the SAP system are SecStore.key and Secstore.properties. They are located in the “\usr\sap\\SYS\global\security\data\” directory.
What can we find here? We have prepared some examples below:
#SAP Secure Store file - Don't edit this file manually! #Thu Feb 04 19:19:13 PST 2016 $internal/version=Ny4wMC4wMDAuMDAx $internal/mode=encrypted jdbc/pool/M13=2261rTZ2pITmqgaR1/UB1iIMr03nbOke3UHjwgib7LTBkoXC2Hugj7DfC7NTK4Rq\r\npapvuV8fQj6NybzKM/BF1VdAAAxdZni9QT/xfzUUB3C2cQQxcx+LWNSqRmDTwHY6\r\nNyYGBVWge6YwdrNp6KwxfNdmX6oXyQQEc9nVwV9O5WtdZKImzYcAYNumbZMb5QGL\r\nLyjB5psGf8QIqqAie7asj6vLleT3JhjSn9vx8CztVnkDSRg1xkc4bPa+us0T/J5z\r\n8aks4APMjxD8YK32FGuBhQ\=\= $internal/check=hbKoCd5BpzTsKGvOySEX2ZS+LMFqGNKz
SecStore.properties
00000000: 372e 3030 2e30 3030 2e30 3031 7c1a 84bc 7.00.000.001|... 00000010: abc1 a9d7 6340 ....c@
SecStore.key
As you can see, there is encrypted Database connection information in the SecStore.properties file.
It is quite easy to reverse Java applications as we could decompile them and receive a readable code. Some of debugging functions in SAP NetWeaver AS Java were helpful. We found the “com.sap.security.core.server.secstorefs” package with an interesting class “KeyHandler” responsible for key manipulations. After a lot of checks, the private decryptKey
method is called.
private String decryptKey(byte[] ciphertext) throws InvalidStateException, NoHashException {
byte[] plaintext = this.xor(ciphertext);
String keyPhrase = null;
try {
keyPhrase = new String(plaintext, "UTF-8");
return keyPhrase;
} catch (UnsupportedEncodingException arg4) {
throw new InvalidStateException("security.class_secStoreFS_0017", arg4);
}
}
Therefore, the “xor” method, as the name implies, makes XOR between a static hard coded value and significant bytes from Secstore.key.
The result is the keyPhrase in clear text. As a rule, this keyPhrase is also an admin password.
What about SecStore? In the same package “com.sap.security.core.server.secstorefs,” there is a Crypt class with the Crypt()
method:
Crypt() {
try {
Cipher ex = Cipher.getInstance("PbeWithSHAAnd3_KeyTripleDES_CBC", "IAIK");
KeyHandler localKh = new KeyHandler();
localKh.setKeyForSession("xxx");
PBEKeyBMP key = localKh.getEffectiveKey(1);
byte[] salt = new byte[16];
salt[0] = salt[1] = salt[2] = salt[3] = salt[4] = salt[5] = salt[6] = salt[7] = salt[8] = salt[9] = salt[10] = salt[11] = salt[12] = salt[13] = salt[14] = salt[15] = 0;
byte count = 0;
this.pbeParamSpec = new PBEParameterSpec(salt, count);
ex.init(1, key, this.pbeParamSpec);
The “PbeWithSHAAnd3_KeyTripleDES_CBC” algorithm is used to encrypt and decrypt secure data. The encryption uses the TripleDES algorithm in CBC mode via a secret key derived from keyPhrase with the SHA hash algorithm.
As for salt, it’s «0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0».
We have all we need to decrypt secure data. We also wrote a simple tool to decrypt all data from SAP Java AS Secure Storage (that will be released soon):
Java Secure Storage
As you may know, ABAP Secure Storage is introduced as the database table called RSECTAB, which stores information about passwords from:
- RFC destinations.
- Exchange Infrastructure (XI).
- LDAP system users.
- SAPphone.
- SAPconnect.
- CCMS (Generic Request and Message Generator).
When we started our research, our objective was to understand how RFC destinations work, where it’s stored, and how we can get it in the Java Stack system. In total, we discovered a remarkable place with a lot of encrypted data like passwords, logins for SAP Destinations (HTTP, RFC, etc.), JavaMail Client Service, etc. So, let’s start from the beginning.
It’s not a secret that an SAP system can be linked with others, for example, using RFC connections. No need to say that it’s necessary to setup credentials of the external system in the destination to establish the connection. One may ask where and how the credentials are stored.
Of note, we worked with SAP NetWeaver AS Java 7.50 and all we have found works on SAP NetWeaver AS Java 7.30 and further versions.
We created and configured our destination in SAP NetWeaver as the Administrator of the SAP System. We searched for the destination’s name in the database and discover a table titled “J2EE_CONFIGENTRY,” which contains nearly 1 million rows.
Every object has its own list of parameters with pre-installed secure and non-secure flags. Every raw determines one parameter of the object. The table consists of 10 columns:
The fields “CID”, “NAME”, “VSTR” and “VBYTES” attracted our attention.
- “CID” provides a unique ID of the object in a specific format like “-9223372036854775700”. All parameters of a certain object have the same “CID.”
- “NAME” is the name of the object’s parameter. It begins with special symbols like “#~” for the RFC destinations.
- “VSTR” and “VBYTES” are the values of the parameter. If the value has no secure flag, it’s stored in clear text in the “VSTR” column and, if it does have a secure flag it's stored in “VBYTES.” Data in the VBYTES value is encrypted.
We have collected the full parameter list of RFC Destinations:
Parameter |
Secure Flag |
---|---|
#~jco.destination.repository_destination |
No |
#~jco.client.snc_qop |
No |
#~jco.client.snc_mode |
No |
#~AUTHENTICATION_MODE |
No |
#~jco.client.cpic_trace |
No |
#~POOL_MODE |
No |
#~destination.name |
No |
#~jco.client.ashost |
No |
#~jco.client.sysnr |
No |
#~jco.client.trace |
No |
#~jco.client.client |
No |
#~jco.destination.expiration_time |
No |
#~jco.client.passwd |
Yes |
#~jco.client.r3name |
No |
#~jco.destination.pool_capacity |
No |
#~QOP_TEXT |
No |
#~jco.client.abap_debug |
No |
#~jco.client.lang |
No |
#~jco.client.type |
No |
#~jco.client.user |
No |
#~jco.destination.max_get_client_time |
No |
#~jco.destination.peak_limit |
No |
#~CONNECTION_MODE |
No |
The destination’s name was found in a VSTR column. The parameter’s called “#~destination.name.” We got all parameters with the same CID and discovered “#~jco.client.passwd” and “#~jco.client.user.” It’s the credentials of the external system, but the password is encrypted.
Parameter |
Secure Flag |
---|---|
#~jco.client.passwd |
01 01 1C CA 38 1D FB 8C 83 4E 5C B2 06 04 B6 BC 1F 2D 7B B0 10 15 4A 0F 82 BF C8 C1 AD 88 10 60 CC 37 |
Since the password is used to connect to external systems, the value of the encrypted data could not be hashed. Nonetheless, we cannot be completely sure. To check it, we created several other destinations with different passwords and logins.
What did we reveal? The data is not a value’s hash, it does not depend on the username, system time, or anything else. The same passwords have the same encrypted appearance. It’s an interesting fact that the ciphertext consists of the static and dynamic parts. You can see our attempts in the table below:
As we have already mentioned, reversing Java applications is easy enough as it’s possible to decompile them and receive readable code. We started analyzing the Java code to find where the data became encrypted. At last, we got it. One variable looked so familiar:
Yes, it’s a static part of ciphertext. More steps were taken, and we detected the algorithm «PbeWithSHAAnd3_KeyTripleDES_CBC» we have described before.
Let’s check our findings. We have a ciphertext and know an algorithm, but the key remains undisclosed. When secure data from the database was being decrypted, methods such as “getSecretKey” were called from the “com.sap.security.core.server.secstorefs” and “com.sap.engine.core.configuration.impl.security” packages. It seems that our system tried to access our Java Secure Storage file and attain the Secret Key.
Our assumptions turned out to be correct. The key for Java Secure Storage in the file system and the key for encrypted data in “J2EE_CONFIGENTRY” table are the same.
Now we can decrypt every required value from this table. Do you remember the static part of the ciphertext? It's always the same: «ABCDEFGHIJKLMNOP ».
Eventually, we got the credentials and now can use them to access the external SAP system. An account used for remote function calling usually has special privilege permissions. It’s significant to keep in mind these connections since an attacker can compromise a peripheral system and get access to the main system by-passing its secure options. As they say, the system is as secure as the least protected element.
We wrote a special tool:
Defense
- Restrict access to the individual key file SecStore.key and SecStore.properties. Once an attacker gains access to this file, they will know the encryption key that allows decrypting Secure Storage data.
- Don’t store any credentials in SAP RFC Destinations. In case it is impossible, create a special user in the target system with low-level privileges to make a connection. This action prevents the damage and reduces the potential loss.
- Monitor your SAP system regularly for various vulnerabilities and misconfigurations to prevent attackers from accessing your database.