Как curl защищает пароль от вывода ps?

readarray также может читать из stdin, поэтому:

readarray arr <<< "$(echo a; echo b; echo c)"; echo ${#arr[@]}
70
11.08.2017, 02:14
3 ответа

Когда ядро ​​выполняет процесс, оно копирует аргументы командной строки в память для чтения и записи, принадлежащую процессу (в стеке, по крайней мере, в Linux). Процесс может записывать в эту память, как и в любую другую память. Когда psотображает аргумент, он считывает все, что хранится по этому конкретному адресу в памяти процесса. Большинство программ сохраняют исходные аргументы, но их можно изменить. В POSIX-описании psуказано, что

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

Причина, по которой это упоминается, заключается в том, что большинство вариантов Unix действительно отражают изменение, но реализации POSIX на других типах операционных систем могут не учитываться.

Эта функция имеет ограниченное применение, поскольку процесс не может вносить произвольные изменения. По крайней мере, общая длина аргументов не может быть увеличена, потому что программа не может изменить место, где psбудет извлекать аргументы, и не может расширить область сверх исходного размера. Длину можно эффективно уменьшить, поместив нулевые байты в конец, потому что аргументы представляют собой строки в стиле C, заканчивающиеся нулем (это неотличимо от набора пустых аргументов в конце).

Если вы действительно хотите копать, вы можете посмотреть исходный код реализации с открытым исходным кодом.В Linux источник psне интересен, все, что вы там увидите, это то, что он считывает аргументы командной строки из файловой системы proc, в /proc/ PID/cmdline. Код, который генерирует содержимое этого файла, находится в ядре, вproc_pid_cmdline_readв fs/proc/base.c. Часть памяти процесса (доступная с помощью access_remote_vm) идет от адреса mm->arg_startдо mm->arg_end; эти адреса записываются в ядро ​​при запуске процесса и не могут быть изменены впоследствии.

Некоторые демоны используют эту способность для отражения своего статуса, например они меняют свой argv[1]на строку типа startили availableили exiting. Многие варианты Unix имеют для этого функциюsetproctitle . Некоторые программы используют эту возможность для сокрытия конфиденциальных данных. Обратите внимание, что это имеет ограниченное применение, поскольку аргументы командной строки видны во время запуска процесса.

Большинство языков высокого уровня копируют аргументы в строковые объекты и не дают возможности изменить исходное хранилище. Вот программа на C, которая демонстрирует эту возможность, напрямую изменяя элементы argv.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
    int i;
    system("ps -p $PPID -o args=");
    for (i = 0; i < argc; i++)
    {
        memset(argv[i], '0' + (i % 10), strlen(argv[i]));
    }
    system("ps -p $PPID -o args=");
    return 0;
}

Пример вывода:

./a.out hello world
0000000 11111 22222

Вы можете увидеть модификацию argvв исходном коде curl. Curl определяет функцию cleanargв src/tool_paramhlp.c , которая используется для изменения аргумента на все пробелы с помощью memset. В src/tool_getparam.cэта функция используется несколько раз, напримерпутем редактирования пароля пользователя. Поскольку функция вызывается из синтаксического анализа параметра, это происходит в начале вызова curl, но вывод командной строки до того, как это произойдет, все равно покажет любые пароли.

Поскольку аргументы хранятся в собственной памяти процесса, их нельзя изменить извне, кроме как с помощью отладчика.

84
27.01.2020, 19:31

Процесс может не только читать свои параметры, но и записывать их.

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

https://stackoverflow.com/questions/205064/is-there-a-way-to-change-another-processs-environment-variables

3
27.01.2020, 19:31

Другие ответы хорошо отвечают на вопрос в общем виде. Чтобы конкретно ответить " Как достигается этот эффект?Это где-то в исходном коде curl?":

В секции разбора аргументов исходного кода curl параметр -uобрабатывается следующим образом:

    case 'u':
      /* user:password  */
      GetStr(&config->userpwd, nextarg);
      cleanarg(nextarg);
      break;

А функцияcleanarg()определяется следующим образом:

void cleanarg(char *str)
{
#ifdef HAVE_WRITABLE_ARGV
  /* now that GetStr has copied the contents of nextarg, wipe the next
   * argument out so that the username:password isn't displayed in the
   * system process list */
  if(str) {
    size_t len = strlen(str);
    memset(str, ' ', len);
  }
#else
  (void)str;
#endif
}

Таким образом, мы можем явно видеть, что аргумент имя пользователя :пароль в argvперезаписывается пробелами, как описано в других ответах.

14
27.01.2020, 19:31

Теги

Похожие вопросы