GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wie verstecke ich ein als Befehlszeilenargument übergebenes Passwort?

Lösung 1:

Wirklich, das sollte in der Anwendung selbst behoben werden. Und solche Anwendungen sollten Open Source sein, sodass das Beheben des Problems in der App selbst eine Option sein sollte. Eine sicherheitsrelevante Anwendung, die diese Art von Fehlern macht, könnte auch andere Fehler machen, also würde ich ihr nicht vertrauen.

Einfacher Interposer

Aber Sie haben nach einem anderen Weg gefragt, also hier ist einer:

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

Kompilieren Sie dies mit

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

Führen Sie dann Ihren Prozess mit

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

Die Interposer-Bibliothek führt diesen Code vor main aus Funktion aus Ihrer Anwendung ausgeführt wird. Es ersetzt das letzte Kommandozeilenargument durch das tatsächliche Passwort im Aufruf von main. Die Befehlszeile wie in /proc/*/cmdline gedruckt (und daher von Tools wie ps gesehen ) enthält jedoch immer noch das falsche Argument. Offensichtlich müssten Sie den Quellcode und die Bibliothek, die Sie daraus kompilieren, nur für Sie selbst lesbar machen, arbeiten Sie also am besten in einem chmod 0700 Verzeichnis. Und da das Passwort nicht Teil des Befehlsaufrufs ist, ist auch Ihr Bash-Verlauf sicher.

Erweiterter Interposer

Wenn Sie etwas Ausführlicheres tun möchten, sollten Sie sich daran erinnern, dass __libc_start_main wird ausgeführt, bevor die Laufzeitbibliothek ordnungsgemäß initialisiert wurde. Daher würde ich vorschlagen, Funktionsaufrufe zu vermeiden, es sei denn, sie sind absolut notwendig. Wenn Sie nach Herzenslust Funktionen aufrufen können, tun Sie dies unbedingt kurz vor main selbst aufgerufen wird, nachdem die Initialisierung abgeschlossen ist. Für das folgende Beispiel muss ich mich bei Grubermensch bedanken, der darauf hinwies, wie man ein als Kommandozeilenargument übergebenes Passwort versteckt, das getpass brachte zu meiner Aufmerksamkeit.

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

Dies fordert zur Eingabe des Passworts auf, sodass Sie die Interposer-Bibliothek nicht länger geheim halten müssen. Das Platzhalter-Argument wird als Passwort-Eingabeaufforderung wiederverwendet, rufen Sie es also wie folgt auf

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

Eine andere Alternative würde das Passwort aus einem Dateideskriptor lesen (wie z.B. gpg --passphrase-fd tut) oder ab x11-ssh-askpass , oder was auch immer.

Lösung 2:

Es ist nicht nur die Geschichte. Es wird in ps angezeigt auch ausgegeben.

Wer auch immer dieses Stück Software geschrieben hat, sollte aufgehängt, gezeichnet und geviertelt werden. Es ist ein absolutes NEIN, ein Passwort auf der Befehlszeile eingeben zu müssen, unabhängig davon, um welche Software es sich handelt.
Für einen Daemon-Prozess ist es noch unverzeihlicher...

Neben rm -f Auf der Software selbst kenne ich keine Lösung dafür. Ehrlich gesagt:Finden Sie andere Software, um die Arbeit zu erledigen. Verwenden Sie keinen solchen Müll.

Lösung 3:

Dadurch wird ps gelöscht Ausgabe.

SEIEN SIE SEHR BEWUSST :Dies könnte die Anwendung beschädigen. Ihr seid gebührend gewarnt, dass hier Drachen sind.

  • Fremde Prozesse sollten nicht im Speicher eines Prozesses herumfummeln.
  • Wenn der Prozess für das Passwort auf diese Region angewiesen ist, können Sie Ihre Anwendung beschädigen.
  • Dadurch könnten alle Arbeitsdaten, die Sie in diesem Prozess haben, beschädigt werden.
  • Das ist ein wahnsinniger Hack.

Jetzt werden Sie ordnungsgemäß über diese düsteren Warnungen informiert. Dadurch wird die in ps angezeigte Ausgabe gelöscht . Es löscht weder Ihren Verlauf noch den Bash-Job-Verlauf (z. B. das Ausführen des Prozesses wie myprocess myargs & ). Aber ps zeigt die Argumente nicht mehr an.

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

Rufen Sie das Programm auf, indem Sie es speichern, chmod +x es. Dann mache ./whatever <pidoftarget> Wenn dies funktioniert, wird keine Ausgabe erzeugt. Wenn es fehlschlägt, wird es sich über etwas beschweren und beenden.

Lösung 4:

Können Sie das Argument aus einer Datei übergeben, auf die nur root oder der erforderliche Benutzer zugreifen kann?

Es ist ein RIESIGES No-No, Passwörter in die Konsole einzugeben, aber letzte Möglichkeit ... beginnen Sie Ihre Zeile mit einem Leerzeichen, damit sie nicht im Verlauf erscheint.

Lösung 5:

Vielleicht funktioniert das (?):

darkcoind masternode start `cat password.txt`

Linux
  1. Wie übergibt man ein Befehlszeilenargument an ein Shell-Skript?

  2. So starten Sie Linux über die Befehlszeile neu

  3. Maximale Länge des Befehlszeilenarguments, das an SQL*Plus übergeben werden kann?

  4. Wie übergebe ich ein Befehlszeilenargument beim Starten von GDB unter Linux?

  5. Wie gebe ich das Passwort für den Git-Pull-Befehl ein?

3 Passwort-Manager für die Linux-Kommandozeile

Wie verwende ich Proxy in der Linux-Befehlszeile?

So booten Sie in die Linux-Befehlszeile

So übergeben Sie das Passwort an den SSH-Befehl in Linux

So finden Sie die IP-Adresse in der Linux-Befehlszeile

So verwenden Sie das Passwortargument über die Befehlszeile für openssl zur Entschlüsselung