Как скрыться, пароль передал как параметр командной строки?

В дополнение к изнасилованию, ping 255.255.255.255 и arp -na вместе может помочь.

43
задан 13 April 2017 в 15:47
9 ответов

На самом деле, это должно быть исправлено в самом приложении. И такие приложения должны быть с открытым исходным кодом, так что решение проблемы в самом приложении должно быть вариантом. Приложение, связанное с безопасностью, которое допускает такую ​​ошибку, может допускать и другие ошибки, поэтому я бы ему не доверял.

Простая вставка

Но вы просили другой способ, поэтому вот один:

#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 или что угодно.

В следующем примере я должен поблагодарить 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 или что угодно.

В следующем примере я должен поблагодарить 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 или что угодно.

68
ответ дан 28 November 2019 в 19:41

Дело не только в истории. Это также будет отображаться в выводе ps .

Тот, кто написал эту программу, должен быть повешен, нарисован и четвертован. Абсолютно НЕТ необходимости вводить пароль в командной строке независимо от того, какое это программное обеспечение.
Для процесса-демона это еще БОЛЬШЕ непростительно ...

Кроме rm -f на самом программном обеспечении, я не знаю никакого решения для этого. Честно: найдите другое программное обеспечение для выполнения этой работы. Не используйте такой хлам.

28
ответ дан 28 November 2019 в 19:41

Это очистит вывод 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. Затем выполняем ./ независимо от Если это сработает, результат не будет. В случае неудачи он на что-то пожалуется и уйдет.

19
ответ дан 28 November 2019 в 19:41

Можете ли вы передать аргумент из файла, доступного только root или необходимому пользователю?

ОГРОМНОЕ запрещение вводить пароли в консоли, но последнее обращение ... начните строку с пробела, чтобы она не отображалась в истории.

11
ответ дан 28 November 2019 в 19:41

Возможно, это сработает (?):

darkcoind masternode start `cat password.txt`
7
ответ дан 28 November 2019 в 19:41

Вы можете сохранить пароль в истории вашей оболочки, выполнив команду из новый процесс оболочки, который затем немедленно прекращается. Например:

bash$ sh
sh$ darkcoind masternode start 'correct horse battery staple'
sh$ exit
bash$

Убедитесь, что sh настроен , а не , чтобы сохранять свою историю в файл.

Конечно, это не решает другие проблемы, такие как пароль отображается в пс . Я считаю, что у самой программы darkcoind есть способы скрыть информацию из ps , но это лишь сокращает окно уязвимости.

2
ответ дан 28 November 2019 в 19:41

К сожалению, если ваша команда darkcoind ожидает пароль в качестве аргумента командной строки, то он будет открыт с помощью таких утилит, как ps . Единственное реальное решение - обучить разработчиков .

Хотя раскрытие ps может быть неизбежным, вы можете, по крайней мере, предотвратить запись пароля в файл истории оболочки.

$ xargs darkcoind начало мастерноды

p a s s w o r d

Ctrl ] D

Файл истории должен записывать только xargs darkcoind начало мастерноды , но не пароль.

4
ответ дан 28 November 2019 в 19:41

Как уже говорили другие, посмотрите в свой элемент управления историей оболочки, чтобы скрыть информацию от истории.

Но одна вещь, похоже, еще никто не предлагал, - это смонтировать / proc с параметром hidepid . Попробуйте изменить строку / proc в / etc / fstab , чтобы включить hidepid , например:

# <file system> <mount point>   <type>  <options>       <dump>  <pass>
proc            /proc           proc    defaults,hidepid=2        0       0
3
ответ дан 28 November 2019 в 19:41

Для Биткойн официальный ответ разработчика - использовать предоставленную оболочку 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

2
ответ дан 28 November 2019 в 19:41

Теги

Похожие вопросы