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`