In this article about SAP security topics, we continue exploring the HANA SQL Command Network Protocol, now looking into password-based authentication mechanisms and how to protect traffic with the use of
TLS. The following is the second installment in our three-part series covering SAP HANA SQL Command Network Protocol. It is recommended you read the first installment in the series if you missed it: Exploring the SAP HANA SQL Command Network Protocol – Protocol Basics and Authentication.
We will begin digging into the password-based authentication mechanisms offered by the HANA SQL Command Network Protocol, and its related capabilities. We will also show how the packet crafting capabilities can be leveraged to, for example, validate credentials against a HANA server.
As already mentioned in the first part of this blog posts series, password-based authentication in HANA is implemented with the use of the
SCRAM scheme with different algorithms. In this authentication mechanism, the password is not transmitted from the client to the server, and instead a challenge-and-response flow is used. The use of this authentication mechanism provides protection against eavesdroppers, as observing the traffic does not provide the ability to recover plain passwords, and enables the ability to store salted hashed versions of the user’s password if required. Although we haven’t found this in use by the official HDB clients, they should be able to do so to decrease the potential impact of an information leak or compromise.
The authentication methods available in the latest SAP HANA version are
SCRAM-based methods such as SCRAMMD5 were at some point included and supported by the protocol but are not available in current versions of the product.
As part of latest pysap release we included an example script that implements the authentication methods supported in the library, and can be used to understand the process of connecting to the server and performing the handshake. Extending the script, for example, to implement a password spraying, brute-force or other type of online password attack should be quite easy.
examples/hdb_auth.py -d hxehost -p 39013 --username SYSTEM --password Passw0rd --method SCRAMSHA256 -v [*] Using authentication method SCRAMSHA256 [*] Connected to HANA database hxehost:39013 [*] HANA database version 0/protocol version 0 [*] Successfully authenticated against HANA database server [*] Connection with HANA database server closed
Authentication attempts with username and password are also governed by very comprehensive password policies. The passwords are subject to complexity, customizable deny-lists, and lockout settings. While the industry is moving along from enforcing password complexity and instead focusing on layering up MFA (Multi-Factor Authentication) and risk checks, the values for those policies are acceptable as delivered by default in recent HANA versions.
From an offensive security standpoint, checking weak and/or default passwords is one of the first items to “tick” on the assessment checklist. Doing so in a up-to-date and properly configured HANA server might result in users’ accounts blocked, so this exercise should be performed with proper care.
The operation of the HANA Database requires the presence of certain users, that are generally created at installation or upgrade time. There are some predefined users common to most HANA deployments. Some of those predefined user accounts are considered technical users and not meant to be used by actual persons, but instead by applications or application processes. Moreover, most of those users (for example the
SYS user account) are not allowed external access and instead are utilized as owners of system tables and such. The full list of predefined user accounts can be found in the official documentation.
A particularly interesting account is the
SYSTEM user. This user is created during the creation of a HANA Database, and like in other database engines it’s the most powerful database user. In the system database, the user has additional privileges associated with the management of tenant databases. It is advised not to use the
SYSTEM user for regular operations in the database and instead deactivate it and/or treat it as a privileged one, monitoring its usage and having it subject to PAM solutions or manual break-glass procedures.
Due to the critical nature of this user account the lockout policies were not applied to it in first versions of the HANA database. This turned out to be an issue as an adversary can perform as many passwords attempts as desired without any limitation, making password guessing attacks easier. With HANA 1.0 revision 102, SAP introduced a new configuration parameter
password_lock_for_system_user to control this behavior. The change is detailed in SAP Security Note 2216869 from 2015. While the parameter is turned on by default in new installations, it might be possible to still find it disabled in previously installed servers due to compatibility reasons.
In the same Security Note 2216869, SAP introduced an additional configuration parameter,
detailed_error_on_connect, that controls the level of information returned upon an invalid login attempt. Older HANA versions returned detailed messages when a login attempt failed, that included the reason of the authentication failure. In this context, an attacker can leverage this information to learn if a user was existent in the database or not, or if a particular user was already locked. This information can be fed back and used to narrow down brute-force or other type of password guessing attacks against the database’s users. While the
detailed_error_on_connect parameter is turned off by default in new installations, it is also common for administrators to temporarily change it during troubleshooting or disable it in non-productive environments.
The first steps are the creation of the connection object, and initialization of the communication:
In : from pysap.SAPHDB import * In : conn = SAPHDBConnection("hxehost", 39013) In : conn.connect() In : conn.initialize()
After those steps are performed, we can select the SCRAM authentication method of our choice and perform the initial handshake:
In : auth_method = SAPHDBAuthScramSHA256Method("username", "Password") In : auth_part = auth_method.authenticate(conn) In : auth_part.show() ###[ SAP HANA SQL Command Network Protocol Part ]### partkind = AUTHENTICATION partattributes= 0 argumentcount= 1 bigargumentcount= 0 bufferlength= None buffersize= 131016 \buffer \ |###[ SAP HANA SQL Command Network Protocol Authentication Part ]### | count = None | \auth_fields\ | |###[ SAP HANA SQL Command Network Protocol Authentication Field ]### | | length = None | | value = 'username' | |###[ SAP HANA SQL Command Network Protocol Authentication Field ]### | | length = None | | value = 'SCRAMSHA256' | |###[ SAP HANA SQL Command Network Protocol Authentication Field ]### | | length = None | | value = '\x00\x01 \xc6=\x87N\x19\xb6\xb9pi\xe2r\xc3_mfT\xe4\x9aW\x9c\xe2l\xe0\xe3\xfd^Ocn\x03\x7f2'
The initial exchange of packets that form the handshake is performed, and we obtained the Authentication Part to use in the last round trip. This packet piece should be included in the CONNECT message sent to the server and will mark the end of the authentication process, successful or not.
In : auth_segm = SAPHDBSegment(messagetype=66, parts=[auth_part]) In : auth_request = SAPHDB(segments=[auth_segm]) In : auth_response = conn.sr(auth_request) In : auth_response.show() ###[ SAP HANA SQL Command Network Protocol ]### sessionid = -1 packetcount= 0 varpartlength= 80 varpartsize= 29968 noofsegm = 1 packetoptions= Uncompressed reserved1 = 0 compressionvarpartlength= 0 reserved2 = 0 \segments \ |###[ SAP HANA SQL Command Network Protocol Segment ]### | segmentlength= 80 | segmentofs= 0 | noofparts = 1 | segmentno = 1 | segmentkind= Error | reserved4 = '' | \parts \ | |###[ SAP HANA SQL Command Network Protocol Part ]### | | partkind = ERROR | | partattributes= 0 | | argumentcount= 1 | | bigargumentcount= 0 | | bufferlength= 40 | | buffersize= 29928 | | \buffer \ | | |###[ SAP HANA SQL Command Network Protocol Error Part ]### | | | error_code= 10 | | | error_position= 0 | | | error_text_length= 21 | | | error_level= ERROR | | | sql_state = '28000' | | | error_text= 'authentication failed'
The result here denoted that the authentication was failed, probably due to an invalid password or inexistent user. However, repeating the process with a deactivated or locked user results in a different error text returned by the server.
In : conn = SAPHDBConnection("hxehost", 39013) ...: conn.connect() ...: conn.initialize() ...: auth_method = SAPHDBAuthScramSHA256Method("DEACTIVATED", "Password") ...: auth_part = auth_method.authenticate(conn) ...: auth_segm = SAPHDBSegment(messagetype=66, parts=[auth_part]) ...: auth_request = SAPHDB(segments=[auth_segm]) ...: auth_response = conn.sr(auth_request) ...: auth_response.segments.parts.buffer.show() ...: ###[ SAP HANA SQL Command Network Protocol Error Part ]### error_code= 415 error_position= 0 error_text_length= 80 error_level= ERROR sql_state = 'HY000' error_text= 'user is deactivated: DEACTIVATED was explicitly deactivated by administrator 'In : conn = SAPHDBConnection("hxehost", 39013) ...: conn.connect() ...: conn.initialize() ...: auth_method = SAPHDBAuthScramSHA256Method("LOCKED", "Password") ...: auth_part = auth_method.authenticate(conn) ...: auth_segm = SAPHDBSegment(messagetype=66, parts=[auth_part]) ...: auth_request = SAPHDB(segments=[auth_segm]) ...: auth_response = conn.sr(auth_request) ...: auth_response.segments.parts.buffer.show() ...: ###[ SAP HANA SQL Command Network Protocol Error Part ]### error_code= 416 error_position= 0 error_text_length= 174 error_level= ERROR sql_state = 'HY000' error_text= 'user is locked; try again later: lock time for user LOCKED is 1440 minutes; user is locked until 2020-08-05 15:27:21.4830000 (given in UTC) [1440,2020-08-05 15:27:21.4830000]'
Fortunately, the SAP HANA database services almost natively support protecting the traffic with modern cryptographic protocols. Opposed to other proprietary protocols that do not support encryption, integrity protection and strong authentication, or that require the use of custom proprietary protocols (such as SNC), the SAP HANA SQL Command Network Protocol can be configured to run on top of
We are not going to enter into the details about its configuration, as documentation can be found in SAP’s official Help portal. From a packet crafting angle, it is important to mention that no special handshake or communication exchange needs to be performed, instead just wrapping the socket connection with TLS is enough. We added that support in
pysap by means of the SAPHDBTLSConnection Python class.
from pysap.SAPHDB import SAPHDBTLSConnection
conn = SAPHDBTLSConnection("hxehost", 39013, tls_cert_trust=True)
Be aware that, as a matter of good practice, pysap’s code tries to validate the server certificate by default. That behavior, as well as a set of additional settings such as the protocol version and cipher suites to use, can be customized with the tls_* parameters when initializing the connection class.
Even though the hdbsql client help and other documentation refers to the use of
TLS as an “encryption” protection, it’s important to mention that the use of TLS-protected channels to connect to HANA database instances can provide additional guarantees if configured properly. In particular, with good and trusted server certificates it can help prevent man-in-the-middle and server impersonation attacks, properties that as already mentioned are not granted by the protocol’s authentication on its own due to the lack of a binding mechanism. The addition of client certificates can provide strong mutual authentication as well, which is generally desired when dealing with business data at scale.
TLS traffic is also possible using our Wireshark plugin, provided the right keys are available and configured in the tool. SAP HANA and other systems use a proprietary file format to store and encrypt cryptographic material, called “Personal Security Environment” (
PSE). We are going to keep the details about this file format and the overall topic of SAP’S cryptographic libraries for future blog posts, but we wanted to show how the private keys can be exported from a HANA server so traffic can be decrypted in Wireshark. For the curious readers more information about this topic can be found in our Hunting crypto secrets in SAP systems presentation at the Troopers 2018 Security Conference.
The HANA server generally keeps private keys used by TLS-enabled HANA SQL Command Network Protocol traffic in the
sapsrv.pse file, usually available on path
/usr/sap/<SID>/HDB<instance-no>/<host>/sec/sapsrv.key. As an example, we are going to use
sapgenpse tool and
openssl to extract the private key used for TLS communications with the following commands:
/usr/sap/<SID>/HDB<instance-no>/<host>/sec> sapgenpse export_p12 -p sapsrv.pse sapsrv.p12 Please enter PKCS#8 encryption password: ************ For verification, please reenter password: ************/usr/sap/<SID>/HDB<instance-no>/<host>/sec> openssl pkcs12 -nodes -nocerts -in sapsrv.p12 Enter Import Password: MAC verified OK Bag Attributes localKeyID: 01 00 00 00 friendlyName: sapsrv Key Attributes: <No Attributes> -----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC+QAKwMYv2Xk0W K3x2APnX54X2CnKrq73Il/nHV8Yrd5rnYU1BLX5FBeOB4oeUtAp2C3cyx39MT6fS <..> 2aSOKD0mfnwxZglbaxcuTcFzO9ESEw6hfAda8IJ4hHbINLk8qXmSU28Sq0m455ne diRJUNZ66msgofdYlHhywSbdTQ== -----END PRIVATE KEY-----
With the first command we exported the X.509 certificate from the PSE file into a PKCS#12 formatted one, and then with the use of openssl we extracted the certificate’s private key in DER format and without encryption. The private key can then be configured in Wireshark for TLS traffic decryption, via the RSA Keys option under Preferences:
It is important also to mention that, for Wireshark to decrypt the
TLS traffic, certain conditions need to be fulfilled:
- The key should be an
- The negotiated cipher suite needs to not use
- The protocol version needs to be less than
We have included those settings as default when establishing a
TLS connection using
pysap but captures from traffic between other clients and servers might not work. The use of modern
TLS protocol versions and cipher suites is recommended to avoid these type of potential issues and provide forward secrecy.
Finally, as the same port numbers are used for both
TLS-protected and unprotected traffic by HANA, we added the protocol as a “Decode As” option in Wireshark. If the decrypted traffic is not shown in Wireshark, try setting a “Decode As” rule for the
TLS port you are dissecting and set it to the proper
In a first article we shared the basis about the HANA SQL Command Network Protocol and the different authentication mechanisms supported. In this post, we shared some details about how password-based authentication is implemented in the network protocol, some of the built-in protections in it, and the use of our tools to manually craft packets and perform the authentication handshake to communicate with it. Finally, we reviewed how
TLS-protected traffic can be decrypted and dissected.
Read the complete posts in this series: