This series of articles will continue our EAS-SEC Guide for secure development that is aimed to unveil all the most important types of vulnerabilities in ABAP applications. At first, we would like to shed a light on SAP SQL Injections.
At the moment, SQL injection is one of the most common injection vulnerabilities in general and in ABAP as well.
It consists of the insertion of a malicious SQL query crafted by an attacker into an entry field of an application. Via SQL injection, an attacker can affect database in different ways: to read sensitive data, modify content, or even shutdown the database.
In ABAP, there are several statements where SQL injection can occur:
- Open SQL Injections in SQL Statements (read more below).
- Injections in System functions.
- ADBC Injections.
- AMDP Injections.
Open SQL Injections
As the name implies, SQL injections can occur in Open SQL statements: SELECT, WHERE, FROM UPDATE, DELETE, and INSERT.
Here is an example of a potentially dangerous piece of code:
PARAMETERS input TYPE string. DATA table1 TYPE string. DATA fieldlist TYPE string. DATA (sql_cond) = `some_field = '` && input && `'`. SELECT fieldlist FROM table1 WHERE (sql_cond).
In this example, in the WHERE statement a user-controlled parameter input is used. If an attacker is able to define data reading criteria, he or she will be able to get access to critical data.
An attacker can pass the string ‘anything’ OR ‘1’=’1’ to the variable input. As a result, the SQL statement will look as follows:
SELECT fieldlist FROM table1 WHERE some_field =’anything’ OR '1=1'
As ‘1’=’1′ is always true, all records from the database will be shown. Besides, an attacker can use a UNION statement to combine two different SQL requests and get data from other tables.
Injections in System Functions
Another dangerous construction is related to the system functions “C_DB_EXECUTE” and “C_DB_FUNCTION”. These functions are used to call for database commands directly:
PARAMETERS STMT(65535) TYPE C. CALL 'C_DB_EXECUTE‘ ID 'STATLEN‘ FIELD LN ID 'STATTXT‘ FIELD STMT ID 'SQLERR‘ FIELD SQL_CODE ID 'ERRTXT‘ FIELD SQL_MSG ID 'ROWNUM‘ FIELD ROW_NUM.
The field ‘STATTXT‘ contains a SQL statement. The variable STMT is declared as a parameter and transmitted to this field. Therefore, an attacker can pass a specially crafted SQL statement to the variable STMT and reach the malicious goals by executing it.
Methods “EXECUTE_UPDATE”, “EXECUTE_DDL” and “EXECUTE_QUERY” of the “CL_SQL_STATEMENT” class also can be sources of SQL injections:
PARAMETERS: ld_STMNT TYPE STRING. DATA: ld_RESULT_SET TYPE REF TO CL_SQL_RESULT_SET. DATA: lo_STATEMENT TYPE REF TO CL_SQL_STATEMENT. CALL METHOD lo_STATEMENT->EXECUTE_QUERY( EXPORTING STATEMENT = ld_STMNT RECEIVING RESULT_SET = ld_RESULT_SET ).
By exploiting a SQL injection vulnerability, an attacker can get access to business-critical information or system data. Moreover, a denial of service attack can be performed by executing a complicated SQL statement. For example, a perpetrator can pass a query, which will search for a certain pattern through all the records in the database (via a LIKE statement). This query will take a long time to run and, at the same time, will significantly increase the server load, thus blocking access to the application for legitimate users.
SAP ADBC Injections
There is also a risk of a SQL injection when ABAP Database Connectivity (ADBC) is used. SQL statements are passed as strings to the objects of the ADBC class and then to the database system. An attack is possible if all parts of one of these SQL statements originate from outside of the program to the following methods:
DATA key TYPE string. cl_demo_input=>request( CHANGING field = key ). TRY. DATA(result) = NEW cl_sql_statement( )->execute_query( `SELECT carrname ` && `FROM scarr ` && `WHERE mandt = ` && `'` && sy-mandt && `' AND` && ` carrid = ` && `'` && key && `'` ).
The variable ‘key’ passes from a request to the method ‘execute_query’ without validation. An attack example is similar to one described in the Open SQL injection section.
SAP AMDP Injections
With new power comes new responsibility; thus, when working with the most powerful database, namely SAP HANA, you have to pay close attention to its security.
When ABAP Managed Database Procedures (AMDP) is used, database procedures are created and called that are currently implemented in SQLScript for the SAP HANA database. Risks are incurred whenever a database procedure contains dynamic parts.
CLASS cl_dyn_amdp IMPLEMENTATION. METHOD increase_seatsocc BY DATABASE PROCEDURE FOR HDB LANGUAGE SQLSCRIPT. EXEC 'UPDATE sflight SET seatsocc = seatsocc + ' || :seats; ENDMETHOD. ENDCLASS.
This method uses the SQLScript statement EXEC in the SAP HANA database to execute a SQL specified as a character string into which the input parameter seats are merged. In this example, the value in the SEATSOCC column is increased by the value of the parameter seats, which is passed unchecked. An attacker can send the string
2, seatsmax = seatsmax + 10 to this parameter and change the value in the SEATMAX column as well. A method like this should be classified as a potential risk since the input parameter is not checked. If possible, an input check should be implemented in the SQLScript directly before the statement EXEC is executed.
SAP SQL Injection Protection
To protect an ABAP code from SQL injections, primarily, you need to make sure that dynamically generated statements are necessary for your code (actually, this applies to all injections). In some cases, you can transform the program so they will not be required. For example, use the listing of tables (FROM … table1 … tableN …) instead of the table catalog (FROM …(tablecatalog)…).
If it is not possible, filter user input via special methods QUOTE_STR and QUOTE of the CL_ABAP_DYN_PRG class. In ABAP, strings are usually enclosed with backticks (‘) and char arrays are usually enclosed in single quotation marks (‘). Use different methods of CL_ABAP_DYN_PRG depending on the type of enclosing symbol: use QUOTE_STR with backticks and QUOTE with single quotation marks.
PARAMETERS: sel_list TYPE c, frfield TYPE c. DATA: li_bseg TYPE string. CONCATENATE 'bukrs ' 'belnr ' 'dmbtr ' frfield INTO sel_list. DATA: sel_list_8507961 LIKE sel_list. sel_list_8507961 = CL_ABAP_DYN_PRG=>QUOTE( sel_list ). SELECT bukrs FROM (sel_list_8507961) UP TO 100 ROWS INTO li_bseg. ENDSELECT.
Note: CL_ABAP_DYN_PRG=>ESCAPE_QUOTES_STR and CL_ABAP_DYN_PRG=>ESCAPE_QUOTES methods can also be used to filter data, but they provide less security.
In terms of ADBC, the values transmitted to the database can be parameterized to avoid a SQL injection. To specify parameters, it is necessary to use the character “?” (placeholder). Before SQL expression execution, all parameters must be filled. The filling of parameters is carried out through the SET_PARAM method with specifying of the link to a variable. At the same time, by default, the filling of parameters happens in turn, from left to right, in the SQL expression. After the SQL expression execution, all assignments of the parameters are lost.
DATA key TYPE string. cl_demo_input=>request( CHANGING field = key ). TRY. DATA(sql) = NEW cl_sql_statement( ). sql->set_param( REF #( sy-mandt ) ). sql->set_param( REF #( key ) ). DATA(result) = sql->execute_query( `SELECT carrname ` && `FROM scarr ` && `WHERE mandt = ? AND carrid = ?` ). DATA name TYPE scarr-carrname. result->set_param( REF #( name ) ). result->next( ). cl_demo_output=>display( name ). CATCH cx_sql_exception INTO DATA(err). cl_demo_output=>display( err->get_text( ) ). ENDTRY.
That’s all for today, and I hope the article clarified all questions you wanted to learn about SAP SQL injections.