$ k=v p &
[1] 3028
Есть ли способ p
изменить содержимое, /proc/3028/environ
чтобы не упоминать, k=v
пока p
работает?
linux
security
process
linux-kernel
environment-variables
Цетин Серт
источник
источник
Ответы:
В Linux вы можете перезаписать значение строк окружения в стеке.
Таким образом, вы можете скрыть запись, переписав ее нулями или чем-то еще:
Беги как:
k=v
был перезаписан\0\0\0
.Обратите внимание, что
setenv("k", "", 1)
перезапись значения не будет работать, так как в этом случае выделяется новая"k="
строка.Если вы не изменили
k
переменную окружения с помощьюsetenv()
/putenv()
, то вы также должны сделать что-то вроде этого, чтобы получить адресk=v
строки в стеке (ну, одного из них):Обратите внимание, что он удаляет только одну из
k=v
записей, полученных в среде. Обычно есть только один, но ничто не мешает кому-либо передать обаk=v1
иk=v2
(илиk=v
два раза) в список env, переданныйexecve()
. Это было причиной уязвимостей в прошлом, таких как CVE-2016-2381 . Это может действительно произойтиbash
до «шеллшока» при экспорте переменной и функции с одним и тем же именем.В любом случае всегда будет маленькое окно, в течение которого строка env var еще не была переопределена, поэтому вы можете захотеть найти другой способ передачи секретной информации в команду (например, конвейер), если вы предоставляете ее через
/proc/pid/environ
это проблема.Также обратите внимание, что, в отличие от
/proc/pid/cmdline
,/proc/pid/environment
доступен только процессам с одинаковым euid или root (или root только если euid и ruid процесса не совпадают).Вы можете скрыть это значение от них
/proc/pid/environ
, но они все равно смогут получить любую другую копию строки, которую вы сделали, например, подключив к ней отладчик.См. Https://www.kernel.org/doc/Documentation/security/Yama.txt, чтобы узнать, как это сделать, по крайней мере, пользователям без полномочий root.
источник
Это не было необходимо переписать строки выше ( на самом деле не на ) стека основного потока на Linux с 2010 года.
Оба
/proc/self/cmdline
и/proc/self/environ
могут быть изменены самим процессом во время выполнения, путем вызоваprctl()
функции с соответственноPR_SET_MM_ARG_START
+PR_SET_MM_ARG_END
илиPR_SET_MM_ENV_START
+PR_SET_MM_ENV_END
. Они непосредственно устанавливают указатели памяти в пространство памяти приложения процесса, которое хранится в ядре для каждого процесса, которые используются для извлечения содержимого/proc/${PID}/cmdline
и/proc/${PID}/environ
, и, следовательно, командной строки и среды, сообщаемыхps
командой.Поэтому нужно просто создать новый аргумент или строку окружения (не вектор, обратите внимание -
␀
указанная память должна быть фактическими строковыми данными, объединенными и -delimited) и сообщить ядру, где оно находится.Это задокументировано на странице руководства Linux для этой
prctl(2)
функции, а также наenviron(7)
странице руководства. Что не задокументировано, так это то, что ядро отклоняет любую попытку установить начальный адрес выше конечного адреса или конечный адрес ниже начального адреса; или (пере) установить любой адрес на ноль. Кроме того, это не оригинальный механизм, предложенный Брайаном Донланом в 2009 году, который позволял устанавливать начало и конец одной операции, атомарно. Более того, ядро не предоставляет способа получить текущие значения этих указателей.Это затрудняет изменение среды и областей командной строки с помощью
prctl()
. Необходимо вызыватьprctl()
функцию до четырех раз, потому что первые попытки могут привести к попыткам установить начальный указатель выше конечного указателя, в зависимости от того, где старые и новые данные находятся в памяти. Нужно вызывать его еще четыре раза, если вы хотите убедиться, что это не приведет к тому, что другие процессы в системе получат возможность проверить произвольный диапазон пространства памяти процесса в период, когда начинается новый запуск. был установлен, но новый конец / начало не было.Один атомарный системный вызов, который устанавливает весь диапазон за один раз, был бы намного проще для прикладных программ в безопасном использовании.
Еще одна проблема заключается в том, что без веской причины (учитывая проверки в ядре, перезаписываемость исходных областей данных в любом случае и тот факт, что эквиваленты не являются привилегированными операциями ни на одной из BSD), в Linux это требует суперпользователя. привилегии.
Я написал довольно простые
setprocargv()
иsetprocenvv()
функции для своих наборов инструментов, которые используют это. Программы с цепочечной загрузкой из наборов инструментов, которые являются встроенными, например,setenv
иforeground
, таким образом, отражают аргументы цепочки команд и среду, в которой это позволяет Linux.Обратите внимание, что это не препятствует вещам, которые отслеживают процесс и получают доступ к его памяти напрямую другими способами (а не через эти два псевдофайла), и, конечно, оставляет окно перед изменением строк, где эта информация может быть видна, просто как и при перезаписи данных над стеком основного потока. И так же, как в случае с перезаписью данных, это не учитывает библиотеки времени выполнения, которые делают копии среды (в куче) при различных обстоятельствах. В общем, не рассматривайте это как такой же хороший механизм для передачи «секретов» программе, как (скажем), когда она наследует дескриптор открытого файла в конец чтения безымянного канала, считываемого во входной буфер полностью под вашим контролем что вы потом вытрите.
дальнейшее чтение
источник
/proc/$pid/stat
(помимо других значений , которые вы , возможно , потребуется вstruct prctl_mm_map
). Смотрите также мой пример filter_env.c для небольшой демонстрации. JdeBP, вы можете добавить ссылки на вашиsetprocargv()
/setprocenvv()
функции?