Апрель 2002


Профессионалу администратору


Пит Финнеган

Эксплуатация и защита баз данных Oracle
(Exploiting and Protecting Oracle, PenTest Limited,
by Pete Finnigan ( pete.finnigan@pentest-limited.com ))
(Часть 3)

Источник: http:// .pentest-limited.com/oracle-security.htm

От переводчика

Эта статья задумана как рабочий документ, который планируется постоянно расширять в сотрудничестве со всеми заинтересованными специалистами в области баз данных Oracle и информационной безопасности вообще. Интерес к данной тематике несомненно связан не только со все возрастающей компьютеризацией общества, включая потенциальных злоумышленников, но и с ростом промышленного применения баз данных Oracle в России. Перевод дается с некоторыми сокращениями.

От редакции "Oracle Magazine/Русское Издание"

Первая и вторая части этой статьи опубликованы соответственно в мартовском и апрельском выпусках OM/RE за 2002 год.

Оглавление 3-й части:

В следующем выпуске:

  • Средства “старения” паролей в Oracle 8i
  • Встраивание “троянских коней”
  • Утилита PL/SQL wrap
  • Как Oracle хранит информацию о всех объектах пользователей базы данных
  • Функция DBMS_SYS_SQL.PARSE_AS_USER
  • Дамп внутренних структур Oracle
  • Отладчик oradebug
  • Доступ к Oracle без соединения
  • Отладчик PL/SQL
  • Пакет трассировки PL/SQL
  • Пакет профилирования PL/SQL
  • Встроенный пакет UTL_FILE
  • Недокументированные интерфейсы ‘C’
  • x$- и $-таблицы и системное табличное пространство
  • Другие “слабые места” Oracle
  • Полезные ссылки
  • Библиография
  • Заключение

 

Файлы с открытым доступом по чтению и файлы, выполняемые с правами владельцев (SUID- и SGID-файлы)

В ORACLE_HOME всегда нужно проверять файлы с открытым для всех пользователей доступом по чтению. Особое внимание следует уделять трассировочным файлам, журнальным файлам, реальным файлам данных баз данных, архивным журнальным файлам и любым экспортным файлам. Всегда важно проверять каталоги, в которые записываются протоколы, /tmp-каталоги и все каталоги, куда могут помещаться резервные копии и экспортные файлы. В трассировочных файлах можно находить (например, командой UNIX grep) операторы ALTER USER, CREATE USER и GRANT CONNECT. В экспортных файлах можно обнаружить имена пользователей и пароли в открытом тексте, которые иногда вставляются для связей баз данных. Кроме того, из экспортных файлов можно извлекать хешированные пароли.

В некоторых выполняемых модулях Oracle существует ряд хорошо документированных “дыр”, которые позволяют эскалировать привилегии. Информацию об этом можно найти в базе данных отслеживания ошибок (bugtrack database) по адресу: .securityfocus.com.

События базы данных

Одной из важнейших внутренних функциональных характеристик РСУБД Oracle является использование событий. Oracle имеет большое количество событий, которые могут устанавливаться для изменения поведения некоторых функциональных средств РСУБД или для выдачи некоторой информации в трассировочные файлы. Кроме того, некоторые события устанавливаются при возникновении в РСУБД ошибок. Краткая информация о событиях содержится в файле $ORACLE_HOME/rdbms/mesg/oraus.msg (в инсталляции Unix). В основном события устанавливаются в диапазоне от 10000 до 10999, но некоторые – и за пределами этого диапазона.

Для установки события обычно нужно знать его точный синтаксис. Oracle не рекомендует устанавливать события без разрешения корпорации (кроме события трассировки 10046).

Их можно включать следующим образом:

SQL> alter session set events '10046 trace name context forever, level 12';

Этот оператор создает трассировочный файл 12-го уровня. Этот файл записывается в user_dump_dest и будет содержать информацию о выполняемых операторах SQL, рекурсивном SQL, событиях WAIT, а также о переменных привязки и их значениях.

Помните, что Oracle не поддерживает использование никаких событий, поэтому не пытайтесь устанавливать события в промышленной базе данных; несомненно, что установка некоторых событий может привести к ошибке “Denial of service” (отказ в обслуживании) или повреждению базы данных. События можно устанавливать под пользователем DBSNMP, если он имеет привилегию alter session.

В пакете DBMS_SYSTEM есть пара недокументированных процедур, одна из которых позволяет устанавливать любые события любого уровня, а другая – читать события, установленные в текущем сеансе. Функция установки событий вызывается следующим образом:

sys.dbms_system.set_ev
( si binary_integer,      -- sid
  se binary_integer,      -- serial#
  ev binary_integer,      -- событие
  le binary_integer,      -- уровень
  nm varchar2);         -- имя

Для вызова этой процедуры нужно разрешение на ее выполнение (execute), выдаваемое SYS. По умолчанию оно не выдается. С помощью этой процедуры можно устанавливать любое событие. Экспериментирование с событиями может привести к интересным открытиям и разрушению базы данных, так что будьте осторожны. Ниже показан фрагмент командного файла events.sql, который можно использовать для проверки установленных в сеансе событий. Этот файл можно загрузить из .pentest-limited.com.

set serveroutput on size 100000

spool event.lis
declare
   ev   binary_integer:=0;
   stat   binary_integer:=0;
begin   
   for ev in 10000..10999 loop
      sys.dbms_system.read_ev(ev,stat);
      if stat=1 then
         dbms_output.put_line
             ('event :'||ev||' value :'||stat);
      end if;
   end loop;
