GNU/Linux >> Znalost Linux >  >> Linux

Jak skrýt heslo předané jako argument příkazového řádku?

Řešení 1:

Opravdu, to by mělo opravit v samotné aplikaci. A takové aplikace by měly být open source, takže řešení problému v samotné aplikaci by mělo být možností. Aplikace související se zabezpečením, která dělá tento druh chyby, může dělat i jiné chyby, takže bych jí nevěřil.

Jednoduchý interposer

Ale ptali jste se na jiný způsob, takže tady je jeden:

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

Zkompilujte to pomocí

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

pak spusťte proces pomocí

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

Knihovna interposeru spustí tento kód před main funkce z vaší aplikace se spustí. Nahradí poslední argument příkazového řádku skutečným heslem ve volání main. Příkazový řádek vytištěný v /proc/*/cmdline (a proto je vidět pomocí nástrojů jako ps ) však bude stále obsahovat falešný argument. Je zřejmé, že byste museli zdrojový kód a knihovnu, kterou z něj kompilujete, učinit tak, aby byly čitelné pouze pro vás, takže je nejlepší pracovat v chmod 0700 adresář. A protože heslo není součástí vyvolání příkazu, vaše historie bash je také bezpečná.

Pokročilejší interposer

Pokud chcete udělat něco propracovanějšího, měli byste mít na paměti, že __libc_start_main se spustí před řádnou inicializací runtime knihovny. Navrhoval bych tedy vyhnout se jakýmkoli voláním funkcí, pokud nejsou absolutně nezbytné. Pokud chcete mít možnost volat funkce podle svých představ, ujistěte se, že tak učiníte těsně před main po dokončení všech inicializací se sám vyvolá. Za následující příklad musím poděkovat Grubermenschovi, který poukázal na to, jak skrýt heslo předané jako argument příkazového řádku, který přinesl getpass do mé pozornosti.

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

To vás vyzve k zadání hesla, takže knihovnu interposeru již nemusíte udržovat v tajnosti. Argument zástupného symbolu je znovu použit jako výzva k zadání hesla, takže jej vyvolejte jako

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

Další alternativou by bylo čtení hesla z deskriptoru souboru (jako např. gpg --passphrase-fd dělá), nebo z x11-ssh-askpass nebo cokoliv jiného.

Řešení 2:

Nejde jen o historii. Zobrazí se v ps výstup také.

Kdokoli napsal ten kus softwaru, měl by být zavěšen, nakreslen a rozčtvrcen. Je absolutní NE muset zadat heslo na příkazovém řádku bez ohledu na to, jaký software to je.
Pro proces démona je to ještě NEPROPUSTITELNĚJŠÍ...

Kromě rm -f na samotném softwaru neznám žádné řešení pro toto. Upřímně řečeno:Najděte si jiný software, abyste svou práci zvládli. Nepoužívejte takový odpad.

Řešení 3:

Tím se vymaže ps výstup.

BUĎTE VELMI VĚDOMÍ :Mohlo by to přerušit aplikaci. Jste řádně varováni, aby zde byli draci.

  • Cizí procesy by se neměly pohrávat v paměti procesů.
  • Pokud proces závisí na této oblasti jako heslo, můžete svou aplikaci přerušit.
  • Můžete tím poškodit veškerá pracovní data, která v tomto procesu máte.
  • Toto je šílený hack.

Nyní jste na tato strašná varování řádně upozorněni. Tím vymažete výstup zobrazený v ps . Nevymaže vaši historii ani nevymaže historii úloh bash (například spuštění procesu jako myprocess myargs & ). Ale ps již nebude zobrazovat argumenty.

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

Vyvolejte program jeho uložením, chmod +x to. Poté proveďte ./whatever <pidoftarget> Pokud to funguje, nebude to produkovat žádný výstup. Pokud selže, bude si na něco stěžovat a skončí.

Řešení 4:

Můžete předat argument ze souboru, ke kterému má přístup pouze root nebo požadovaný uživatel?

Zadávat hesla do konzole je VELKÉ NE-NE, ale poslední možnost...začněte řádek mezerou, aby se neobjevila v historii.

Řešení 5:

Možná to funguje (?):

darkcoind masternode start `cat password.txt`

Linux
  1. Jak předat argument příkazového řádku do skriptu Shell?

  2. Jak vytvořit hash hesel Sha512 na příkazovém řádku?

  3. Jak restartovat Linux pomocí příkazového řádku

  1. 6 Očekávejte příklady argumentů příkazového řádku skriptu

  2. Maximální délka argumentu příkazového řádku, který lze předat SQL*Plus?

  3. Jak předám argument příkazového řádku při spouštění GDB v Linuxu?

  1. Jak změnit heslo v Linuxu (příkaz passwd)

  2. Jak předat heslo příkazu SCP v Linuxu

  3. Jak zadat heslo do příkazu git pull?