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:

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.

Image title

Version is highlighted in yellow and significant bytes are highlighted in green.


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:

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.

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

 

 

 

 

Top