Волатильное целое и компьютерная безопасность

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

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

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

#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; 
}

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

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 сам.

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

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

Для сравнения strcpy а также strncpy что является более безопасной альтернативой, см. их страницу руководства

Этот код опасен из-за этой строки:

strcpy (buf, s); 

Строка пытается скопировать переданную строку в буфер длиной 32. Однако мы не устанавливаем длину, как долго копировать или как долго вводить строку s может быть. Это то, что называется переполнением буфера. Благодаря этому произвольные данные (например, строки, выполняющие "злые" команды) могут быть помещены в память.

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

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

strncpy(buf, s, 32);
Другие вопросы по тегам