На самом деле, это должно быть исправлено в самом приложении. И такие приложения должны быть с открытым исходным кодом, так что решение проблемы в самом приложении должно быть вариантом. Приложение, связанное с безопасностью, которое допускает такую ошибку, может допускать и другие ошибки, поэтому я бы ему не доверял.
Но вы просили другой способ, поэтому вот один:
#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);
}
Скомпилируйте его с помощью
gcc -O2 -fPIC -shared -o injectpassword.so injectpassword.c -ldl
, затем запустите свой процесс с помощью
LD_PRELOAD=$PWD/injectpassword.so darkcoind masternode start fakepasshrase
Библиотека интерпозера запустит этот код до того, как будет выполнена функция main
из вашего приложения. Он заменит последний аргумент командной строки фактическим паролем при вызове main. Однако командная строка, напечатанная в / proc / * / cmdline
(и, следовательно, видимая такими инструментами, как ps
), все равно будет содержать ложный аргумент. Очевидно, вам придется сделать исходный код и компилируемую из него библиотеку доступными для чтения только вам, поэтому лучше всего работать в каталоге chmod 0700
. А поскольку пароль не является частью вызова команды, ваша история bash тоже безопасна.
Если вы хотите сделать что-нибудь более сложное, вы должны помнить, что __ libc_start_main
запускается до того, как библиотека времени выполнения будет правильно инициализирована. Поэтому я бы посоветовал избегать любых вызовов функций, если они не являются абсолютно необходимыми. Если вы хотите иметь возможность вызывать функции, сколько душе угодно, убедитесь, что вы сделали это непосредственно перед тем, как main
будет вызван, после завершения всех инициализаций. В следующем примере я должен поблагодарить Grubermensch, который указал , как скрыть пароль, переданный в качестве аргумента командной строки , который привлек мое внимание getpass
.
#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);
}
Это запрашивает пароль, так что вам больше не нужно держать библиотеку интерпозера в секрете. Аргумент заполнителя повторно используется в качестве запроса пароля, поэтому вызовите его, как
LD_PRELOAD=$PWD/injectpassword.so darkcoind masternode start "Password: "
. Другой альтернативой будет считывание пароля из файлового дескриптора (например, gpg --passphrase-fd
) или из x11 -ssh-askpass
или что угодно.
getpass
.
#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);
}
Это запрашивает пароль, так что вам больше не нужно держать библиотеку интерпозера в секрете. Аргумент заполнителя повторно используется в качестве запроса пароля, поэтому вызовите его, как
LD_PRELOAD=$PWD/injectpassword.so darkcoind masternode start "Password: "
. Другой альтернативой будет считывание пароля из файлового дескриптора (например, gpg --passphrase-fd
) или из x11 -ssh-askpass
или что угодно.
getpass
.
#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);
}
Это запрашивает пароль, так что вам больше не нужно держать библиотеку интерпозера в секрете. Аргумент заполнителя повторно используется в качестве запроса пароля, поэтому вызовите его, как
LD_PRELOAD=$PWD/injectpassword.so darkcoind masternode start "Password: "
. Другой альтернативой будет считывание пароля из файлового дескриптора (например, gpg --passphrase-fd
) или из x11 -ssh-askpass
или что угодно.
Дело не только в истории. Это также будет отображаться в выводе ps .
Тот, кто написал эту программу, должен быть повешен, нарисован и четвертован. Абсолютно НЕТ необходимости вводить пароль в командной строке независимо от того, какое это программное обеспечение.
Для процесса-демона это еще БОЛЬШЕ непростительно ...
Кроме rm -f на самом программном обеспечении, я не знаю никакого решения для этого. Честно: найдите другое программное обеспечение для выполнения этой работы. Не используйте такой хлам.
Это очистит вывод ps
.
БУДЬТЕ ВНИМАТЕЛЬНЫ : это может нарушить работу приложения. Вас должным образом предупреждают, что здесь есть драконы.
Теперь вы должным образом уведомлены об этих ужасных предупреждениях. Это очистит вывод, отображаемый в ps
. Он не очистит вашу историю и не очистит историю заданий bash (например, запуск процесса вроде myprocess myargs &
). Но ps
больше не будет отображать аргументы.
#!/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)
Вызов программы, сохранив ее, chmod + x
it. Затем выполняем ./ независимо от
Если это сработает, результат не будет. В случае неудачи он на что-то пожалуется и уйдет.
Можете ли вы передать аргумент из файла, доступного только root или необходимому пользователю?
ОГРОМНОЕ запрещение вводить пароли в консоли, но последнее обращение ... начните строку с пробела, чтобы она не отображалась в истории.
Вы можете сохранить пароль в истории вашей оболочки, выполнив команду из новый процесс оболочки, который затем немедленно прекращается. Например:
bash$ sh
sh$ darkcoind masternode start 'correct horse battery staple'
sh$ exit
bash$
Убедитесь, что sh
настроен , а не , чтобы сохранять свою историю в файл.
Конечно, это не решает другие проблемы, такие как пароль отображается в пс
. Я считаю, что у самой программы darkcoind
есть способы скрыть информацию из ps
, но это лишь сокращает окно уязвимости.
К сожалению, если ваша команда darkcoind
ожидает пароль в качестве аргумента командной строки, то он будет открыт с помощью таких утилит, как ps
. Единственное реальное решение - обучить разработчиков .
Хотя раскрытие ps
может быть неизбежным, вы можете, по крайней мере, предотвратить запись пароля в файл истории оболочки.
$ xargs darkcoind начало мастерноды
p a s s w o r d ⏎
Ctrl ] D
Файл истории должен записывать только xargs darkcoind начало мастерноды
, но не пароль.
Как уже говорили другие, посмотрите в свой элемент управления историей оболочки, чтобы скрыть информацию от истории.
Но одна вещь, похоже, еще никто не предлагал, - это смонтировать / proc
с параметром hidepid
. Попробуйте изменить строку / proc
в / etc / fstab
, чтобы включить hidepid
, например:
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults,hidepid=2 0 0
Для Биткойн официальный ответ разработчика - использовать предоставленную оболочку python в contrib / bitrpc / bitrpc.py
( github ):
Он запрашивает пароль безопасным способом, если вы, например, используете команду
walletpassphrase
. Нет планов по добавлению интерактивных функций вbitcoin-cli
.
и:
bitcoin-cli
останется как есть и не получит интерактивных функций.
Источник: # 2318
Разблокировать кошелек:
$ python bitrpc.py walletpassphrase
Изменить кодовую фразу:
$ python bitrpc.py walletpassphrasechange
https://github.com/bitcoin/bitcoin/tree/master/contrib/bitrpc
Для дарккойнов это работает в журнале:
https://github.com/darkcoin/darkcoin/tree/master/contrib/bitrpc