Продолжение.
Восстановленные лог файлы, также могут быть проанализированы вручную. Хорошая статья, демонстрирующая это, может быть найдена здесь.
Теперь мы можем просмотреть пример и исследовать содержание архивных лог файлов. Сначала проверьте, находится ли база данных в ARCHIVELOGMODE, определите, где записаны архивные лог файлы и, наконец, что включен аудит имен пользователей.
SQL> select log_mode from v$database;
LOG_MODE
------------
ARCHIVELOG
SQL> select name,value from v$parameter
2 where name in('log_archive_start','log_archive_dest');
NAME
------------------------------------------------------
VALUE
------------------------------------------------------
log_archive_start
TRUE
log_archive_dest
/export/home/u01/app/oracle/admin/emil/archive
Обнаружение, какой именно пользователь выполнил команду:
SQL> select name,value from v$parameter
2 where name = 'transaction_auditing';
NAME
----------------------------------------------------------------
VALUE
----------------------------------------------------transaction_auditing
TRUE
Теперь запустите пробную SQL инъекцию, а затем используйте Сборщик логов, для просмотра того, что было зарегистрировано. Для облегчения анализа этого примера, архивный лог файл сохраняется только до, и после выполнения этой команды находящейся в лог файле:
SQL> connect sys as sysdba
Enter password:
Connected.
SQL> alter system archive log current;
System altered.
SQL>
SQL> connect dbsnmp/dbsnmp@emil
Connected.
SQL>
set serveroutput on size 100000
debug:select customer_phone from customers where customer_surname='x' union
select username from all_users where 'x'='x'
::AURORA$JIS$UTILITY$
::AURORA$ORB$UNAUTHENTICATED
::CTXSYS
:
BSNMP
::EMIL
<records snipped>
::SYS
::SYSTEM
::WKSYS
::ZULIA
PL/SQL procedure successfully completed.
SQL> connect sys as sysdba
Enter password:
Connected.
SQL> alter system archive log current;
System altered.
SQL>
Сначала создайте словарь Сборщика логов:
SQL> set serveroutput on size 1000000
SQL> exec dbms_logmnr_d.build('logmnr.dat','/tmp');
LogMnr Dictionary Procedure started
LogMnr Dictionary File Opened
TABLE: OBJ$ recorded in LogMnr Dictionary File
TABLE: TAB$ recorded in LogMnr Dictionary File
TABLE: COL$ recorded in LogMnr Dictionary File
TABLE: TS$ recorded in LogMnr Dictionary File
<output snipped>
Procedure executed successfully - LogMnr Dictionary Created
PL/SQL procedure successfully completed.
SQL>
Найдите правильный архивный лог файл:
SQL> select name
2 from v$archived_log
3 where completion_time=(select max(completion_time) from v$archived_log);
NAME
--------------------------------------------------------------
/export/home/u01/app/oracle/admin/emil/archive/1_7.dbf
SQL>
Теперь загрузите архивный лог файл в Сборщик логов:
SQL> exec dbms_logmnr.add_logfile
('/export/home/u01/app/oracle/admin/emil/archive/1_7.dbf',sys.dbms_logmnr.NEW);
PL/SQL procedure successfully completed.
SQL> exec dbms_logmnr.start_logmnr(dictFileName => '/tmp/logmnr.dat');
PL/SQL procedure successfully completed.
SQL>
Наконец необходимо найти результаты:
SQL> select scn,username,timestamp,sql_redo
2 from v$logmnr_contents
SQL>
<snipped>
SCN USERNAME TIMESTAMP SQL_REDO
---------- --------------- --------- ------------------------------
253533 DBSNMP 16-JUN-03 set transaction read write;
253533 DBSNMP 16-JUN-03 update "SYS"."AUD$" set
"ACTION#" = '101',
"RETURNCODE" = '0',
"LOGOFF$LREAD" = '228',
"LOGOFF$PREAD" = '0',
"LOGOFF$LWRITE" = '10',
"LOGOFF$DEAD" = '0',
"LOGOFF$TIME" =
TO_DATE('16-JUN-2003
12:16:12', 'DD-MON-YYYY
SCN USERNAME TIMESTAMP SQL_REDO
---------- --------------- --------- ------------------------------
HH24:MI:SS'), "SESSIONCPU" =
'5' where "ACTION#" = '100'
and "RETURNCODE" = '0' and
"LOGOFF$LREAD" IS NULL and
"LOGOFF$PREAD" IS NULL and
"LOGOFF$LWRITE" IS NULL and
"LOGOFF$DEAD" IS NULL and
"LOGOFF$TIME" IS NULL and
"SESSIONCPU" IS NULL and ROWID
= 'AAAABiAABAAAAEWAAX';
SCN USERNAME TIMESTAMP SQL_REDO
---------- --------------- --------- ------------------------------
253534 DBSNMP 16-JUN-03 commit;
<snipped output>
Первое, что можно заметить это то, что Сборщик логов не обрабатывает команды select и отображает вывод в 9i. Модуль Сборщика логов не поддерживает выборки, поскольку они не сохраняются в восстановленных лог файлах. Возможно использование Сборщика логов, для онлайнового чтения восстановленных лог файлов, но я оставляю эти эксперименты читателям. Даже притом, что SQL инъекция может быть обнаружена в insert, delete и update выражениях, Сборщик логов не является подходящим средством для обнаружения SQL инъекций. Это, также как и некоторые другие проблемы, упомянутые выше, является недостатком в способности Сборщика логов обнаруживать команды select.
Анализатор сетевых пакетов
Главная проблема в анализаторе пакетов при подключении к базе данных Oracle это то, что сетевой протокол Oracle является собственным и не открытым. Это имеет ли значение при установлении, были ли попытки SQL инъекций? Вероятно да, поскольку доступ к протоколу был бы более эффективным инструментом для решения этой задачи. При отсутствии доступа к протоколу и желания это воспроизводить, задача ограничена только захватом строк ASCII-текста из шины. Существуют как преимущества, так и недостатки этого метода:
Преимущества:
Система может быть реализована на отдельном сервере, позволяющем проводить анализ в реальном масштабе без влияния на исходную базу данных.
Недостатки:
Этот метод использует много ресурсов.
Пакеты должны проанализированы близко к источнику и в той же самой подсети, для гарантирования проходов всех пакетов через анализатор.
Если используются дополнительные защитные параметры Oracle применяемые для шифрования сетевых пакетов или любые другие решения, используемые для шифрования, то анализатор сетевых пакетов не будет работать.
Если, как в нашем примере, пробную попытка SQL инъекции передают как запрос к хранимой процедуре, то не будет виден настоящий внутренний динамический SQL. Вместо этого вы будете просто видеть напечатанный в команде.
Анализ каждого пакета приводит к генерации огромного количества данных. Конвейеризация пакетов через программу-фильтр смягчает эту проблему.
Для демонстрации, мы будем использовать snoop на Solaris, чтобы увидеть то, что видимо внутри сетевых пакетов. Запустите snoop, и SQL из сеанса SQL*PLUS:
root:jupiter> snoop -t a -x 0 jupiter and port 1521 | strings
Using device /dev/hme (promiscuous mode)
15:06:34.31348 172.16.240.3 -> jupiter TCP D=1521 S=1404 Ack=299902194
\Seq=26460609 Len=174 Win=8413
0: 0800 2092 9d88 00a0 ccd3 a550 0800 4500 .. ........P..E.
16: 00d6 6884 4000 8006 596d ac10 f003 ac10 ..h.@...Ym......
32: f00b 057c 05f1 0193 c1c1 11e0 24f2 5018 ...|........$.P.
48: 20dd 0f36 0000 00ae 0000 0600 0000 0000 ..6............
64: 1169 36a4 61de 0001 0101 0303 5e37 0304 .i6.a.......^7..
80: 0021 0078 71de 0001 52bc 39de 0001 0a00 .!.xq...R.9.....
96: 0000 00e0 39de 0000 0101 0000 0000 0000 ....9...........
112: 0000 0000 0000 0000 0000 0000 0000 0000 ................
128: e239 de00 4245 4749 4e20 6765 745f 6375 .9..BEGIN get_cu
144: 7374 2827 7827 2720 756e 696f 6e20 7365 st('x'' union se
160: 6c65 6374 2075 7365 726e 616d 6520 6672 lect username fr
176: 6f6d 2061 6c6c 5f75 7365 7273 2077 6865 om all_users whe
192: 7265 2027 2778 2727 3d27 2778 2729 3b20 re ''x''=''x');
208: 454e 443b 0a00 0101 0101 0000 0000 0001 END;............
224: 0800 0105 ....
15:06:34.33281 jupiter -> 172.16.240.3 TCP D=1404 S=1521 Ack=26460783
Seq=299902194 Len=54 Win=24820
0: 00a0 ccd3 a550 0800 2092 9d88 0800 4500 .....P.. .....E.
16: 005e 094a 4000 4006 f91f ac10 f00b ac10 .^.J@.@.........
32: f003 05f1 057c 11e0 24f2 0193 c26f 5018 .....|..$....oP.
С помощью этого метода очевиден немедленный успех, так как SQL захватывается вместе с SQL инъекцией. Как и в других методах описанных в этой статье, должно быть выполнено следующее:
Должна быть запущена программа - фильтр, это необходимо для синтаксического анализа SQL выражений и определения потенциальных попыток SQL инъекций.
Для реального использования, программа-фильтр также должна извлекать информацию о времени создания файла и IP адрес источника из заголовков сетевых пакетов.
Выделение пользователя базы данных может быть чрезвычайно трудным, поскольку, для выделения информации об учетных записях входа в систему, должны быть проверены все предыдущие сетевые пакеты. Все это дает потребность в сохранении предыдущих пакетов или информации о них и их последовательностях.
В качестве простого решения, анализ сетевых пакетов, может выступать в роли альтернативного решения, обеспечивающего достаточно простые фильтры/синтаксические анализаторы, написанные в Perl или C. Нашей целью является вывод возможных преступлений, выделяя SQL, timestamp и src и dest IP из пакетного потока.
Анализ внутренних сетевых пакетов Oracle (sqlnet trace)
Извлечение сетевой информации из Oracle возможно, используя средство трассировки SQL*NET, Net*8 или Oracle networking (смотря какое из названий подходит к версии вашей базы данных).
Средства трассировки доступны для большинства сетевых сервисов Oracle, таких как: listener, Oracle names, connection manager, names control utility, и конечно Oracle networking client and server. В этом примере мы сконцентрируем внимание на трассировке сервера.
Существуют некоторые недостатки в использовании сетевых трассировочных файлов, как средства поиска SQL инъекций:
Трассировочные файлы очень быстро увеличиваются в размерах, используя при этом огромное количество дискового пространства. При неправильном управлении существует опасность переполнения диска, и как следствие отказ в обслуживании.
Существует предел в записи трассировочных файлов.
Хотя и возможно определить уникальное имя и расположение трассировочного файла, но Oracle добавляет идентификатор процесса (PID) в конец имени файла трассировки. PID можно увидеть в следующих SQL:
SQL> select p.spid,s.username
2 from v$session s,v$process p
3 where s.paddr=p.addr;
SPID USERNAME
--------- ------------------------------
<records snipped>
616 DBSNMP
556 SYSTEM
9 rows selected.
SQL>
Для включения трассировки необходимо в файле $ORACLE_HOME/network/admin/sqlnet.ora добавить следующие строки:
TRACE_FILE_SERVER=pf_trace.trc
TRACE_DIRECTORY_SERVER=/tmp
TRACE_LEVEL_SERVER=SUPPORT
Параметры определяют, где должен быть записан файл трассировки, как он должен называться, а также его уровень. Существует четыре используемых уровня трассировки: OFF, USER, ADMIN и SUPPORT. Они повышают детализацию трассировки от OFF до SUPPORT; уровень SUPPORT учитывает содержание сетевых пакетов.
Давайте снова запустим наш пример из SQL*PLUS на Windows-клиенте и посмотрим, что было сгенерировано в a файле трассировки. Трассировочный файл, как и ожидалось, называется pf_trace_616.trc. Ничего себе! Этот файл содержит в себе 4005 строк, и это только из-за соединения и запуска следующей команды:
SQL> exec get_cust('x'' union select username from all_users where ''x''=''x');
PL/SQL procedure successfully completed.
Выполнив поиск дампа пакета, в файле трассировке, мы можем найти попытку SQL инъекции, посланной базе данных:
nsprecv: 165 bytes from transport
nsprecv: tlen=165, plen=165, type=6
nsprecv: packet dump
nsprecv: 00 A5 00 00 06 00 00 00 |........|
nsprecv: 00 00 03 5E 35 03 04 00 |...^5...|
nsprecv: 21 00 78 71 DE 00 01 52 |!.xq...R|
nsprecv: BC 39 DE 00 01 0A 00 00 |.9......|
nsprecv: 00 00 E0 39 DE 00 00 01 |...9....|
nsprecv: 01 00 00 00 00 00 00 00 |........|
nsprecv: 00 00 00 00 00 00 00 00 |........|
nsprecv: 00 00 00 00 00 00 00 E2 |........|
nsprecv: 39 DE 00 42 45 47 49 4E |9..BEGIN|
nsprecv: 20 67 65 74 5F 63 75 73 | get_cus|
nsprecv: 74 28 27 78 27 27 20 75 |t('x'' u|
nsprecv: 6E 69 6F 6E 20 73 65 6C |nion sel|
nsprecv: 65 63 74 20 75 73 65 72 |ect user|
nsprecv: 6E 61 6D 65 20 66 72 6F |name fro|
nsprecv: 6D 20 61 6C 6C 5F 75 73 |m all_us|
nsprecv: 65 72 73 20 77 68 65 72 |ers wher|
nsprecv: 65 20 27 27 78 27 27 3D |e ''x''=|
nsprecv: 27 27 78 27 29 3B 20 45 |''x'); E|
nsprecv: 4E 44 3B 0A 00 01 01 01 |ND;.....|
При использовании файлов трассировки SQL*Net, существует еще ряд проблем, помимо перечисленных выше:
Был еще раз необходим синтаксический анализатор, для извлечения SQL текста из дампов пакета и определения были ли SQL инструкции попыткой SQL инъекции.
PID, используемый как часть имени файла трассировки не известен, до тех пор, пока не подсоединится пользователь, и не запустится фоновый процесс. Если бы имена файлов не были уникальны подобно snoop, то трассировка могла бы быть пропущена через фильтр, и проблема использования дискового пространства была бы решена.
Трассировочные файлы могут регулярно проверяться простым сценарием, который проверяет трассировочные файлы, в которых больше не запущен фоновый процесс. В этом случае они могут быть обработаны и удалены. Длительные сеансы генерировали бы огромные трассировки и таким образом не могли бы идеально контролироваться.
Проще всего определить пользователей операционной системы и пользователей базы данных, включающих в себя трассировку SQL*NET, поскольку эта информация может быть найдена в представлениях v$process и v$session со сведениями об OS PID.
Этот метод не удобен, для выполнения простой утилиты обнаружения SQL инъекций. Ресурсные проблемы только затрудняют управление и работу. Можно использовать это более расчетливо, когда подозреваемый инцидент произошел и где использование трассировки может контролироваться на ограниченном отрезке времени или числе пользователей.
продолжение следует....