2014-02-22 1 views
1

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

Можете ли вы объяснить это мне?

Вот проблема:

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

void f (char *s) 
{ 
    char buf[32]; 
    strcpy (buf, s); 
} 

int main (int argc, char **argv) 
{ 
    volatile int i = 0; 
    if (argc> 1) 
     f (argv[1]); 

    if (i) 
     system ("/bin/sh"); 

    return EXIT_SUCCESS; 
} 

Спасибо за ответы!

+2

Какая книга? ... –

+1

В дополнение к ответам ниже: энергозависимый не является проблематичной частью, он только там, чтобы предотвратить компилятор от удаления переменной из-за оптимизации (потому что, кроме переполнения буфера, ясно, что происходит с это будет одинаково при каждом запуске программы) – deviantfan

ответ

1

Функция f копирует содержимое первого аргумента, переданного программе в буфер, но использует strcpy, который не выполняет проверку границ. Таким образом, вы можете выполнить атаку переполнения буфера и переопределить значение переменной i, которая затем заставит программу выдавать приглашение оболочки.

Попробуйте сами - просто вызовите программу с аргументом длиной более 32 символов.

Для сравнения strcpy и strncpy, которая является безопасной альтернативой, см their manual page

1

Этот код является опасным из-за этой линии:

strcpy (buf, s); 

Линия пытается скопировать переданную строку в буфер длины 32. Тем не менее, мы не устанавливаем длину того, как долго копировать или как долго может вводиться строка ввода s. Это то, что называется переполнением буфера . В связи с этим в память могут быть помещены произвольные данные (например, строки, выполняющие «злые» команды).

Например, если я использовал строку, состоящую из 32 пробелов, то строку «/ bin/sh -c rm -rf /», как s, тогда функция может случайно стереть ваш жесткий диск! (ну, технически, вам нужно быть администратором для этого, но этот пример эффективен)

Чтобы исправить это, используйте вместо этого strncpy, который принимает дополнительный аргумент, длину для копирования. Это сделало бы нашу опасную строку кода сейфа с:

strncpy(buf, s, 32); 
+0

Спасибо за объяснение!Но то, что вы говорите мне, не работает, когда я пытаюсь, у меня есть ошибка сегментации или нелегальная инструкция – user3341638

+0

@ user3341638 Если после замены 'strcpy (buf, s);' с 'strncpy (buf, s, 32); ', код вызывает ошибку сегментации, то есть что-то _else_ вы изменили или не показывали в своем сообщении. – chux

+0

Нет, я получил его, когда я попробовал строку из 32 пробелов, затем «/ bin/sh ...» – user3341638

3

Функция strcpy не проверяет пределы буфера он записывает в и, следовательно, может переполниться, если строка для копирования слишком велик для буфера вызывающего неопределенное поведение и даже сбой программы. Вы должны использовать более безопасную альтернативу strncpy. Он ограничивает количество копируемых байтов.

void f(char *s) { 
    char buf[32]; // can be a variable length array 
    strncpy(buf, s, (sizeof buf) - 1); // copy at most 31 bytes 
    buf[31] = '\0'; // make buf a string just in case strlen(s) > 31 
} 

Если нет нулевой байт в первые 32 байта в буфере не указывает s, то buf не будет нулевым байтом, и все 32 байта будут скопированы strncpy. Поэтому, если вы хотите, чтобы buf был строкой, вы должны оставить одно место для нулевого байта и поместить его туда в конце buf.

+1

+1 для хорошего ответа, включая проблему с голой 'strncpy()'. – chux

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