2013-12-23 5 views
2

У меня есть следующая программапереполнение буфера, что не должно произойти (?)

1 #include <stdio.h> 
2 #include <stdlib.h> 
3 #include <string.h> 
4 
5 int check_authentication(char *password){ 
6 char password_buffer[16]; 
7 int auth_flag =0; 
8 
9 
10 strcpy(password_buffer, password); 
11 
12 if(strcmp(password_buffer, "brillig") == 0) 
13 auth_flag = 1; 
14 if(strcmp(password_buffer, "outgrabe") == 0) 
15 auth_flag = 1; 
16 
17 return auth_flag; 
18 } 
19 
20 int main(int argc, char *argv[]){ 
21 if (argc<2){ 
22 printf("Usage: %s <password>\n", argv[0]); 
23 exit(0); 
24 } 
25 
26 if(check_authentication(argv[1])){ 
27  printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"); 
28  printf(" Access Granted.\n"); 
29  printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"); 
30  } 
31 else { 
32 printf("\n Access Denied. \n"); 
33 } 
34 } 

Я бегу он поставляет 30 байт как через GDB ... и я устанавливаю следующие контрольные точки

(gdb) break 9 
Breakpoint 1 at 0x80484c1: file auth_overflow2.c, line 9. 
(gdb) break 16 
Breakpoint 2 at 0x804850f: file auth_overflow2.c, line 16. 
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 

Пока все хорошо. Все идет, как должно было идти даже до следующего точки останова

Breakpoint 1, check_authentication (password=0xbffff6d2 'A' <repeats 30 times>) 
at auth_overflow2.c:10 
10 strcpy(password_buffer, password); 
(gdb) x/s password_buffer 
0xbffff484: "\364\237\374\267\240\205\004\b\250\364\377\277\245",   <incomplete  sequence \352\267> 
(gdb) x/x &auth_flag 
0xbffff494: 0x00 

Теперь мы видим следующую информацию:

переменной auth_flag находится по адресу 0xbffff494 и переменный буфер находится в адресном 0xbffff484. Поскольку адрес var auth_flag больше, чем адрес буфера, и стек растет в сторону более низких адресов, что означает, что дополнительные (переполнение буфера) байтов в переменной буфера НЕ ОБНОВЛЯТЬ auth_flag. Правильно ?

Но GDB имеет другое мнение ...

(gdb) cont 
Continuing. 

Breakpoint 2, check_authentication (
password=0xbf004141 <Address 0xbf004141 out of bounds>) 
at auth_overflow2.c:17 
17 return auth_flag; 
(gdb) x/s password_buffer 
0xbffff484: 'A' <repeats 30 times> 
(gdb) x/x &auth_flag 
0xbffff494: 0x41 

и ...

(gdb) x/16xw &auth_flag 
0xbffff494: 0x41414141 0x41414141 0x41414141 0xbf004141 
0xbffff4a4: 0x00000000 0xbffff528 0xb7e8bbd6 0x00000002 
0xbffff4b4: 0xbffff554 0xbffff560 0xb7fe1858 0xbffff510 
0xbffff4c4: 0xffffffff 0xb7ffeff4 0x080482bc 0x00000001 

Мы видим, что auth_flag был переписан с этими 0x41 (= А), хотя эта переменная была в нижнее положение в стеке. Почему это произошло?

ответ

5

Направление роста стека не имеет ничего общего с тем, куда идут дополнительные байты, когда вы переполняете буфер. Перерасход от strcpy всегда будет в более высоких адресах (если только перерасход до тех пор, пока вы не обрушитесь на адрес 0, что маловероятно)

0

Если вы читаете более 15 байт, вы получите это. strcpy будет искать конец строки. Вы можете использовать что-то вроде strncpy, чтобы копировать только ограниченное количество символов.

+0

Это не имеет ничего общего с вопросом, то зЬгсру используется намеренно для того, чтобы обеспечить переполнение буфера. – MByD

1

Объекты хранятся в памяти от нижних udresses до более высоких адресов. Поскольку вы не можете гарантировать, что длина строки, на которую ссылается пароль параметра, меньше 16, ваш код недействителен. На самом деле в локальном буфере password_buffer нет необходимости. функция может быть записана следующим образом

_Bool check_authentication(const char *password) 
{ 
    return (strcmp(password, "brillig") == 0 || strcmp(password, "outgrabe") == 0); 
} 

Вместо типа возвращаемого _Bool вы можете использовать тип Int, как в вашей реализации функции. В любом случае возвращается 1 или 0.

1

компилятор может свободно переупорядочить стек переменных, поэтому в этом случае он всегда является массивом символов до переменной int. Это делает программу уязвимой для переполнения буфера на основе стека.

Для того, чтобы изменить следующие параметры:

(gdb) x/s password_buffer 
0xbffff484: 'A' <repeats 30 times> 
(gdb) x/x &auth_flag 
0xbffff494: 0x41 

в ожидаемого ответа, как показано ниже:

(gdb) x/s password_buffer 
0xbffff494: 'A' <repeats 30 times> 
(gdb) x/x &auth_flag 
0xbffff484: 0x00 

Мы просто добавить -fstack-protector-all аргумент во время компиляции, и результат будет, как и ожидалось. Чтобы быть наоборот, возможно, вы можете использовать -O0 или -fno-stack-protector.

Ответ от: https://stackoverflow.com/a/21215205/3205268

Смежные вопросы