2010-09-30 15 views
21

Tengo un script que inicia dentro de sí un comando con un parámetro que es un secreto. Por ejemplo:Ocultar el secreto del parámetro de línea de comando en Unix

#!/bin/bash 
command-name secret 

Mientras se ejecuta el comando que puedo leer a través de ps -ef | grep command-name que es el secreto.

¿Hay alguna forma de ocultar el secreto de manera que a través del ps -ef, el parámetro de la línea de comando se ofusque?

+0

que hace el comando acepta el argumento secreto a través de un archivo de entrada o las corrientes? – Jeff

+0

Tenga en cuenta que el script en sí es legible, por lo que el secreto está visible para cualquier persona interesada en encontrarlo. Para que un usuario pueda ejecutar un script de shell, el script debe ser legible, o debe usar un programa SUID para ejecutar una copia protegida del script u otras contorsiones similares. –

+0

Aquí hay una buena respuesta: modifique/proc/PID/cmdline usando un truco de Scott James Remnant http://netsplit.com/hiding-arguments-from-ps – Martin

Respuesta

1

No hay una manera fácil. Echar un vistazo a esta pregunta que hice hace un tiempo:

Hide arguments from ps

Es command su propio programa? Puedes intentar encriptar el secreto y tener el command descifrándolo antes de usarlo.

+0

en su caso, el problema se solucionó configurando ad-hoc conf por leer la clave privada por defecto. En este caso, el problema es diferente. – Kerby82

+0

@ Kerby82: no, la situación es la misma; no hay forma de ocultar las opciones de línea de comando de 'ps'. –

+0

Esta es una pregunta diferente. En _su_ pregunta quería protegerse contra otras personas con los mismos derechos (usuario de Unix). En esta pregunta, se pregunta cómo ocultar un secreto a los demás usuarios de Unix. – VasyaNovikov

5

La única manera de ocultar su argumento secreto desde ps es no proporcionar el secreto como argumento. Una forma de hacerlo es colocar el secreto en un archivo, y para redirigir descriptor de archivo 3 para leer el archivo, y luego eliminar el archivo:

echo secret > x.$$ 
command 3<x.$$ 
rm -f x.$$ 

No está del todo claro que esta es una manera segura para guardar el secreto; el comando echo es un intérprete de comandos incorporado, por lo que no debería aparecer en la salida 'ps' (y cualquier aspecto sería fugaz). Hace mucho tiempo, echo no estaba incorporado; de hecho, en MacOS X, todavía hay un /bin/echo aunque está incorporado a todas las shells.

Por supuesto, esto supone que tiene el origen en command y puede modificarlo para leer el secreto de un descriptor de archivo abierto previamente en lugar de hacerlo desde el argumento de la línea de comando. Si no puede modificar el comando, está completamente atascado, la lista 'ps' mostrará la información.

Otro truco que podría utilizar si es el propietario del comando: podría capturar el argumento (secreto), escribirlo en una tubería o archivo (que se desvincula inmediatamente) y luego volver a ejecutar el comando sin el argumento secreto; la segunda invocación sabe que, dado que el secreto está ausente, debería verse dondequiera que la primera invocación ocultara el secreto. La segunda invocación (menos el secreto) es lo que aparece en la salida 'ps' después del intervalo minúsculo necesario para tratar de ocultar el secreto. No es tan bueno como tener el canal secreto configurado desde el principio. Pero estos son indicativos de la duración a la que debe ir.

Al cambiar un argumento desde dentro del programa - sobrescribir con ceros, por ejemplo - no se oculta el argumento de 'ps'.

+2

Agregaría un 'umask 077' antes del eco para asegurarme de que solo el usuario pueda leer el archivo. – JeremyP

+0

Si desea seguridad adicional, simplemente eliminar un archivo no eliminará su contenido.Guardar una contraseña en un archivo simple es inseguro. –

+1