end;
/

spool off

После включения трассировки получаем следующее:

   
SQL> alter session set sql_trace true;
Session altered.
SQL> @events
event :10046 value :1 
PL/SQL procedure successfully completed.

Анализ размещения базы данных

Показанный ниже командный файл layout.sql может быть использован для проверки размещения основных файлов базы данных. Этот файл можно загрузить из www.pentest-limited.com. Он выдает информацию об управляющих файлах, журнальных файлах, файлах данных, используемых в табличных пространствах для фактического хранения данных, а также об установках параметров табличных пространств. Этот командный файл в общем предназначен для DBA, но может быть полезен для задач информационной безопасности, чтобы показать, где находятся все файлы и для чего они используются.

clear cols

set headoff feedback off pagesize 80 linesize 80
col filen head "Filename" for a45
col grp head "Group" for 99
col sizn head "Size (K)" for 999990
col tblsp head "Tablespace" for a18
col minextst head "Min|ext" for 999
col maxxt head "Max|ext" for 99990
col pinc head "Pct|Inc" for 99990
col rseg head 'Rollback|Segment' for a10 trunc
col ts head 'Tablespace|' for a10
col inxtt head 'Init|(K)' for 9999999
col nxt head 'Next|(K)' for 9999999
col exts head 'ext|(#)' for 99990
col sz head 'Size|(K)' for 999999
col bk for 999
col typ head 'type|' for a7

col megb head 'Size (MB)' for 9999
   
spool layout.lis
prompt   Control Files
select    name 
from       v$controlfile;
set head on
prompt   Redo Log Files
select    a.group# grp, 
      b.member filen, 
      a.bytes/1024 sizn
from       v$log a, 
      v$logfile b
where    a.group# = b.group#;
prompt   Data Files
select    tablespace_name tblsp, 
      file_name filen, 

      bytes/1048576 megb
from       sys.dba_data_files
order by tablespace_name;
prompt   Tablespace Storage
select    tablespace_name tblsp, 
      initial_extent/1024 inxtt, 
      next_extent/1024 nxt,
      min_extents minextst, 
      max_extents maxxt, 
      pct_increase pinc
from       sys.dba_tablespaces
order by tablespace_name;
select    n.name rseg, 
      r.tablespace_name ts,
      decode(r.owner,'SYS','PRIVATE',r.owner) typ,
      r.initial_extent/1024 inxtt, 
      r.next_extent/1024 nxt, 
      r.min_extents minextst,

      r. max_extents maxxt, 
      s.extents exts, 
      s.rssize/1024 sz
from       v$rollname n, 
      v$rollstat s, 
      sys.dba_rollback_segs r
where    n.usn = s.usn 
and      s.usn = r.segment_id;
set head off
select    segment_name rseg, 
      tablespace_name ts,
      decode(owner,'SYS','PRIVATE',owner) typ,
      initial_extent/1024 inxtt, 
      next_extent/1024 nxt, 
      min_extents minextst,
      max_extents maxxt, 
      0 bk, 
      status
from       sys.dba_rollback_segs

where    status != 'ONLINE';
spool off

Пример выдачи после запуска этого командного файла в базе данных под управлением ОС Windows:

Control Files
NAME 
---------------------------------------
C:\ORACLE\ORADATA\PENT\CONTROL01.CTL 
C:\ORACLE\ORADATA\PENT\CONTROL02.CTL 
Redo Log Files
Group Filename Size (K) 
----- --------------------------------- ---- 
1     C:\ORACLE\ORADATA\PENT\REDO04.LOG 1024 
2     C:\ORACLE\ORADATA\PENT\REDO03.LOG 1024 
3     C:\ORACLE\ORADATA\PENT\REDO02.LOG 1024 
4     C:\ORACLE\ORADATA\PENT\REDO01.LOG 1024 
Data Files

Tablespace     Filename                            Size (MB) 
-------------- ----------------------------------- --------- 
INDX           C:\ORACLE\ORADATA\PENT\INDX01.DBF           2 
OEM_REPOSITORY C:\ORACLE\ORADATA\PENT\OEMREP01.DBF         5 
RBS            C:\ORACLE\ORADATA\PENT\RBS01.DBF           25 
SYSTEM         C:\ORACLE\ORADATA\PENT\SYSTEM01.DBF       140 
TEMP           C:\ORACLE\ORADATA\PENT\TEMP01.DBF           2 
USERS          C:\ORACLE\ORADATA\PENT\USERS01.DBF          3 
6 rows selected.
Tablespace Storage
              Init Next Min Max Pct 
Tablespace     (K) (K)  ext ext Inc 
-------------- --- ---- --- --- ---
INDX           10  10    1  121 50 
OEM_REPOSITORY 10  10    1  121 50 
RBS            10  10    1  121 50 
SYSTEM         10  10    1  121 50 
TEMP           10  10    1  121 50 
USERS          10  10    1  121 50 
6 rows selected.
RollbackTable type   Init Next Min Max ext Size 

