GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cómo ocultar una contraseña pasada como argumento de línea de comando?

Solución 1:

Realmente, esto debería fijarse en la propia aplicación. Y tales aplicaciones deberían ser de código abierto, por lo que solucionar el problema en la propia aplicación debería ser una opción. Una aplicación relacionada con la seguridad que comete este tipo de error también podría cometer otros errores, por lo que no confiaría en ella.

Intercalador simple

Pero estabas preguntando por una forma diferente, así que aquí tienes una:

#define _GNU_SOURCE
#include <dlfcn.h>

int __libc_start_main(
    int (*main) (int, char * *, char * *),
    int argc, char * * ubp_av,
    void (*init) (void),
    void (*fini) (void),
    void (*rtld_fini) (void),
    void (* stack_end)
  )
{
  int (*next)(
    int (*main) (int, char * *, char * *),
    int argc, char * * ubp_av,
    void (*init) (void),
    void (*fini) (void),
    void (*rtld_fini) (void),
    void (* stack_end)
  ) = dlsym(RTLD_NEXT, "__libc_start_main");
  ubp_av[argc - 1] = "secret password";
  return next(main, argc, ubp_av, init, fini, rtld_fini, stack_end);
}

Compile esto con

gcc -O2 -fPIC -shared -o injectpassword.so injectpassword.c -ldl

luego ejecuta tu proceso con

LD_PRELOAD=$PWD/injectpassword.so darkcoind masternode start fakepasshrase

