В языке ABAP есть реализация паттерна «снимок» (Memento), цель которого сохранять и восстанавливать состояния объектов. Под состоянием понимается значения всех его атрибутов. Используя данный паттерн можно считать PROTECTED и PRIVATE атрибуты и изменять из значения в произвольном объекте.
Паттерн «Снимок»
Для сохранения состояния объекта используется системный вызов SYSTEM-CALL OBJMGR GET STATE, который записывает атрибуты класса в специальную сгенерированную структуру. Для восстановления объекта из структуры используется SYSTEM-CALL OBJMGR SET STATE.
Использование системных вызовов из клиентского кода настоятельно не рекомендуется, поэтому SAP предоставил специальный класс CL_OS_STATE. Ниже пример его использования.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
CLASS lcl_example DEFINITION. PUBLIC SECTION. METHODS constructor IMPORTING iv_value TYPE i. METHODS print. PRIVATE SECTION. DATA mv_value TYPE i. ENDCLASS. CLASS lcl_example IMPLEMENTATION. METHOD constructor. mv_value = iv_value. ENDMETHOD. METHOD print. WRITE / |Value = { mv_value }|. ENDMETHOD. ENDCLASS. START-OF-SELECTION. DATA lo_foo TYPE REF TO lcl_example. DATA lo_bar TYPE REF TO lcl_example. DATA lo_memento TYPE REF TO cl_os_state. lo_foo = NEW #( 100 ). lo_bar = NEW #( 200 ). lo_memento = NEW #( ). lo_memento->set_state_from_object( lo_foo ). lo_memento->set_object_from_state( lo_bar ). lo_bar->print( ). " WRITE: Value = 100 |
При создании снимка, данные сохраняются в специальную сгенерированную структуру.
Зная внутренности структуры данных и имея доступ к ней, можно получить копию атрибутов произвольного объекта. Изменив структуру и восстановив снимок в объект, мы изменим атрибуты объекта.
Иными словами, получив доступ к структуре снимка мы получим доступ на чтение и на запись к атрибутам класса.
Структура данных «Снимка»
Структура данных снимка находится в атрибуте CL_OS_STATE->STATE. Данный атрибут имеет публичную зону видимости, т.е. доступ к нему открыт вне класса.
Ссылка на STATE имеет 2 вложенные структуры: в первой перечислены PROTECTED и PRIVATE поля, во второй PUBLIC поля. Порядок полей соответствует порядку определения их в классе. Если класс наследуется от другого класса, то сначала перечисляются атрибуты родительских классов, затем дочерних.
Теперь, зная структуру STATE, можно сделать пример, демонстрирующий чтение и запись PRIVATE атрибутов
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
CLASS lcl_example DEFINITION. PUBLIC SECTION. METHODS constructor IMPORTING iv_bar TYPE i iv_foo TYPE string. METHODS print. PRIVATE SECTION. DATA mv_bar TYPE i. DATA mv_foo TYPE string. ENDCLASS. CLASS lcl_example IMPLEMENTATION. METHOD constructor. mv_bar = iv_bar. mv_foo = iv_foo. ENDMETHOD. METHOD print. WRITE / |bar={ mv_bar }; foo={ mv_foo }|. ENDMETHOD. ENDCLASS. START-OF-SELECTION. TYPES: BEGIN OF lts_state, bar TYPE i, foo TYPE string, END OF lts_state. FIELD-SYMBOLS <ls_state> TYPE lts_state. DATA lo_object TYPE REF TO lcl_example. DATA lo_memento TYPE REF TO cl_os_state. lo_object = NEW #( iv_bar = 100 iv_foo = 'Im private' ). lo_object->print( ). " bar=100; foo=Im private lo_memento = NEW #( ). lo_memento->set_state_from_object( lo_object ). ASSIGN lo_memento->state->* TO <ls_state> CASTING. <ls_state>-bar = 99. <ls_state>-foo = 'Im public'. lo_memento->set_object_from_state( lo_object ). lo_object->print( ). " bar=99; foo=Im public |
Содержимое структуры STATE
Результат замены состояния
Используя RTTS, можно определять структуру произвольного объекта в Runtime и манипулировать с атрибутами в объектах без каких-либо ограничений.
Примечание. Статья носит ознакомительный характер. Описанный выше подход нарушает инкапсуляцию, не используйте его для решения практических задач.
P.S: Данная возможность не является багом или уязвимостью. Ниже официальный ответ от SAP.
Since this is only exploitable with authorization S_DELEVOP, which enables you to do almost anything anyway, there is no protection for this kind of «inside» attack or put differently. There is no protection from developers.
Присоединиться к обсуждению...