@ JorgeFuentesGonzález: Y si se trata de un sistema de archivos de diario, la sobrescritura del archivo tampoco borrará el contenido anterior. –

4

La biblioteca expect se creó parcialmente para este tipo de cosas, por lo que aún puede proporcionar una contraseña/otra información confidencial a un proceso sin tener que pasarlo como argumento. Asumiendo que cuando no se da 'secreto' el programa lo pide, por supuesto.

+0

Uso espero a menudo para mantener las contraseñas entre otras cosas fuera de la línea de comandos. Se puede usar para iniciar sesión en sistemas remotos, responder a solicitudes de contraseña, etc. –

0

Si el script está diseñado para funcionar de forma manual, la mejor manera es para leerlo desde STDIN

#!/bin/bash 
read -s -p "Enter your secret: " secret 

command "$secret" 
+0

Bash 2.04 y posteriores tienen 'read -s' que no se hace eco de los caracteres de entrada, por lo que solo debe usar stty con shells que no lo hacen tener eso (zsh también lo tiene). –

+0

@Dennis Williamson: ¡Estupendo, no lo sabía! Gracias – Daenyth

+11

El problema con esto es que el secreto está expuesto en la línea de comandos y aparecerá en salida 'ps', pero la pregunta es cómo evitar esa exposición. –

8

Si el secreto no cambia entre ejecuciones, utilice un archivo de configuración especial, ".appsecrets". Establezca los permisos del archivo como de solo lectura por el propietario. Dentro del archivo establece una variable de entorno para el secreto. El archivo debe estar en el directorio de inicio del usuario que ejecuta el comando.

#!/bin/bash 
#filename: .appsecrets 
set SECRET=polkalover 

Cargue el archivo de configuración para que se establezca la variable de entorno.

. ~/.appsecrets 

Lo que he visto hacer:

1)
echo $SECRET | command

funciona si el comando solicita la contraseña de la entrada estándar y si 'eco' es una orden interna de su concha . Estábamos usando Korn.

2)
password=$ENV{"SECRET"};

funciona si usted tiene el control del código (por ejemplo, en Perl o C++)

3)
. ./.app.config #sets the environment variables
isql -host [host] -user [user] -password <<SECRET
${SQLPASSWORD}
SECRET

funciona si el comando se puede aceptar el secreto de std-in. Una limitación es que la cadena << tiene que ser el último argumento dado al comando. Esto podría ser problemático si hay un argumento no opcional que debe aparecer después de -contraseña

El beneficio de este enfoque es que puede organizarlo para que el secreto se pueda ocultar en la producción. Use el mismo nombre de archivo en producción, pero estará en el directorio principal de la cuenta que ejecuta el comando en producción. A continuación, puede bloquear el acceso al secreto como si tuviera acceso a la cuenta raíz. Solo ciertas personas pueden 'su' a la cuenta prod para ver o mantener el secreto mientras que los desarrolladores todavía pueden ejecutar el programa porque usan su propio archivo '.appsecret' en su directorio principal.

Puede utilizar este enfoque para almacenar información segura para cualquier cantidad de aplicaciones, siempre que utilicen nombres de variables de entorno diferentes para sus secretos.

(para mal)
Un método antiguo vi el uso DBA era establecer SYBASE a "/opt/././././././././././././././././././././././././././././././././././sybase/bin". Entonces sus líneas de comando eran tan largas que el ps lo truncó. Pero en Linux creo que es posible que puedas oler toda la línea de comandos desde/proc.

+3

'La línea de comando solo mostrará la variable de entorno determinada, no su valor' - Estos comentarios son ** INCORRECTO ** en dos aspectos. Primero, salpicar el archivo ~/.appsecrets ha restablecido los argumentos de línea de comandos del shell para tener solo uno, el valor de $ 1 ahora es 'SECRET = polkalover'; no hay variable, y mucho menos variable de entorno, llamada SECRETO. En segundo lugar, si obtiene un SECRETO variable creado (no duro), ejecutar 'comando $ SECRETO' expande $ SECRETO antes de ejecutar el comando, y 'ps' muestra la versión expandida de la información. –

