Подтвердить что ты не робот

Атака переполнения буфера

Я пытаюсь выполнить очень простую атаку переполнения буфера. Я в значительной степени новичок в этом. Итак, если этот вопрос глуп, извините меня: -)

Код:

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

int i, n;

void confused(int i) 
{
 printf("**Who called me? Why am I here?? *** %x\n ", i);
}

void shell_call(char *c) 
{
 printf(" ***Now calling \"%s\" shell command *** \n", c);
 system(c);
}

void victim_func()
{
 int a[4];
 printf("Enter n:  ");  scanf("%d",&n);
 printf("~~~~~~~~~~~~~ values and address of n locations ~~~~~~~~~~");
 for (i = 0;i <n ;i++) 
  printf ("\n a[%d] = %x, address = %x", i, a[i], &a[i]);
 printf("\nEnter %d HEX Values \n", n);

 // Buffer Overflow vulnerability HERE!

 for (i=0;i<n;i++)  scanf("%x",&a[i]);
   printf("Done reading junk numbers\n");
}

int main() 
{
 victim_func();
 printf("\n done");
 return 0; 
}

Когда я использую objdump для получения адресов функций, у меня есть следующее:

main(): 0x804854d
Address of main() where printf() is called: 0x8048563
victim_func(): 0x8048455
confused(): 0x8048414

Теперь я хочу перейти к функции 'confused()' from victim_func(), переполнив там буфер, и переписав обратный адрес на адрес confused(). И я хочу вернуться из confused() в printf() в main и нормально выйти. Итак, я предоставляю следующий ввод

Enter n: 7
Enter 7 HEX values:
1
2
3
4
5
8048414 (This is to jump to confused)
8048563 (this is to jump to printf() in main)

Несмотря на то, что программа печатает "Done" из этого оператора printf, она перескакивает обратно в victim_func() и печатает "Enter n:"

Что я делаю неправильно? Любая помощь будет принята с благодарностью!

PS: Я не уверен, правильно ли поставил вопрос. Пожалуйста, дайте мне знать, если вам нужна дополнительная информация.

4b9b3361

Ответ 1

Атака переполнения буфера намного сложнее, чем эта. Прежде всего вам нужно понять ассемблер, чтобы выполнить это. После того, как вы разобрали программу и функцию, на которые вы хотите настроить таргетинг, вам необходимо определить структуру стека при выполнении этой функции. Здесь образец буфера переполняет его с помощью visual studio, но принцип тот же.

#include "stdafx.h"
#include <math.h>

volatile double  test;

double function3()
{
    test++;
    return exp(test);
}

double  function2()
{
    return log(test);
}

double  function1()
{
    int a[5] = {0};           
    a[7] = (int)&function3;
    return exp(function2());

}
int _tmain(int argc, _TCHAR* argv[])
{
    double a = function1();
    test = a;
    return a;
}

Благодаря разборке мы знаем, что функция a в функции выделяется до того момента, когда функция сохранила указатель фрейма стека. Значение после этого - это адрес возврата, куда должна перейти функция function1, если она завершена.

00401090 55               push        ebp    <- we save the stack pointer
00401091 8B EC            mov         ebp,esp 
00401093 83 EC 1C         sub         esp,1Ch <- save space to allocate a[5]
00401096 B8 CC CC CC CC   mov         eax,0CCCCCCCCh 
0040109B 89 45 E4         mov         dword ptr [ebp-1Ch],eax  <- crt debug init a[5]  
0040109E 89 45 E8         mov         dword ptr [ebp-18h],eax 
004010A1 89 45 EC         mov         dword ptr [ebp-14h],eax 
004010A4 89 45 F0         mov         dword ptr [ebp-10h],eax 
004010A7 89 45 F4         mov         dword ptr [ebp-0Ch],eax 
004010AA 89 45 F8         mov         dword ptr [ebp-8],eax 
004010AD 89 45 FC         mov         dword ptr [ebp-4],eax 

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

Надеюсь, что это поможет.

Ответ 2

Прежде всего мне кажется, что вы не должны вводить номер 5 в своем примере ввода. Ваш массив объявлен как [4], поэтому элементы с индексом 0-3 - поэтому ваш ввод атаки кажется мне неправильным.

Мне также кажется, что ваша программа предполагает несколько вещей об архитектуре:

  • sizof (int) == sizeof (адрес памяти)
  • Направление роста и механизм реализации стека среды

Если одно из этих предположений неверно, это никогда не сработает.

Это похоже на очень сложное трудовое задание.

Есть более простые примеры переполнений буфера, чем изменение потока управления кодом. Например, вы можете перезаписать другую часть данных, которая должна быть защищена от пользователя (например, параметр безопасности).

Ответ 3

Теперь я хочу перейти к функции 'confused()' from victim_func(), переполнив там буфер и перезаписать обратный адрес на адрес confused()...

На современных платформах Linux вам также необходимо будет отключить две функции безопасности для тестирования. Сначала в NX-стеках, а во-вторых, Stack Protectors.

Чтобы отключить NX-Stacks, используйте -Wl,z,execstack (в отличие от -Wl,z,noexecstack). Чтобы отключить защиту стека, используйте -fno-stack-protector (в отличие от -fstack-protector или -fstack-protector-all).

Там есть третья защита, которую вам может потребоваться отключить. Эта защита FORTIFY_SOURCE. FORTIFY_SOURCE использует "более безопасные" варианты функций высокого риска, таких как memcpy и strcpy. Компилятор использует более безопасные варианты, когда он может определить размер буфера назначения. Если копия превысит размер буфера назначения, программа вызывает abort(). Чтобы отключить FORTIFY_SOURCE, скомпилируйте программу с помощью -U_FORTIFY_SOURCE или -D_FORTIFY_SOURCE=0.

Функции безопасности включены по умолчанию, потому что в прошлом было так много проблем. В общем, это хорошо, потому что это останавливает многие проблемы (например, тот, с которым вы экспериментируете).

Ответ 4

Вы не показали нам выход программы с адресами [i]. Я подозреваю, что компилятор делает что-то вроде выравнивания данных в стеке до 16. Это может быть намного больше адреса возврата, чем вы ожидаете.