2015-12-14 2 views
-1

В следующем коде:Почему это переполнение?

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

int check_authentication(char *password) { 
    char password_buffer[16]; 
    int auth_flag = 0; 

    strcpy(password_buffer, password); 

    if(strcmp(password_buffer, "brillig") == 0) 
     auth_flag = 1; 
    if(strcmp(password_buffer, "outgrabe") == 0) 
    auth_flag = 1; 

    return auth_flag; 
} 

int main (int argc, char *argv[]){ 
    if(argc < 2){ 
     printf("Usage: %s <password>\n", argv[0]); 
     exit(0);  
    } 

     if(check_authentication(argv[1])){ 
     printf("\n-=-=-=-=-=-=-==-=-=-\n"); 
     printf(" Access Granted\n"); 
     printf("-=-=-=-=-=-=-==-=-=-\n"); 
    } 
    else { 
     printf("Access Denied\n"); 
    }  
} 

если я бегу что-то такое, как «AAAAAAAAAAAAAAAAAAAA», как-то что-то переполняется, и это приводит к тому, запуск программы, как доступ предоставлен. Я смущен, потому что, когда я запускал отладчик gdb, auth_flag был до password_buffer в памяти, и он никогда не переполнялся.

EDIT: Я понимаю, что текст не вписывается в буфер, но я экспериментирую с переполнением буфера и как использовать их контролируемым образом. Да, мы могли бы сделать массив крупнее, но дело не в этом

Мне было интересно, сможет ли кто-нибудь сказать мне, почему это происходит/что переполняется, чтобы вызвать это.

+2

Когда вы задаете размер буфера, он должен быть длиной + 1, так как ему нужен конечный нулевой символ. – Glenn

+1

Как уже объяснялось, вы вызываете Undefined Behavior. Поэтому стандартного ответа не может быть. Любой ответ зависит от системы, компилятора и используемых параметров компиляции. Поэтому, если вы действительно хотите получить достойный ответ, вам необходимо предоставить эту информацию. – kaylum

ответ

5

AAAAAAAAAAAAAAAAAAAA имеет размер 20. Вы затем с помощью strcpy, чтобы скопировать его в массив символов в размер 16. Попробуйте увеличить размер password_buffer.

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

http://www.cplusplus.com/reference/cstring/strcpy/

+0

, но я смущен тем, что причина, по которой предоставляется доступ, - это если auth_flag не равен нулю. если мы используем эту строку, я понимаю, что она переполняет «шведский стол», но почему это вызвало доступ к доступу? (auth_flag> 0) – yasgur99

+5

@ yasgur99 переполнение буфера вызывает неопределенное поведение. В этом случае все может случиться. –

3

Поскольку вы копируете вход в буфер, который слишком мал (и без причины). Ваш метод может быть реализован (без переполнения), как

int check_authentication(const char *password) { 
    size_t len = strlen(password); 

    return strncmp(password, "brillig", len) == 0 || 
      strncmp(password, "outgrabe", len) == 0; 
} 

Я понимаю, что это перетекает в буфете, но почему это может вызвать доступ само собой разумеющееся? (Auth_flag> 0)

Поскольку auth_flag находится в памяти следующего int после char password_buffer[16];. С некоторыми компиляторами (и операционными системами), если вы переполняете password_buffer, существует высокая вероятность того, что вы измените auth_flag.

+0

Я не пытаюсь заставить код работать правильно, я понимаю, что он переполнен, и вот почему есть проблема, но я не могу понять, что именно так происходит. – yasgur99

+0

@ yasgur99 Отредактировано. В вашем коде 'int' для' auth_flag' почти наверняка ** сохраняется ** сразу после 'password_buffer' (в памяти). –

+0

Я проверил в отладчике, и это не так. Я не знаю, связано ли это с Linux/Little Endian, но я на 1000% уверен, что password_buffer после auth_flag – yasgur99

1

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

Когда вы передаете указатель на буфер и копируете его без проверки границы локального буфера, вы рискуете переполнять свой буфер и переписывать переменные стека.

Когда вы вводите 'A' * 20, первые 16 'A' вошли в буфер, а остальные 4 'A вошли в int (обычно sizeof (int) составляет 4 байта).

Так что теперь ваш int не 0, это: auth = 0x41414141 поскольку код ASCII 'A' равен 0x41.

Там действительно отличная статья, связанная с этим - http://insecure.org/stf/smashstack.html

Изложены основы переполнение стека и становится немного более продвинутые позже.

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