La biblioteca de interposición ejecutará este código antes del main La función de su aplicación se ejecuta. Reemplazará el último argumento de la línea de comando por la contraseña real en la llamada a main. La línea de comando impresa en /proc/*/cmdline (y por lo tanto visto por herramientas como ps ) seguirá conteniendo el argumento falso, sin embargo. Obviamente, tendrías que hacer que el código fuente y la biblioteca que compilas solo sean legibles para ti, así que es mejor operar en un chmod 0700 directorio. Y dado que la contraseña no forma parte de la invocación del comando, su historial de bash también está seguro.

Interposición más avanzada

Si quieres hacer algo más elaborado, debes tener en cuenta que __libc_start_main se ejecuta antes de que la biblioteca de tiempo de ejecución se haya inicializado correctamente. Por lo tanto, sugiero evitar cualquier llamada de función a menos que sea absolutamente esencial. Si desea poder llamar funciones a su gusto, asegúrese de hacerlo justo antes del main se invoca a sí mismo, después de que se realiza toda la inicialización. Para el siguiente ejemplo, debo agradecer a Grubermensch, quien señaló cómo ocultar una contraseña pasada como argumento de línea de comando que trajo getpass a mi atención.

#define _GNU_SOURCE
#include <dlfcn.h>
#include <unistd.h>

static int (*real_main) (int, char * *, char * *);

static int my_main(int argc, char * * argv, char * * env) {
  char *pass = getpass(argv[argc - 1]);
  if (pass == NULL) return 1;
  argv[argc - 1] = pass;
  return real_main(argc, argv, env);
}

int __libc_start_main(
    int (*main) (int, char * *, char * *),
    int argc, char * * ubp_av,
    void (*init) (void),
    void (*fini) (void),
    void (*rtld_fini) (void),
    void (* stack_end)
  )
{
  int (*next)(
    int (*main) (int, char * *, char * *),
    int argc, char * * ubp_av,
    void (*init) (void),
    void (*fini) (void),
    void (*rtld_fini) (void),
    void (* stack_end)
  ) = dlsym(RTLD_NEXT, "__libc_start_main");
  real_main = main;
  return next(my_main, argc, ubp_av, init, fini, rtld_fini, stack_end);
}

Esto le solicita la contraseña, por lo que ya no tiene que mantener en secreto la biblioteca de interposición. El argumento de marcador de posición se reutiliza como solicitud de contraseña, así que invoque esto como

LD_PRELOAD=$PWD/injectpassword.so darkcoind masternode start "Password: "

Otra alternativa sería leer la contraseña de un descriptor de archivo (como, por ejemplo, gpg --passphrase-fd lo hace), o desde x11-ssh-askpass , o lo que sea.

Solución 2:

No es solo la historia. Aparecerá en ps salida también.

Quienquiera que haya escrito esa pieza de software debería ser ahorcado, descuartizado y descuartizado. Es absolutamente NO tener que proporcionar una contraseña en la línea de comandos, independientemente del software que sea.
Para un proceso daemon es aún MÁS imperdonable...

Además de rm -f en el software en sí no conozco ninguna solución para esto. Honestamente:encuentre otro software para hacer el trabajo. No uses esa basura.

Solución 3:

Esto borrará el ps salida.

SÉ MUY CONSCIENTE :Esto podría romper la aplicación. Estás debidamente advertido de que aquí habrá dragones.

  • Los procesos extraños no deberían estar jugando en la memoria de un proceso.
  • Si el proceso se basa en esta región para la contraseña, puede romper su aplicación.
  • Hacer esto podría dañar cualquier dato de trabajo que tenga en ese proceso.
  • Este es un truco demente.

Ahora estás debidamente notificado de estas terribles advertencias. Esto borrará la salida que se muestra en ps . No borrará su historial, ni borrará el historial de trabajos de bash (como ejecutar el proceso como myprocess myargs & ). Pero ps ya no mostrará los argumentos.

#!/usr/bin/python
import os, sys
import re

PAGESIZE=4096

if __name__ == "__main__":
  if len(sys.argv) < 2:
    sys.stderr.write("Must provide a pid\n")
    sys.exit(1)

  pid = sys.argv[1]

  try:
    cmdline = open("/proc/{0}/cmdline".format(pid)).read(8192)

    ## On linux, at least, argv is located in the stack. This is likely o/s
    ## independent.
    ## Open the maps file and obtain the stack address.
    maps = open("/proc/{0}/maps".format(pid)).read(65536)
    m = re.search('([0-9a-f]+)-([0-9a-f]+)\s+rw.+\[stack\]\n', maps)
    if not m:
      sys.stderr.write("Could not find stack in process\n");
      sys.exit(1)

    start = int("0x"+m.group(1), 0)
    end = int("0x"+m.group(2), 0)

    ## Open the mem file
    mem = open('/proc/{0}/mem'.format(pid), 'r+')
    ## As the stack grows downwards, start at the end. It is expected
    ## that the value we are looking for will be at the top of the stack
    ## somewhere
    ## Seek to the end of the stack minus a couple of pages.
    mem.seek(end-(2*PAGESIZE))

    ## Read this buffer to the end of the stack
    stackportion = mem.read(8192)
    ## look for a string matching cmdline. This is pretty dangerous.
    ## HERE BE DRAGONS
    m = re.search(cmdline, stackportion)
    if not m:
      ## cause this is an example dont try to search exhaustively, just give up
      sys.stderr.write("Could not find command line in the stack. Giving up.")
      sys.exit(1)

    ## Else, we got a hit. Rewind our file descriptor, plus where we found the first argument.
    mem.seek(end-(2*PAGESIZE)+m.start())
    ## Additionally, we'll keep arg0, as thats the program name.
    arg0len = len(cmdline.split("\x00")[0]) + 1
    mem.seek(arg0len, 1)

    ## lastly overwrite the remaining region with nulls.
    writeover = "\x00" * (len(cmdline)-arg0len)
    mem.write(writeover)

    ## cleanup
    mem.close()

  except OSError, IOError:
    sys.stderr.write("Cannot find pid\n")
    sys.exit(1)

Invoque el programa guardándolo, chmod +x eso. Luego haciendo ./whatever <pidoftarget> Si esto funciona, no producirá ningún resultado. Si falla, se quejará de algo y abandonará.

Solución 4:

¿Puedes pasar el argumento desde un archivo, al que solo puede acceder root o el usuario requerido?

Es un ENORME no-no escribir contraseñas en la consola, pero último recurso... comienza tu línea con un espacio para que no aparezca en el historial.

Solución 5:

Tal vez esto funcione (?):

darkcoind masternode start `cat password.txt`

Linux
  1. Cómo borrar el historial de línea de comandos BASH en Linux

  2. ¿Cómo pasar un argumento de línea de comando a un script de Shell?

  3. ¿Cómo crear hashes de contraseña Sha512 en la línea de comandos?

  4. 6 Ejemplos de argumentos de línea de comando de secuencia de comandos esperada

  5. ¿Longitud máxima del argumento de la línea de comando que se puede pasar a SQL * Plus?

3 gestores de contraseñas para la línea de comandos de Linux

¿Cómo usar el proxy en la línea de comandos de Linux?

Cómo iniciar en la línea de comandos de Linux

Cómo pasar la contraseña al comando SSH en Linux

Cómo encontrar la dirección IP en la línea de comandos de Linux

Cómo usar el argumento de la contraseña a través de la línea de comandos para abrir SSL para el descifrado