$ k=v p &
[1] 3028
existe alguma maneira de p
alterar o conteúdo de /proc/3028/environ
não mencionar k=v
enquanto p
ainda está em execução?
linux
security
process
linux-kernel
environment-variables
Cetin Sert
fonte
fonte
Respostas:
No Linux, você pode sobrescrever o valor das seqüências de caracteres do ambiente na pilha.
Para ocultar a entrada, substitua-a por zeros ou qualquer outra coisa:
Correr como:
o
k=v
foi substituído por\0\0\0
.Observe que,
setenv("k", "", 1)
para substituir o valor, não funcionará, pois, nesse caso, uma nova"k="
string é alocada.Se você não modificou a
k
variável de ambiente comsetenv()
/putenv()
, também poderá fazer algo assim para obter o endereço dak=v
string na pilha (bem, de uma delas):Observe, no entanto, que ele remove apenas uma das
k=v
entradas recebidas no ambiente. Geralmente, há apenas um, mas nada impede que alguém passe ambosk=v1
ek=v2
(ouk=v
duas vezes) na lista env enviada paraexecve()
. Essa foi a causa de vulnerabilidades de segurança no passado, como o CVE-2016-2381 . Isso poderia realmente acontecerbash
antes do shellshock ao exportar uma variável e uma função com o mesmo nome.De qualquer forma, sempre haverá uma pequena janela durante a qual a cadeia env var ainda não foi substituída, portanto, você pode querer encontrar outra maneira de passar as informações secretas para o comando (como um canal por exemplo), se for exposto via
/proc/pid/environ
é uma preocupação.Observe também que
/proc/pid/cmdline
, ao contrário de ,/proc/pid/environment
só é acessível por processos com o mesmo euid ou raiz (ou raiz somente se o euid e o ruid do processo não forem os mesmos que parecem).Você pode ocultar esse valor deles
/proc/pid/environ
, mas eles ainda podem obter qualquer outra cópia que você tenha feito da string na memória, por exemplo, anexando um depurador a ela.Consulte https://www.kernel.org/doc/Documentation/security/Yama.txt para obter formas de impedir que pelo menos usuários não root façam isso.
fonte
Não é necessário sobrescrever as strings acima ( na verdade não estão ) a pilha do thread principal no Linux desde 2010.
Ambos
/proc/self/cmdline
e/proc/self/environ
são modificáveis pelo próprio processo em tempo de execução, por chamar aprctl()
função com respectivamentePR_SET_MM_ARG_START
+PR_SET_MM_ARG_END
ouPR_SET_MM_ENV_START
+PR_SET_MM_ENV_END
. Eles configuram diretamente os ponteiros de memória no espaço de memória do aplicativo do processo, mantido pelo kernel para cada processo, usado para recuperar o conteúdo/proc/${PID}/cmdline
e/proc/${PID}/environ
, portanto, a linha de comando e o ambiente relatados pelops
comando.Portanto, basta construir um novo argumento ou string de ambiente (não vetor, observe - a memória apontada deve ser os dados reais da string, concatenados e
␀
delimitados) e informar ao kernel onde está.Isso está documentado na página de manual do Linux para a
prctl(2)
função e também naenviron(7)
página de manual. O que não está documentado é que o kernel rejeita qualquer tentativa de definir o endereço inicial acima do endereço final ou o endereço final abaixo do endereço inicial; ou para (re) definir um endereço para zero. Além disso, esse não é o mecanismo original proposto por Bryan Donlan em 2009, que permitiu definir atomicamente o início e o fim de uma única operação. Além disso, o kernel não fornece como obter os valores atuais desses ponteiros.Isso torna difícil modificar o ambiente e as áreas da linha de comando
prctl()
. É necessário chamar aprctl()
função até quatro vezes, porque as primeiras tentativas podem resultar em tentativas de definir o ponteiro inicial mais alto que o ponteiro final, dependendo de onde os dados antigos e novos estão na memória. É preciso chamá-lo mais quatro vezes se quiser garantir que isso não resulte em uma janela de oportunidade para outros processos no sistema inspecionarem um intervalo arbitrário do espaço de memória do processo no período em que o novo início / fim foi definido, mas o novo final / início não foi.Uma única chamada de sistema atômico que define todo o intervalo de uma só vez seria muito mais fácil para os aplicativos usarem com segurança.
Outra desvantagem é que, por nenhuma razão realmente boa (dadas as verificações no kernel, a sobregravabilidade das áreas de dados originais de qualquer maneira e o fato de os equivalentes não serem operações privilegiadas em nenhum dos BSDs), no Linux isso requer superusuário privilégios.
Eu escrevi bastante simples
setprocargv()
esetprocenvv()
funções para meus conjuntos de ferramentas, que empregam isso. Os programas de carregamento em cadeia dos conjuntos de ferramentas integrados, comosetenv
eforeground
, refletem os argumentos e o ambiente encadeados para o comando, onde o Linux permite.Observe que isso não milita contra coisas que rastreiam o processo e acessam sua memória diretamente por outros meios (e não através desses dois pseudo-arquivos) e, é claro, deixa uma janela antes que as strings sejam modificadas, onde essas informações podem ser vistas, apenas como sobrescrever os dados acima da pilha do encadeamento principal. E, como é o caso da substituição dos dados, isso não leva em consideração as bibliotecas de tempo de execução de idiomas que fazem cópias do ambiente (na pilha) em várias circunstâncias. Em geral, não considere isso um mecanismo tão bom para passar "segredos" para um programa quanto (digamos) tê-lo herdado um descritor de arquivo aberto para o final de leitura de um canal sem nome, lido em um buffer de entrada totalmente sob seu controle que você então limpa.
Leitura adicional
fonte
/proc/$pid/stat
(além de outros valores que você pode precisar emstruct prctl_mm_map
). Veja também meu exemplo filter_env.c para uma pequena demonstração. JdeBP, você pode adicionar links para suassetprocargv()
/setprocenvv()
funções?