Некоторое время назад я заметил, что имена пользователей и пароли, заданные в curl
качестве аргументов командной строки, не отображаются в ps
выходных данных (хотя, конечно, они могут появляться в вашей истории bash).
Они также не появляются в /proc/PID/cmdline
.
(Длина объединенного аргумента имя пользователя / пароль может быть получена, хотя.)
Демонстрация ниже:
[root@localhost ~]# nc -l 80 &
[1] 3342
[root@localhost ~]# curl -u iamsam:samiam localhost &
[2] 3343
[root@localhost ~]# GET / HTTP/1.1
Authorization: Basic aWFtc2FtOnNhbWlhbQ==
User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.15.3 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Host: localhost
Accept: */*
[1]+ Stopped nc -l 80
[root@localhost ~]# jobs
[1]+ Stopped nc -l 80
[2]- Running curl -u iamsam:samiam localhost &
[root@localhost ~]# ps -ef | grep curl
root 3343 3258 0 22:37 pts/1 00:00:00 curl -u localhost
root 3347 3258 0 22:38 pts/1 00:00:00 grep curl
[root@localhost ~]# od -xa /proc/3343/cmdline
0000000 7563 6c72 2d00 0075 2020 2020 2020 2020
c u r l nul - u nul sp sp sp sp sp sp sp sp
0000020 2020 2020 0020 6f6c 6163 686c 736f 0074
sp sp sp sp sp nul l o c a l h o s t nul
0000040
[root@localhost ~]#
Как достигается этот эффект? Это где-то в исходном коде curl
? (Я предполагаю, что это curl
особенность, а не ps
особенность? Или это какая-то особенность ядра?)
Кроме того: это может быть достигнуто извне исходного кода двоичного исполняемого файла? Например, с помощью команд оболочки, возможно, в сочетании с правами root?
Другими словами, могу ли я как-то замаскировать аргумент, появляющийся в /proc
или в ps
выходных данных (я думаю, то же самое), которые я передал какой-то произвольной команде оболочки? (Я предполагаю, что ответом будет «нет», но, кажется, стоит включить эту лишнюю половину вопроса.)
environ
непосредственно для доступа к переменным среды? - нижняя строка: список аргументов, как и список переменных среды, находится в памяти пользовательского процесса для чтения / записи и может быть изменен пользовательским процессом.grep
шаблона классом символов. Напримерps -ef | grep '[c]url'
curl
соответствует,curl
но[c]url
не соответствует[c]url
. Если вам нужно больше подробностей, задайте новый вопрос, и я буду рад ответить.Ответы:
Когда ядро выполняет процесс, оно копирует аргументы командной строки для чтения-записи памяти, принадлежащей процессу (в стеке, по крайней мере, в Linux). Процесс может записывать в эту память как любую другую память. Когда
ps
отображается аргумент, он читает все, что хранится по этому конкретному адресу в памяти процесса. Большинство программ сохраняют исходные аргументы, но их можно изменить. В описании POSIXps
говорится, чтоПричина, по которой это упоминается, заключается в том, что большинство вариантов 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]
на строки, подобныеstarting
илиavailable
илиexiting
. Многие варианты Unix имеютsetproctitle
функцию для этого. Некоторые программы используют эту возможность, чтобы скрыть конфиденциальные данные. Обратите внимание, что это ограниченное использование, поскольку аргументы командной строки видны при запуске процесса.Большинство языков высокого уровня копируют аргументы в строковые объекты и не дают возможности изменить исходное хранилище. Вот программа на C, которая демонстрирует эту способность путем
argv
непосредственного изменения элементов.Образец вывода:
Вы можете увидеть
argv
модификацию в исходном коде curl. Curl определяет функцию,cleanarg
вsrc/tool_paramhlp.c
которой используется для изменения аргумента для всех пробелов с помощьюmemset
. Вsrc/tool_getparam.c
этой функции используется несколько раз, например, путем редактирования пароля пользователя . Поскольку функция вызывается из парсинга параметров, это происходит на раннем этапе вызова curl, но выгрузка командной строки до того, как это произойдет, покажет все пароли.Поскольку аргументы хранятся в собственной памяти процесса, их нельзя изменить извне, кроме как с помощью отладчика.
источник
ps
аргументы отчета из этого куска памяти ядра, игнорируя любые изменения, внесенные в память чтения-записи процессов? Но (если я правильно понял?) Большинство вариантов UNIX даже не делают первое, так что вы не можете заставитьps
реализацию сделать второе без модификаций ядра, поскольку исходные данные нигде не хранятся?argv
изменять содержимое записей (вы не можете установитьargv[i]
, но вы можете записатьargv[i][0]
черезargv[i][strlen(argv[i])]
), поэтому должна быть копия в памяти процесса.ps
выводе множество пустых аргументов выглядит так, будто там ничего нет, но да, это имеет значение, если вы проверите, сколько есть пробелов, и вы можете наблюдать более непосредственно из/proc/PID/cmdline
.Другие ответы хорошо отвечают на вопрос в целом. Чтобы конкретно ответить « Как достигается этот эффект? Это где-то в исходном коде curl? »:
В разделе аргумента синтаксического анализа исходного кода локонов , то
-u
опция обрабатываются следующим образом :И
cleanarg()
функция определяется следующим образом:Таким образом, мы можем явно видеть, что аргумент username: password in
argv
перезаписывается пробелами, как описано в других ответах.источник
cleanarg
прямо говорится, что он делает то, что задает вопрос!Процесс может не только читать свои параметры, но и записывать их.
Я не разработчик, поэтому я не знаком с этим, но это может быть возможно извне с подходом, аналогичным изменению параметров среды:
https://stackoverflow.com/questions/205064/is-there-a-way-to-change-another-processs-environment-variables
источник
bash -c 'awk 1 /proc/$$/cmdline; set -- something; awk 1 /proc/$$/cmdline'
показывает, что по крайней мере в оболочке установка параметров отличается от модификации того, что ядро видит в качестве параметров процесса.