+0

@jonathan - tienes razón. Estaba pensando en el enfoque C++ principalmente. He actualizado mi respuesta para mostrar el enfoque del guión. –

3

Lo vi en otra publicación. Esta es la forma más fácil en Linux.

Esto modifica la parte de memoria de la línea de comandos que todos los demás programas ven.

strncpy(argv[1], "randomtrash", strlen(argv[1])); 

También puede cambiar el nombre del proceso, pero solo cuando lo lea desde la línea de comando. Programas como top mostrarán el nombre del proceso real:

strncpy(argv[0], "New process name", strlen(argv[0])); 

No se olvide de copiar máximo strlen(argv[0]) bytes porque probablemente no hay más espacio asignado.

Creo que los argumentos solo se pueden encontrar en la parte de la memoria que modificamos, así que creo que esto funciona como un amuleto. Si alguien sabe algo sobre esto, por favor comente.

4
  1. En primer lugar, NO se puede ocultar un argumento de línea de comandos. Es visible a través de ps y cat /proc/$YOUR_PROCESS_PID/cmdline. La buena noticia es que aún puede tener un secreto al usar alternativas:

  2. Usar variables de entorno. Si el programa puede leer, hacer esto:

    # this is not a command so it does not show up in `ps` 
    mySecret='hello-neo' 
    
    export mySecret # you may need this sometimes. Skip this if your script works without this 
    
    myCommand # just launch the program and let it read the environment variables 
    
  3. Uso de entrada estándar:

    mySecret='hello-neo' 
    printenv mySecret | command 
    

Tenga en cuenta que nunca utilizamos $mySecret. El valor expandido no aparecerá en ps.

Quizás haya otras soluciones con stdin, ¡no dude en compartirlas!

  1. Use archivos:

    mySecret='hello-neo' command <(printenv mySecret) 
    

En este ejemplo estamos usando un truco de magia de fiesta <(). Cuando bash cumple esos símbolos, ejecutará el comando interno, capturará su stdout y lo "guardará" en un archivo temporal. El resultado de <() es un enlace al archivo temporal creado (un descriptor de archivo). Se ve como "/ dev/fd/67". El contenido de "/ dev/fd/67" es el texto "hello-neo". (En nuestro ejemplo.)

Así, en nuestro ejemplo, la expansión fiesta será:

mySecret='hello-neo' command <(printenv mySecret) 

=>

export mySecret='hello-neo' 
command <(printenv mySecret) 

=>

command <(printenv mySecret) # environment variable "mySecret" is already set to our secret 

=>

command /dev/fd/67 # a file "/dev/fd/67" is created, its contents are "hello-neo" 
+1

Sí puede, he visto programas enmascarar sus argumentos de línea de comandos con '*' todo el tiempo. Es así en la salida de 'ps -ef':'/xware/lib/EmbedThunderManager ****************************** ************ ' – Meow

+1

Pero esos argumentos pueden probablemente ser extraídos de/proc en alguna parte. En su caso, parece que ps puede estar truncando porque están ingresando los "secretos" después de una larga cadena de *. –

+0

@Meow eso está completamente mal. Pruebe, por ejemplo, 'htop' en lugar de' ps'. Simplemente te permite desplazarte hacia la derecha, por el tiempo que desees. – VasyaNovikov

0

puede ser que usted puede hacer como esto:

#include <boost/algorithm/string/predicate.hpp> 
void hide(int argc, char** argv, std::string const & arg){ 
    for(char** current = argv; current != argv+ argc ;++current){ 
     if(boost::algorithm::starts_with(*current, "--"+arg)){ 
      bzero(*current, strlen(*current)); 
     } 
    } 
} 
int main(int argc, char** argv){ 
    hide(argc, argv, "password"); 
} 
Cuestiones relacionadas