GNU/Linux >> Tutoriels Linux >  >> Linux

Comment masquer un mot de passe passé en argument de ligne de commande ?

Solution 1 :

Vraiment, cela devrait être fixé dans l'application elle-même. Et ces applications devraient être open source, de sorte que la résolution du problème dans l'application elle-même devrait être une option. Une application liée à la sécurité qui fait ce genre d'erreur peut également en faire d'autres, donc je ne lui ferais pas confiance.

Interposeur simple

Mais vous demandiez une méthode différente, alors en voici une :

#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);
}

Compilez ceci avec

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

puis exécutez votre processus avec

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

La bibliothèque d'interposition exécutera ce code avant le main fonction de votre application est exécutée. Il remplacera le dernier argument de la ligne de commande par le mot de passe réel dans l'appel à main. La ligne de commande telle qu'imprimée dans /proc/*/cmdline (et donc vu par des outils comme ps ) contiendra toujours le faux argument. Évidemment, vous devez rendre le code source et la bibliothèque que vous compilez à partir de celui-ci lisibles uniquement par vous-même, il est donc préférable de fonctionner dans un chmod 0700 annuaire. Et comme le mot de passe ne fait pas partie de l'invocation de la commande, votre historique bash est également sécurisé.

Interposeur plus avancé

Si vous voulez faire quelque chose de plus élaboré, vous devez garder à l'esprit que __libc_start_main est exécuté avant que la bibliothèque d'exécution ait été correctement initialisée. Je suggérerais donc d'éviter tout appel de fonction à moins qu'il ne soit absolument essentiel. Si vous voulez pouvoir appeler des fonctions à votre guise, assurez-vous de le faire juste avant main lui-même est appelé, une fois l'initialisation terminée. Pour l'exemple suivant, je dois remercier Grubermensch qui a indiqué comment masquer un mot de passe passé en argument de ligne de commande qui a apporté getpass à mon attention.

#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);
}

Cela vous demande le mot de passe, vous n'avez donc plus à garder secrète la bibliothèque de l'interposeur. L'argument d'espace réservé est réutilisé comme invite de mot de passe, alors invoquez-le comme

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

Une autre alternative serait de lire le mot de passe à partir d'un descripteur de fichier (comme par exemple gpg --passphrase-fd fait), ou de x11-ssh-askpass , ou quoi que ce soit.

Solution 2 :

Ce n'est pas seulement l'histoire. Il va apparaître dans ps sortie également.

Celui qui a écrit ce logiciel devrait être pendu, dessiné et écartelé. C'est un NON absolu de devoir fournir un mot de passe sur la ligne de commande, quel que soit le logiciel.
Pour un processus démon c'est encore PLUS impardonnable...

Outre rm -f sur le logiciel lui-même, je ne connais aucune solution pour cela. Honnêtement :Trouvez d'autres logiciels pour faire le travail. N'utilisez pas ces déchets.

Solution 3 :

Cela effacera le ps sortie.

SOYEZ TRÈS CONSCIENT :Cela pourrait casser l'application. Vous êtes dûment averti qu'il y a ici des dragons.

  • Les processus étrangers ne doivent pas bricoler dans la mémoire d'un processus.
  • Si le processus s'appuie sur cette région pour le mot de passe, vous risquez de casser votre application.
  • Cela pourrait corrompre toutes les données de travail dont vous disposez au cours de ce processus.
  • C'est un hack insensé.

Maintenant, vous êtes dûment informé de ces terribles avertissements. Cela effacera la sortie affichée dans ps . Cela n'effacera pas votre historique, ni l'historique des tâches bash (comme l'exécution du processus comme myprocess myargs & ). Mais ps n'affichera plus les arguments.

#!/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)

Appelez le programme en le sauvegardant, chmod +x ce. Puis faire ./whatever <pidoftarget> Si cela fonctionne, il ne produira aucune sortie. S'il échoue, il se plaindra de quelque chose et abandonnera.

Solution 4 :

Pouvez-vous passer l'argument à partir d'un fichier, accessible uniquement par root ou l'utilisateur requis ?

C'est un ÉNORME non-non de taper des mots de passe dans la console, mais dernier recours... commencez votre ligne par un espace pour qu'elle n'apparaisse pas dans l'historique.

Solution 5 :

Peut-être que ça marche (?) :

darkcoind masternode start `cat password.txt`

Linux
  1. Comment créer des hachages de mot de passe Sha512 sur la ligne de commande ?

  2. Comment analyser chaque ligne d'un fichier texte comme argument d'une commande ?

  3. Comment redémarrer Linux en utilisant la ligne de commande

  4. 6 Attendez-vous à des exemples d'arguments de ligne de commande de script

  5. Longueur maximale de l'argument de ligne de commande pouvant être transmis à SQL*Plus ?

3 gestionnaires de mots de passe pour la ligne de commande Linux

Comment utiliser le proxy sur la ligne de commande Linux ?

Comment démarrer en ligne de commande Linux

Comment transmettre un mot de passe à la commande SSH sous Linux

Comment trouver une adresse IP dans la ligne de commande Linux

Comment utiliser l'argument de mot de passe via la ligne de commande pour openssl pour le déchiffrement