Ř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`