解決策 1:
本当に、これはすべき アプリケーション自体で修正されます。そして、そのようなアプリケーションはすべき オープンソースであるため、アプリ自体で問題を修正することはオプションです。この種の間違いを犯すセキュリティ関連のアプリケーションは、他の間違いも犯す可能性があるため、私はそれを信用しません。
シンプルなインターポーザ
しかし、あなたは別の方法を求めていたので、ここにその方法を示します:
#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
の直前に呼び出してください。 すべての初期化が完了した後、それ自体が呼び出されます。次の例では、getpass
をもたらしたコマンドライン引数として渡されたパスワードを非表示にする方法を指摘してくれた Grubermensch に感謝しなければなりません。
#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
から 、または何でも。
解決策 2:
歴史だけではありません。 ps で表示されます 出力も同様です。
そのソフトウェアを書いた人は誰でも、ハングアップし、描画し、四分の一にする必要があります.ソフトウェアに関係なく、コマンドラインでパスワードを入力する必要があるのは絶対にNOです。
デーモン プロセスの場合、これはさらに許されません...
rm -f 以外に ソフトウェア自体では、これに対する解決策はわかりません。正直なところ、仕事を終わらせるために他のソフトウェアを見つけてください。そのようながらくたを使用しないでください。
解決策 3:
これで 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
を保存してプログラムを呼び出します。 それ。次に ./whatever <pidoftarget>
を実行します これが機能する場合、出力は生成されません。失敗すると何か文句を言って終了します。
解決策 4:
ルートまたは必要なユーザーのみがアクセスできるファイルから引数を渡すことができますか?
コンソールにパスワードを入力するのは非常に難しいことですが、最後の手段として、履歴に表示されないように行をスペースで始めてください。
解決策 5:
これでうまくいくかもしれません (?):
darkcoind masternode start `cat password.txt`