Мне нужно скрыть некоторые секретные аргументы для программы, которую я запускаю, но у меня нет доступа к исходному коду. Я также запускаю это на общем сервере, поэтому я не могу использовать что-то подобное, hidepid
потому что у меня нет привилегий sudo.
Вот несколько вещей, которые я пробовал:
export SECRET=[my arguments]
с последующим вызовом./program $SECRET
, но это, похоже, не помогает../program `cat secret.txt`
гдеsecret.txt
содержатся мои аргументы, но всемогущийps
способен раскрыть мои секреты.
Есть ли другой способ скрыть мои аргументы, которые не связаны с вмешательством администратора?
ps
не делает ничего волшебного, чтобы «раскрыть свои секреты». В любом случае, разумно написанные программы вместо этого должны предлагать параметр командной строки для чтения секрета из указанного файла или из стандартного ввода, вместо того, чтобы принимать его непосредственно в качестве аргумента.Ответы:
Как объясняется здесь , Linux помещает аргументы программы в пространство данных программы и сохраняет указатель на начало этой области. Это то, что используется
ps
и так далее, чтобы найти и показать аргументы программы.Поскольку данные находятся в пространстве программы, они могут манипулировать ими. Выполнение этого без изменения самой программы включает в себя загрузку прокладки с
main()
функцией, которая будет вызываться перед реальной основной программой. Эта прокладка может копировать реальные аргументы в новое пространство, а затем перезаписывать исходные аргументы, чтобыps
просто видеть nuls.Следующий код C делает это.
Невозможно вмешаться
main()
, но вы можете вмешаться в стандартную библиотечную функцию C__libc_start_main
, которая затем вызывает main. Скомпилируйте этот файл,shim_main.c
как указано в комментарии в начале, и запустите его, как показано. Я оставилprintf
в коде, чтобы вы убедились, что он на самом деле вызывается. Например, запуститьзатем выполните a,
ps
и вы увидите пустую команду и отображаемые аргументы.Командные аргументы команды могут быть видны еще немного времени. Чтобы избежать этого, вы можете, например, изменить шим, чтобы прочитать ваш секрет из файла и добавить его к аргументам, передаваемым в программу.
источник
/proc/pid/cmdline
будет отображаться секрет (такой же, как приcurl
попытке скрыть пароль, который ему дается в командной строке). Пока вы используете LD_PRELOAD, вы можете обернуть main так, чтобы секрет копировался из окружения в argv, который получает main. Как звонить,LD_PRELOAD=x SECRET=y cmd
где вы звонитеmain()
сargv[]
существом[argv[0], getenv("SECRET")]
/proc/pid/environ
. Это может быть перезаписано так же, как аргументы, но оно оставляет то же самое окно./proc/pid/cmdline
публично,/proc/pid/environ
нет. Были некоторые системы, в которыхps
(исполняемый файл setuid) представлял окружение любого процесса, но я не думаю, что вы встретите это в наши дни. Окружающая среда обычно считается достаточно безопасной . Не безопасно извлекать информацию из процессов с одним и тем же euid, но они в любом случае часто могут читать память процессов одним и тем же euid, так что вы ничего не можете с этим поделать.main
метод упакованной программы, также удаляет переменную среды, чтобы избежать случайной утечки в дочерние процессы. Кроме того, оболочка может прочитать все аргументы командной строки из файла.Прочитайте документацию интерфейса командной строки рассматриваемого приложения. Вполне может быть возможность предоставить секрет из файла, а не в качестве аргумента напрямую.
Если это не удается, подайте отчет об ошибке в приложение на том основании, что не существует безопасного способа предоставить ему секрет.
Вы всегда можете тщательно (!) Адаптировать решение в ответе meuh на ваши конкретные потребности. Обратите особое внимание на комментарий Стефана и его последующие действия.
источник
Если вам нужно передать аргументы программе, чтобы она заработала, вам не повезет, что бы вы ни делали, если не можете использовать
hidepid
в procfs.Поскольку вы упомянули, что это скрипт bash, у вас уже должен быть доступный исходный код, поскольку bash не является скомпилированным языком.
В противном случае вы можете переписать командную строку процесса, используя
gdb
или подобное, и поигрывая сargc
/argv
после того, как он уже запущен, но:Я бы действительно порекомендовал получить исходный код или поговорить с продавцом, чтобы изменить код. Предоставление секретов в командной строке в операционной системе POSIX несовместимо с безопасной операцией.
источник
Когда процесс выполняет команду (через
execve()
системный вызов), его память стирается. Чтобы передать некоторую информацию во время выполнения,execve()
системные вызовы принимают для этого два аргумента:argv[]
иenvp[]
массивов.Это два массива строк:
argv[]
содержит аргументыenvp[]
содержит определения переменных среды в виде строк вvar=value
формате (по соглашению).Когда вы делаете:
(здесь добавлены пропущенные кавычки вокруг расширения параметра).
Вы выполняете
cmd
с секретом (value
), переданным вargv[]
иenvp[]
.argv[]
будет["cmd", "value"]
иenvp[]
что-то подобное[..., "PATH=/bin:...", "HOME=...", ..., "SECRET=value", "TERM=xterm", ...]
. Какcmd
не делает ничегоgetenv("SECRET")
или эквивалент, чтобы получить значение секрета из этогоSECRET
переменной среды , его помещение в среду бесполезно.argv[]
это общественное знание. Это показывает на выходеps
.envp[]
в наше время нет. На Linux это показывает в/proc/pid/environ
. Это показано в выходных данныхps ewww
на BSD (и с procps-ng вps
Linux), но только для процессов, работающих с одинаковым эффективным uid (и с большими ограничениями для исполняемых файлов setuid / setgid). Это может отображаться в некоторых журналах аудита, но эти журналы аудита должны быть доступны только администраторам.Короче говоря, среда, которая передается исполняемому файлу, должна быть частной или, по крайней мере, примерно такой же частной, как внутренняя память процесса (к которой при некоторых обстоятельствах другой процесс с соответствующими правами может также обращаться, например, с помощью отладчика и может также будет сброшен на диск).
Поскольку
argv[]
это общедоступное знание, команда, которая ожидает, что данные, предназначенные для секретности, в своей командной строке не работает.Обычно команды, которым необходимо дать секрет, предоставляют вам другой интерфейс для этого, например, через переменную окружения. Например:
Или с помощью специального файлового дескриптора, такого как stdin:
(
echo
будучи встроенным, он не отображается на выходеps
)Или файл, например,
.netrc
forftp
и несколько других команд илиНекоторые приложения, такие как
curl
(и это тоже подход @meuh здесь ), пытаются скрыть пароль, который они получилиargv[]
от посторонних глаз (в некоторых системах, перезаписывая часть памяти, гдеargv[]
хранились строки). Но это не очень помогает и дает ложное обещание безопасности. Это оставляет окно междуexecve()
и перезаписью, гдеps
все еще покажет секрет.Например, если злоумышленник знает, что вы выполняете скрипт, выполняющий
curl -u user:somesecret https://...
(например, в задании cron), все, что ему нужно сделать, - это удалить из кэша (много) библиотек, которыеcurl
используют (например, запустив ash -c 'a=a;while :; do a=$a$a;done'
), так как замедлить его запуск и даже делать очень неэффективноuntil grep 'curl.*[-]u' /proc/*/cmdline; do :; done
достаточно, чтобы поймать этот пароль в моих тестах.Если аргументы - единственный способ передать секрет командам, все же могут быть некоторые вещи, которые вы можете попробовать.
В некоторых системах, включая более старые версии Linux,
argv[]
могут быть запрошены только первые несколько байтов (4096 в Linux 4.1 и ранее) строк .Там вы можете сделать:
И секрет будет скрыт, потому что он прошел первые 4096 байтов. Теперь люди, которые использовали этот метод, должны сожалеть об этом сейчас, начиная с Linux, так как 4.2 больше не усекает список аргументов в
/proc/pid/cmdline
. Также обратите внимание, что это не потому, чтоps
в командной строке не будет отображаться больше, чем столько байтов (как во FreeBSD, где она ограничена 2048), которую нельзя использовать для того же API,ps
чтобы получить больше. Однако этот подход действителен в системах, гдеps
для обычного пользователя это единственный способ получить эту информацию (например, когда API является привилегированным и для негоps
используется setgid или setuid), но он все еще потенциально не предназначен для будущего.Другой подход заключается в том, чтобы не передавать секрет,
argv[]
а вводить код в программу (используяgdb
или$LD_PRELOAD
взломать) до ееmain()
запуска, которая вставляет секрет вargv[]
полученный отexecve()
.С
LD_PRELOAD
, для динамически связанных исполняемых файлов не-setuid / setgid в системе GNU:Потом:
Ни в коем случае
ps
не показал быps -opid,args
там (-opid,args
будучи секрет в этом примере). Обратите внимание, что мы заменяем элементыargv[]
массива указателей , не переопределяя строки, на которые указывают эти указатели, поэтому наши модификации не отображаются в выходных данныхps
.С
gdb
, все еще для динамически связанных исполняемых файлов не-setuid / setgid и в системах GNU:Тем не менее
gdb
, не специфичный для GNU подход, который не основан на динамическом связывании исполняемых файлов или имеет символы отладки и должен работать по крайней мере для любого исполняемого файла ELF в Linux, может быть следующим:Тестирование со статически связанным исполняемым файлом:
Когда исполняемый файл может быть статическим, у нас нет надежного способа выделить память для хранения секрета, поэтому мы должны получить секрет из другого места, которое уже находится в памяти процесса. Вот почему среда является очевидным выбором здесь. Мы также скрываем этот
SECRET
env var в процессе (изменяя его наSECRE=
), чтобы избежать его утечки, если процесс по какой-либо причине решит сбросить свою среду или выполнить ненадежные приложения.Это также работает на Solaris 11 ( при условии , GDB и GNU Binutils установлены (вы , возможно , придется переименовать
objdump
вgobjdump
).В FreeBSD ( по крайней мере , x86_64, я не уверен , что эти первые 24 байт (которые становятся 16 , когда GDB (8.0.1) является интерактивным предполагая что может быть ошибка в GDB там) на стеке), заменить
argc
иargv
определения с:(вам также может понадобиться установить
gdb
пакет / порт, поскольку версия, поставляемая с системой, устарела).источник
Что вы можете сделать, это
затем, если вы пишете свой язык
./program
C (или кто-то другой делает это и может изменить или улучшить его для вас), используйте getenv (3) в этой программе, возможно, каки после
export
вы просто запускаете./program
в одной оболочке. Или имя переменной среды может быть передано ему (запустив./program --secret-var=SECRET
etc ...)ps
не расскажу о вашей тайне, но proc (5) все равно может дать много информации (по крайней мере, другим процессам того же пользователя).Смотрите также это чтобы помочь разработать лучший способ передачи аргументов программы.
Смотрите этот ответ для лучшего объяснения глобализации и роли оболочки.
Возможно, у вас
program
есть и другие способы получить данные (или использовать межпроцессное взаимодействие более разумно), чем простые программные аргументы (это, безусловно, следует, если он предназначен для обработки конфиденциальной информации). Прочитайте его документацию. Или, возможно, вы злоупотребляете этой программой (которая не предназначена для обработки секретных данных).Скрывать секретные данные действительно сложно. Недостаточно передать его через аргументы программы.
источник
./program
, поэтому первую половину этого ответа , кажется, не будет актуальной.