Атака переполнения буфера
Я пытаюсь выполнить очень простую атаку переполнения буфера. Я в значительной степени новичок в этом. Итак, если этот вопрос глуп, извините меня: -)
Код:
#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: Я не уверен, правильно ли поставил вопрос. Пожалуйста, дайте мне знать, если вам нужна дополнительная информация.
Ответы
Ответ 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. Это может быть намного больше адреса возврата, чем вы ожидаете.