Segment space         (K) (K)  ext ext (#) (K) 
------ ------ ------- --- --- ---- --- --- ------
SYSTEM SYSTEM PRIVATE 50  50     2 121   8 398 
RB1    RBS    PUBLIC 100 250     2 121   3 598 
RB2    RBS    PUBLIC 100 250     2 121   3 598 
RB3    RBS    PUBLIC 100 250     2 121   3 598 
RB4    RBS    PUBLIC 100 250     2 121   3 598 
RB5    RBS    PUBLIC 100 250     2 121   3 598 
RB6    RBS    PUBLIC 100 250     2 121   3 598 
RB7    RBS    PUBLIC 100 250     2 121   3 598 
RB8    RBS    PUBLIC 100 250     2 121   3 598 
RB9    RBS    PUBLIC 100 250     2 121   3 598 
RB10   RBS    PUBLIC 100 250     2 121   3 598 
RB11   RBS    PUBLIC 100 250     2 121   3 598 
RB12   RBS    PUBLIC 100 250     2 121   3 598 
RB13   RBS    PUBLIC 100 250     2 121   3 598 
RB14   RBS    PUBLIC 100 250     2 121   3 598 
RB15   RBS    PUBLIC 100 250     2 121   3 598 
16 rows selected.
RB_TEMP SYSTEM PRIVATE 100 100 10 1024 0 OFFLINE 
RB16    RBS    PUBLIC  100 250  2  121 0 OFFLINE 
RB17    RBS    PUBLIC  100 250  2  121 0 OFFLINE 

RB18    RBS    PUBLIC  100 250  2  121 0 OFFLINE 
RB19    RBS    PUBLIC  100 250  2  121 0 OFFLINE 
RB20    RBS    PUBLIC  100 250  2  121 0 OFFLINE 
RB21    RBS    PUBLIC  100 250  2  121 0 OFFLINE 
RB22    RBS    PUBLIC  100 250  2  121 0 OFFLINE 
RB23    RBS    PUBLIC  100 250  2  121 0 OFFLINE 
RB24    RBS    PUBLIC  100 250  2  121 0 OFFLINE 
10 rows selected.

Все это может использоваться совместно с проверкой размещения трассировочных и архивных журнальных файлов в качестве отправной точки для проверки прав доступа к файлам, чтобы убедиться, что никакие файлы нельзя копировать или читать. Экспортные файлы будут рассмотрены в разделе “Журнальные, трассировочные, экспортные, сигнальные и управляющие файлы”. Место размещения трассировочных и архивных журнальных файлов можно найти с помощью следующих команд. Контроль включения режима ARCHIVELOG был рассмотрен в разделе “Резервные копии баз данных и базы данных разработчиков” (см. Часть 1 в мартовском номере OM/RE).

SQL> sho parameter arch
log_archive_dest string 
log_archive_dest_1 string 
log_archive_dest_2 string 
log_archive_dest_3 string 
log_archive_dest_4 string 
log_archive_dest_5 string 
log_archive_dest_state_1 string enable 
log_archive_dest_state_2 string enable 

log_archive_dest_state_3 string enable 
log_archive_dest_state_4 string enable 
log_archive_dest_state_5 string enable 
log_archive_duplex_dest string 
log_archive_format string ARC%S.%T 
log_archive_max_processes integer 1 
log_archive_min_succeed_dest integer 1 
log_archive_start boolean FALSE 
optimizer_search_limit integer 5 
standby_archive_dest string %ORACLE_HOME%\RDBMS 
SQL> sho parameter user_dump_dest
user_dump_dest string C:\Oracle\admin\PENT 
SQL> spool off

Как видите, архивные журнальные файлы могут быть обнаружены в разных местах. В этой простой инсталляции базы данных под Windows режим архивирования (ARCHIVELOG) не включен и параметр log_archive_dest, указывающий место размещения архивных журнальных файлов, не установлен.

Сбор данных с помощью триггеров

Можно читать данные из таблицы, которая принадлежит другому пользователю, не имея никаких привилегий для доступа к этой таблице!!! Вся хитрость заключается в использовании триггеров. Мы позаимствовали эту идею в книге Oracle Security ( http:// .oreilly.com/catalog/orasec/), с. 103-105, издательства http:// .oreilly.com/, но пример в этой книге некорректен по двум причинам. В коде создаваемого триггера опущено ключевое слово, поэтому код в действительности не работает. Автор указывает, что пользователю ralph назначены только роли CONNECT и RESOURCE, и роль RESOURCE имеет привилегию CREATE TRIGGER. Затем дается пример, в котором пользователь ralph, не имеющий никаких привилегий для доступа к таблице пользователя mary, создает триггер для этой таблицы.

Однако это не годится для Oracle 8i, и, скорее, относится к Oracle 7.2.3, но не работает и там. Причина заключается в том, что для создания триггеров для любой таблицы требуется на самом деле привилегия CREATE ANY TRIGGER (исключая создание триггеров пользователем SYS в своей схеме), а такой привилегии у роли RESOURCE нет. В стандартной инсталляции Linux никакие пользователи, исключая DBA, не получают такой привилегии, а в Windows NT пользователь MDSYS получает. Возможно, что существуют и другие пользователи, имеющие эту привилегию.

Итак, данная уловка будет срабатывать, пока пользователь или назначенная ему роль имеют системную привилегию CREATE ANY TRIGGER. Для демонстрации приведем фрагмент кода и пример его выполнения.

spool trig.lis
connect outln/outln

create table pxf_test
     (col_01   number(2),col_02   varchar2(10));
insert into pxf_test
     (col_01,col_02)values(1,'secret');
--
-- никому и ничего не выдавайте для этой таблицы
--
connect mdsys/mdsys
--
-- создадим таблицу для сбора данных
--
create table pxf_secret
     (col_01 number(2),col_02 varchar2(10),col_03 varchar2(1));
grant select,insert,update on pxf_secret to public;
--
-- создадим триггер для этой таблицы
--
create or replace trigger pxf_trig
before insert or update or delete
on outln.pxf_test
for each row
declare
   act    varchar2(1);
   id   number(2);
   txt   varchar2(10);

begin
   if inserting then
      act:='I';
      id:=:new.col_01;
      txt:=:new.col_02;
   elsif updating then
      act:='U';
      id:=:old.col_01;
      txt:=:new.col_02;
   elsif deleting then
      act:='D';
      id:=:old.col_01;
      txt:=:old.col_02;
   end if;
   insert into pxf_secret(col_01,col_02,col_03)
   values(id,txt,act);
end;
/
connect outln/outln
insert into pxf_test(col_01,col_02)
values(2,'what is it');
connect mdsys/mdsys
select * from pxf_secret;
spool off

После запуска этого кода получим следующие результаты:

Connected.
Table created.
1 row created.
Connected.
Table created.
Grant succeeded.
Trigger created.
Connected.
1 row created.
   
Connected.
COL_01 COL_02     C 
------ ---------- - 
2      what is it I 

Как видно, можно создать триггер как пользователь MDSYS, даже если он не имеет никаких прав доступа к таблице PXF_TEST в схеме пользователя OUTLN, и все изменения будут перехватываться и сохраняться. Из этого можно извлечь два урока:

  • никому не выдавайте системную привилегию CREATE ANY TRIGGER, если этого явно не требуется;
  • регулярно проверяйте в базе данных триггеры и другие объекты, которых там не должно быть.

Журнальные, трассировочные, экспортные, сигнальные и управляющие файлы

Существует ряд выходных файлов, которые могут быть использованы для получения информации о действующей базе данных. Большая часть этих файлов должна быть защищена, и они не должны быть доступными для чтения, но их нужно проверять и пробовать извлекать из них информацию.

Экспортные файлы

Экспортные файлы создаются в Oracle утилитой exp. Эта утилита используется для извлечения данных, хранящихся в отдельных объектах или всех объектах одной схемы пользователя, а также всех объектов целой базы данных. Утилита Oracle imp используется для вставки экспортированных данных назад в ту же схему базы данных, в другую схему или в другую базу данных, в зависимости от потребности.

Заголовок экспортного файла имеет следующий вид:

___EXPORT:V08.01.05
DSYSTEM
RENTIRE
2048
0   
28
4000

В этом файле хранится не чистый ASCII-текст, а комбинация ASCII-текста и двоичных данных. Если экспортный файл, который может быть скопирован, взят с базы данных, которую вы хотите атаковать, вы можете импортировать его в другую базу данных, и, поскольку это ваша база данных, вы можете читать импортированные данные. Если экспортный файл – полный экспорт, то он будет также содержать все данные и структуры всех схем базы данных, включая схему SYS. Если этот файл полностью импортировать в пустую базу данных на локальной машине, то будут доступны все данные и схема SYS, включая хешированные пароли.

Если есть возможность чтения экспортного файла и нельзя сделать его копию для дальнейшего полного импорта, то можно найти и извлечь хешированные пароли всех пользователей, чтобы попробовать угадать их. Это можно делать с помощью программы взлома или создавая пользователей в базе данных с известными хеш-значениями паролей, а затем попробовать угадать настоящие пароли. Примеры создания пользователей можно увидеть в указанном выше экспортном файле:

...
ALTER USER "SYS" IDENTIFIED BY VALUES 'B024681DBF11A33E'
ALTER USER "SYSTEM" IDENTIFIED BY VALUES 'D4DF7931AB130E37'
      DEFAULT TABLESPACE "USERS" TEMPORARY TABLESPACE "TEMP"
CREATE USER "OUTLN" IDENTIFIED BY VALUES '4A3BA55E08595C81'
CREATE USER "DBSNMP" IDENTIFIED BY VALUES 'E066D214D5421CCC'
CREATE USER "AURORA$ORB$UNAUTHENTICATED" IDENTIFIED
      BY VALUES '80C099F0EADF877E'
...

Здесь можно видеть, как Oracle, не зная пароли пользователей, для создания их в другой базе данных, использует недокументированное ключевое слово "VALUES". В экспортном файле можно просто найти (например, командой grep) все фразы IDENTIFIED BY. Если нужно похитить какие-то данные, то в экспортном файле нужно проверить наличие соответствующей таблицы, чтобы импортировать ее в свою базу данных. Извлечение данных из самого экспортного файла возможно, но это очень сложно и потребует больших затрат времени.

Журнальные файлы

Чтение журнальных файлов стало очень простым, начиная с Oracle 8i, поскольку появилось новое инструментальное средство с графическим интерфейсом, LogMiner (анализатор журналов), которое позволяет извлекать информацию из журнальных файлов. В этих файлах данные хранятся в компилированном виде, который требуется для обновления базы данных (“отката вперед” или “наката” – прим. пер.). Для того чтобы с ними можно было что-то делать, требуется их представление в виде ASCII-текста, который можно получить, сделав дамп в трассировочный файл:

   SVRMGRL> ALTER SYSTEM DUMP LOGFILE ;
   

Возможные параметры:


RBA MIN seqno.blocko 
RBA MAX seqno.blockno 
DBA MIN fileno.blockno 
DBA MAX fileno.blockno 
TIME MIN value 
TIME MAX value 
LAYER value 
OPCODE value 

(Оператор ALTER SYSTEM DUMP LOGFILE в документации Oracle не описан. – Прим. пер.)

Дамп журнальных файлов необязательно выполнять в той же базе данных, в которой они были созданы. Требуется только, чтобы версия Oracle была точно такой же. Следовательно, читать журнальные файлы можно в любом месте. Трассировочные файлы пишутся в каталог, указываемый параметром background_dump_dest, значение которого можно определить следующим образом:

SQL> sho parameter background_dump_dest

NAME                 TYPE     VALUE 
-------------------- ------- ------------------ 
background_dump_dest string  C:\Oracle\admin\PENT 

Для генерации имени выходного файла используется обычное соглашение об именовании трассировочных файлов. Чтобы убедиться, что все журнальные файлы находятся в трассировочном файле, нужно проверить, содержится ли в последней строке предложение END_OF_REDO_DUMP. Определить список журнальных файлов для дампирования можно так:

SQL> l
1* select * from v$loghist
SQL> /
THREAD# SEQUENCE# FIRST_CHANGE# FIRST_TIM SWITCH_CHANGE# 
------- --------- ------------- --------- -------------- 
1       1         137639        20-JUL-01 137785 
1       2         137785        20-JUL-01 137861 
...
...
1     104         745439        04-AUG-01 765538 
1     105         765538        04-AUG-01 785644 
1     106         785644        05-AUG-01 805746 
106 rows selected.

С помощью этого оператора можно определять имена журнальных файлов для дампа, объединяя их порядковый номер (SEQUENCE#) со значением параметра log_archive_format. В журнальных файлах можно обнаружить весь DML (Data Manipulation Language – язык манипулирования данными) и весь DDL (Data Definition Language – язык определения данных), которые выполняются в базе данных. DDL фактически трансформируется в операторы SQL, выполняемые в словаре данных для таблиц, принадлежащих SYS. Такой SQL называют рекурсивным SQL.

Таким образом, с небольшой долей удачи из журнальных файлов можно извлечь массу информации. Естественно, если также доступна “холодная резервная копия”, то повторный прогон журнальных файлов позволяет получить копию атакуемой базы данных.

Alert-файлы

Alert-файлы размещаются в каталоге, указываемом параметром background_dump_dest. В каждой базе данных может быть только один alert-файл с именем alert_[SID базы данных].log. В нем нет каких-либо интересных операторов SQL, но из него можно извлечь массу информации, если он доступен. В нем, в частности, содержится время остановки и запуска базы данных. Пример фрагмента alert-файла:

Dump file C:\Oracle\admin\PENT\bdump\pentALRT.LOG
Fri Jul 20 16:24:38 2001
ORACLE V8.1.5.0.0 - Production vsnsta=0
vsnsql=d vsnxtr=3

Windows NT V5.0, OS V8.147, CPU type 586
Starting up ORACLE RDBMS Version: 8.1.5.0.0.
System parameters with non-default values:
processes = 59
shared_pool_size = 15728640
java_pool_size = 20971520
control_files = C:\Oracle\oradata\PENT\control01.ctl,
       C:\Oracle\oradata\PENT\control02.ctl
db_block_buffers = 8192
db_block_size = 2048
compatible = 8.1.0
log_buffer = 32768
...
...

Управляющие файлы

Управляющие файлы содержат подробную информацию о всех структурах и файлах базы данных. Эти файлы не могут просто так читаться, так как они хранятся в двоичном формате, но можно сделать их дамп, а затем пересоздать базу данных или читать в дампе ASCII-текст. Оператор определения места нахождения управляющего файла:

SQL> select *
2 from v$controlfile;
STATUS 
------- 
NAME 
------------------------------------------------------
C:\ORACLE\ORADATA\PENT\CONTROL01.CTL 
C:\ORACLE\ORADATA\PENT\CONTROL02.CTL

Оператор дампа управляющего файла в трассировочный файл:

SQL> alter database backup controlfile to trace;
Данный оператор создает трассировочный файл, который имеет достаточную информацию для повторного создания управляющих файлов базы данных. Информация в этом трассировочном файле позволяет найти все ключевые файлы базы данных.

Трассировочные файлы

В Oracle предлагается множество средств трассировки. Трассировка может использоваться для самых разных целей и можно трассировать практически все события, возникающие во время работы Oracle. Трассировочные файлы могут использоваться для тайного наблюдения за другими процессами Oracle, и даже за значениями данных, используемых в PL/SQL или SQL. Трассировочные файлы могут содержать структурную информацию об атакуемой базе данных, а также о таких операторах, как alter user…, из которых можно извлечь хешированные пароли.

Трассировочные файлы размещаются в двух местах. Трассировочные файлы, создаваемые пользователями, размещаются в каталоге, указываемом параметром user_dump_dest, а файлы, создаваемые в результате сбоев, размещаются в каталоге, указываемом параметром background_dump_dest.

Трассировка может быть использована для изучения структуры и функционирования приложений, исходный код которых недоступен, например, для инъекции SQL, а также любых других целей.

Трассировочные файлы Oracle могут генерироваться для любых приложений. Существует несколько способов включения трассировки. Например, в SQL*Plus можно использовать оператор "alter session":

alter session set sql_trace=true;

Или можно использовать встроенный пакет dbms_sesion, вызывая функцию:


SQL> exec dbms_session.set_sql_trace(true); 

Или, наконец, можно использовать oradebug: сначала находится PID процесса Oracle, а затем выполняется командный файл who.sql, выдающий sid и serial# процесса, который нужно оттрассировать. Этот файл можно загрузить из .pentest-limited.com. После этого выполняются команды oradebug:

SQL> @who
STATUS   SPID USERNAME SID SERIAL# USRNAME 
-------- ---- -------- --- ------- ---------- 
ACTIVE    768 SYSTEM     1       1 
ACTIVE    776 SYSTEM     2       1 
ACTIVE    780 SYSTEM     3       1 
ACTIVE    784 SYSTEM     4       1 
ACTIVE    788 SYSTEM     5       1 
ACTIVE    756 SYSTEM     6       1 
ACTIVE    792 SYSTEM     7     629 
ACTIVE    796 SYSTEM     8     629 
INACTIVE 1192 SYSTEM    11     127 SYSTEM 
ACTIVE    604 SYSTEM    13     484 SYS 
INACTIVE 1268 SYSTEM    12      39 DBSNMP 

11 rows selected.
SQL>

Для трассировки процесса, принадлежащего DBSNMP, нужно использовать spid этого процесса. Затем используется oradebug:

SVRMGRL> oradebug setospid 1268
Statement processed
SVRMGRL> oradebug unlimit
Statement processed
SVRMGRL> oradebug event 10046 trace name context forever, level 12
Statement processed

Для представления трассировочных файлов в более удобном для чтения виде в Oracle имеется утилита tkprof, и можно написать простой командный файл, который обрабатывал бы трассировочные файлы “на лету” и позволял наблюдать за действиями базы данных в реальном времени. Это было сделано в одном проекте настройки Oracle. Перед началом трассировки имя трассировочного файла было заменено на канал (pipe), а затем трассировка была запущена с помощью oradebug. Затем канал направлялся в простой командный файл awk. Это позволило выполнять постоянную трассировку без потребления дискового пространства и наблюдать за внутренним функционированием Oracle.

Словарь данных Oracle

Oracle хранит информацию о структуре всех объектов базы данных в словаре данных. Словарь данных также содержит информацию о структуре самого словаря. В нем есть таблица DICTIONARY, которой можно воспользоваться как отправной точкой для поиска любой информации о любой таблице базы данных Oracle. Для определения детальной информации о любом объекте базы данных можно также использовать представление DBA_OBJECTS.

Проверка: кто чем владеет

Посмотреть, кто чем владеет в базе данных Oracle, очень просто. Представление, в котором это можно посмотреть, зависит от имеющихся прав доступа. Имеется набор представлений:

Представление базы данных Описание
DBA_OBJECTS Содержит информацию о всех объектах базы данных.
ALL_OBJECTS Содержит информацию о всех объектах базы данных, которые запрашивающий пользователь может видеть.
USER_OBJECTS Содержит информацию о всех объектах базы данных, которыми владеет запрашивающий пользователь.

Как читать исходный текст представлений

Представления могут быть хорошим источником информации о том, как различные таблицы в базе данных соединятся (реляционно) друг с другом. Исходный код в представлениях никогда не “свертывается” (wrapped) и может читаться из представлений DBA_VIEWS, ALL_VIEWS и USER_VIEWS. Представление DBA_VIEWS показывает все представления в базе данных, представление ALL_VIEWS показывает все представления, видимые данному пользователю, а представление USER_VIEWS показывает представления, которые принадлежат данному пользователю. Если известно имя представления, его исходный код можно прочитать, как это показано в следующем примере для представления ALL_CONSTRAINTS:

SQL> set pause off
SQL> set long 100000
SQL> set pages 0
SQL> select text from dba_views
2 where view_name='ALL_CONSTRAINTS';
select ou.name, oc.name, 
    decode(c.type#, 1, 'C', 2, 'P', 3, 'U', 
    4, 'R', 5, 'V', 6, 'O', 7,'C', '?'), 
o.name, c.condition, ru.name, rc.name, 
decode(c.type#, 4, 
decode(c.refact, 1, 'CASCADE', 'NO ACTION'), NULL), 
decode(c.type#, 5, 'ENABLED', 
decode(c.enabled, NULL, 'DISABLED', 'ENABLED')), 
decode(bitand(c.defer, 1), 1, 'DEFERRABLE', 'NOT DEFERRABLE'), 
decode(bitand(c.defer, 2), 2, 'DEFERRED', 'IMMEDIATE'), 
decode(bitand(c.defer, 4), 4, 'VALIDATED', 'NOT VALIDATED'), 
decode(bitand(c.defer, 8), 8, 'GENERATED NAME', 'USER NAME'), 

decode(bitand(c.defer,16),16, 'BAD', null), 
decode(bitand(c.defer,32),32, 'RELY', null), 
c.mtime 
from sys.con$ oc, sys.con$ rc, sys.user$ ou, sys.user$ ru, 
sys.obj$ o, sys.cdef$ c 
where oc.owner# = ou.user# 
and oc.con# = c.con# 
and c.obj# = o.obj# 
and c.type# != 8 
and c.rcon# = rc.con#(+) 
and rc.owner# = ru.user#(+) 
and (o.owner# = userenv('SCHEMAID') 
or o.obj# in (select obj# 
from sys.objauth$ 
where grantee# in ( select kzsrorol 
from x$kzsro 
) 
) 
   or /* user has system privileges */ 
    exists (select null from v$enabledprivs 
       where priv_number in (-45 /* LOCK ANY TABLE */, 
               -47 /* SELECT ANY TABLE */, 
               -48 /* INSERT ANY TABLE */, 
               -49 /* UPDATE ANY TABLE */, 
               -50 /* DELETE ANY TABLE */) 
       ) 
) 

Этот пример показывает исходный код одного из стандартных представлений, поставляемых с базой данных. Как видите, он ясно указывает на связи между различными таблицами словаря данных. Это позволяет изучать внутреннюю структуры РСУБД Oracle и, применительно к пользовательским представлениям, использовать для просмотра схем базы данных и находить нужные данные.

Кто соединен с базой данных и что он делает

Определить, кто соединен с базой данных в данное время, легко, используя приведенный ниже командный файл. Заметим, что он не показывает пользователей, которые работают с базой данных через агенты приложений Oracle, такие, как картриджы PL/SQL. Причина – пользователи соединяются с WEB-сервером и каждый картридж поддерживает свое собственное соединение с РСУБД. Все пользователи, использующие функции картриджа, разделяют один и тот же сеанс базы данных.

-- name : who.sql

-- date : Jul-2001
-- Author : Pete Finnigan
-- Описание: получить информацию о пользователях, 
-- соединенных с базой данных Oracle.
-- ограничение: требуется привилегия 
-- select для v_$process и v_$session.
--
-- использование: 
-- SQL> connect имя_пользователя/пароль @who.sql
col status for a8
col spid for a9
col username for a10
col sid for 9999
col serial# for 999999
col uname for a10
   
select    s.status,
      p.spid,
      p.username,
      s.sid,
      s.serial#,
      s.username uname
from       v$process p, 
      v$session s
where    p.addr=s.paddr
/
exit

Пример запуска этого командного файла в Windows NT:

SQL> @..\scripts\who.sql
STATUS SPID USERNAME SID SERIAL# USRNAME 
------ ---- -------- --- ------- ---------- 
ACTIVE  808   SYSTEM   1 1 
ACTIVE  816   SYSTEM   2 1 
ACTIVE  760   SYSTEM   3 1 

ACTIVE  828   SYSTEM   4 1 
ACTIVE  832   SYSTEM   5 1 
ACTIVE  844   SYSTEM   6 1 
ACTIVE  320   SYSTEM   7 2857 
ACTIVE  836   SYSTEM   8 2857 
ACTIVE 1232   SYSTEM  11 2333    DBSNMP 
9 rows selected.
SQL>

Следующий командный файл можно использовать для определения, что делает конкретный пользователь в данное время, вплоть до выполняемого в данный момент SQL. Это может быть полезно при организации атаки типа “инъекция SQL”. Можно суметь угадать, какая используется форма, но быть уверенным в этом нельзя. Использование данного командного файла позволяет увидеть точно, какой был выдан SQL. В данном случае может быть также полезна трассировка Oracle, которая с уровнем трассировки 12 позволяет видеть переменные привязки и их значения.

Файл sql.sql можно загрузить из www.pentest-limited.com.

-- name : sql.sql
-- date : Jul-2001
-- Author : Pete Finnigan
-- Описание : 
-- Получить sql, выполняемый в другом сеансе базы данных.
-- ограничение: 
-- требуется привилегия select для v_$sqltext и v_$sqlarea
--
-- использование: 
-- SQL> connect имя_пользователя/пароль @sql.sql [SID] [serial]
spool sql.lis
undefine usersid
undefine userserial
col hash_value noprint
break on hash_value skip 1 nodup
col sql_text for a64 head 'SQL Code'
set lines 132 pause off
select    sqla.hash_value,
      sqlt.sql_text
from       v$session sess,
      v$sqlarea sqla,
      v$sqltext sqlt,

      v$process proc
where sess.username is not null
and proc.addr = sess.paddr
and sess.audsid != userenv('SESSIONID')
and sess.sql_address = sqla.address
and sess.sql_hash_value = sqla.hash_value
and sqla.address = sqlt.address
and sqla.hash_value = sqlt.hash_value
and sess.sid='&&usersid'
and sess.serial#='&&userserial'
order by sess.last_call_et desc,
    sqla.address,
   sqla.hash_value,
   sqlt.piece;
clear breaks
spool off

Пример проверки, что делает пользователь DBSNMP, за которым мы следим:

SQL> @who

STATUS Process USERNAME SID SERIAL# USRNAME 
------ ------- -------- --- ------- ---------- 
ACTIVE     808   SYSTEM   1 1 
ACTIVE     816   SYSTEM   2 1 
ACTIVE     760   SYSTEM   3 1 
ACTIVE     828   SYSTEM   4 1 
ACTIVE     832   SYSTEM   5 1 
ACTIVE     844   SYSTEM   6 1 
ACTIVE     320   SYSTEM   7 3581 
ACTIVE     836   SYSTEM   8 3581 
ACTIVE    1236   SYSTEM  11 2347    SYSTEM
INACTIVE   800   SYSTEM  12 2333    DBSNMP 
10 rows selected.
SQL> @sql
Enter value for usersid: 12
old 14: and sess.sid='&&usersid'

new 14: and sess.sid='12'
Enter value for userserial: 1011
old 15: and sess.serial#='&&userserial'
new 15: and sess.serial#='1011'
SQL Code 
-------------------------------------------
select sysdate from dual 
SQL> 

Как видите, это, совместно со средствами трассировки Oracle, может быть полезным оружием для определения способа инъекции SQL в приложения Oracle. Можно написать SQL, который извлекает из SGA все операторы SQL или операторы SQL, которые чаще всего выполняются или потребляют наибольшее время. Хороший пример такого командного файла (peep.sql) можно загрузить из .oriole.com.

Выполнение аудита и проверка, включен ли он и что проверяет

Средства аудита Oracle велики и сложны. Главный вопрос для взломщика базы данных – определить, включен ли аудит и на каком уровне; это позволит ему узнать, следят ли за ним и, в случае необходимости, уничтожить журнал аудита.

Аудит Oracle может использоваться для мониторинга доступа к базе данных, а также когда выполняется доступ и откуда. Масштабный аудит Oracle постоянно не используется, поскольку он существенно влияет на производительность. При включении всех опций аудита нагрузка на базу данных удваивается.

Стандартные средства аудита Oracle не поддерживают аудит на уровне строк или записей. Для аудита на уровне строк нужно использовать триггеры базы данных. Если вы “параноик”, проверьте триггеры владельца схемы. Следующий код поможет узнать, кто имеет триггеры и для каких таблиц:

SQL> l
1 select owner,trigger_name,trigger_type,
2 triggering_event,table_name
3* from dba_triggers
SQL> /
OWNER TRIGGER_NAME     TRIGGER_TYPE 
----- ---------------- ---------------- 
TRIGGERING_EVENT 
-------------------------------------
TABLE_NAME 
------------------------------ 
SYSTEM REPCATLOGTRIG AFTER STATEMENT 
UPDATE OR DELETE 
REPCAT$_REPCATLOG 
MDSYS PXF_TRIG BEFORE EACH ROW 
INSERT OR UPDATE OR DELETE 
PXF_TEST 
SQL>

В данной тестовой базе данных нет триггеров для аудита, всего в наличии только два триггера.

Журнал аудита Oracle может записываться в базу данных или в операционную систему. Чтобы проверить, включен ли аудит, нужно проверить параметр инициализации AUDIT_TRAIL:

SQL> col name for a35
SQL> col value for a35
SQL> select name,value
2 from v$parameter
    3 where name='audit_trail';
NAME        VALUE 
----------- ----------------------------------- 
audit_trail NONE 
SQL> 

Как видите, в данной тестовой базе данных аудит не включен. Значения этого параметра могут быть следующими:

  • NONE – аудит не включен.
  • OS – аудит включен и результаты направляются в файл каталога операционной системы, указанного в параметре audit_file_dest.
  • DB – аудит включен и результаты сохраняются в базе данных в таблице sys.aud$

В Oracle предусмотрен ряд представлений таблицы sys.aud$. Их можно проверить, чтобы посмотреть, какая информация аудита собирается. Помните: на самом деле все данные хранятся в sys.aud$. Список представлений аудита можно получить следующим образом:

SQL> select object_name
2 from dba_objects
3 where object_name like '%AUDIT%'
4 and object_type='VIEW'
5 and owner='SYS'
6 order by object_name;
OBJECT_NAME 
------------------------------ 
ALL_DEF_AUDIT_OPTS 
ALL_REPAUDIT_ATTRIBUTE 
ALL_REPAUDIT_COLUMN 
DBA_AUDIT_EXISTS 
DBA_AUDIT_OBJECT 
DBA_AUDIT_SESSION 
DBA_AUDIT_STATEMENT 
DBA_AUDIT_TRAIL 
DBA_OBJ_AUDIT_OPTS 
DBA_PRIV_AUDIT_OPTS 
DBA_REPAUDIT_ATTRIBUTE 
DBA_REPAUDIT_COLUMN 

DBA_STMT_AUDIT_OPTS 
SM$AUDIT_CONFIG 
USER_AUDIT_OBJECT 
USER_AUDIT_SESSION 
USER_AUDIT_STATEMENT 
USER_AUDIT_TRAIL 
USER_OBJ_AUDIT_OPTS 
USER_REPAUDIT_ATTRIBUTE 
USER_REPAUDIT_COLUMN 
21 rows selected.
SQL>

Можно посмотреть на исходный текст этих представлений, чтобы проверить, как они получают данные. Представляет интерес представление DBA_AUDIT_EXISTS, поскольку оно показывает попытки доступа к таблицам и представлениям, к которым пользователь не имеет прав доступа. Следовательно, если аудит включен и вы часто пытаетесь обратиться к таблицам, которые не можете видеть, берегитесь!

Некоторые действия протоколируются в alert-файле. Он находится в каталоге, указываемом параметром background_dump_dest. В этом файле регистрируются: создание базы данных, структурные изменения, соединения администраторов, запуски и остановки базы данных. Для изменения действий аудита пользователь должен иметь привилегию audit system.

Существует большое количество операций аудита, 144 в Oracle 8.1.5 в Windows NT. Их можно посмотреть в таблице audit_actions. Кроме того, обратите внимание на таблицу audit$. Все операции аудита на уровне объектов можно увидеть в представлении DBA_OBJ_AUDIT_OPTS, его вариант USER_… показывает ту же информацию для объектов пользователя. Главное представление для просмотра журнала аудита – DBA_AUDIT_TRAIL. Можно также обнаружить, что некоторые администраторы создают собственные сводные таблицы и представления, используя sys.aud$ и некоторые стандартные представления аудита.

Понятно, что комбинаций установок параметров аудита слишком много, чтобы обсуждать их здесь. Отметим только, что администратор может включать аудит неудачных попыток соединения с базой данных.

Обычно хакер будет стремиться уничтожить следы своих попыток доступа к системе. Это можно сделать очисткой таблицы sys.aud$. Конечно, более опытный хакер будет стараться удалять только свои следы (по времени доступа, по выполненным действиям, имени пользователя, от имени которого он работал).

(Окончание следует)

E-mail this page