Передача парольной фразы в Veracrypt с помощью popen() - это безопасно?

Я пытаюсь сделать монтирование нескольких томов Veracrypt одним и тем же паролем более удобным в командной строке Linux. Поскольку Veracrypt поддерживает только кэширование парольной фразы в GUI-режиме, я написал следующий код, чтобы выполнить эту работу за меня:

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

int main(int argc, char* argv[]){
if(argc > 1 && argc%2==1){
    srand(time(0));

    //prevent veracrypt from asking for user's passphrase
    system("sudo echo -n");

    char *buffer = getpass("Veracrypt Password:");

    for(int i = 1; i<argc; i+=2){
        char* cc;
        cc = (char *) malloc(57+strlen(argv[i])+1+strlen(argv[i+1]));
        strcpy(cc, "veracrypt -t --protect-hidden=no --keyfiles=\"\" --pim=123 ");
        strcat(cc, argv[i]);
        strcat(cc, " ");
        strcat(cc, argv[i+1]);

        FILE* fChild = popen(cc, "w");
        fprintf(fChild, "%s", buffer);
        pclose(fChild);

        free(cc);
    }
    for(int i = 0; i<strlen(buffer); i++)
    buffer[i] = rand();
}
return 0;
}

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

Мои два вопроса:

  • Этот подход - хорошая идея вообще? (Securitywise)

  • Как значение буфера передается в veracrypt с помощью popen()? / Чтение буфера непосредственно из его местоположения или оно скопировано и может поэтому оставаться где-то в памяти?

1 ответ

Решение

Подход в порядке и так же безопасен, как и передача пароля в оболочке <<<"myPassword" veracrypt,

  1. Там нет пароля в ps выход.
  2. Пароль хранится только во временных буферах.
  3. Я думаю, что злоумышленник все еще может получить пароль, используя некоторые атаки по побочным каналам, если он знает достаточно о вашем приложении / исходном коде.

Ваш код вообще не защищен.

  1. Вы не проверяете возвращаемое значение malloc
  2. Вы не проверяете возвращаемое значение popen
  3. Вы не проверяете возвращаемое значение getpass
  4. Вы переполняете выделенную память для cc, Вы не выделяли место для завершающего нулевого символа. Вы могли бы использовать asnprintf и пусть библиотека GNU сделает всю работу за вас.
  5. Потому что вы не проходите должным образом argv[i] а также argv[i+1] просто напасть на любой компьютер с помощью вашей программы, просто напр.: ./your_program "; sudo rm -rf <some_file>" "; echo I can run any shell script here",

Этот подход - хорошая идея вообще? (Securitywise)

Подход в порядке, как вы подошли, это не нормально. Ваша программа теряет память и не проверяет никаких возвращаемых значений и не контролирует строки, передаваемые popen, что просто небезопасно. С помощью system(sudo echo -n) также небезопасно. Что касается approuch, было бы лучше, чтобы bzero буфер после его последнего использования memset(buffer, 0, strlen(buffer) + 1) (может быть, несколько раз, например, 5), а затем free(buffer),

В свете последних атак, таких как Meltdown, Spectre и других, новые версии ssh шифруют пароль длинным ключом (я думаю, с RSA, не уверен) сразу после его получения от пользователя и дешифруют каждый раз при использовании. Ключ достаточно длинный, чтобы сделать атаки такими методами маловероятными или слишком длинными. Я не думаю, что есть потребность в легком небольшом приложении, чтобы реализовать такой метод. источник.

Как значение буфера передается в veracrypt с помощью popen()?

Потому что вы используете fprintf, буфер копируется во внутренний FILE* буфер, а затем сбрасывается на новую строку. По умолчанию FILE* потоки буферизуются и сбрасываются на новую строку. Вы можете указать поведение с setvbufОднако я не думаю, что это вообще безопасно, так как пароль останется в FILE* буфер на некоторое время. Тогда fprintf звонок записывает содержимое внутреннего FILE* буфера после новой строки в связанный дескриптор файла канала с FILE* указатель. Затем ядро ​​передает данные со входа канала в стандартный ввод команды. Немного более безопасный способ (так как вам не нужно printf Утилита вообще, вы просто "%s"...), вероятно, использовать setvbuf(fChild, NULL, _IONBF, 0) а затем использовать fwrite(buffer, strlen(buffer), 1, fChild),

Правильный подход будет состоять в том, чтобы удалить FILE* и использовать правильное pipe() + fork() + exec() и поток пароля прямо в трубу с write() звоните, чтобы не использовать FILE* внутренняя буферизация fork() также позволит вам отправлять сигналы и обрабатывать возвращаемое значение ребенка.

Буфер считывается непосредственно из его местоположения или копируется и поэтому может оставаться где-то в памяти?

Да и да и да. Он читается прямо из его местоположения внутри fprintf вызов. Копируется во внутренний FILE* буфер. Поэтому он может остаться где-то в памяти.

Другие вопросы по тегам