web-dev-qa-db-ja.com

ソースコードなしでプログラムの引数を隠す

実行中のプログラムの機密引数を非表示にする必要がありますが、ソースコードにアクセスできません。また、共有サーバーでこれを実行しているため、Sudo権限がないため、hidepidなどを使用できません。

これが私が試したいくつかのことです:

  • export SECRET=[my arguments]に続いて./program $SECRETを呼び出しますが、これは役に立たないようです。

  • ./program `cat secret.txt`ここでsecret.txtには私の引数が含まれていますが、万能のpsは私の秘密を盗み見ることができます。

管理者の介入を必要としない、私の議論を隠す他の方法はありますか?

15
M.S.

説明したように here 、Linuxはプログラムの引数をプログラムのデータ空間に配置し、この領域の先頭へのポインタを保持します。これは、プログラムの引数を見つけて表示するためにpsなどが使用するものです。

データはプログラムの空間にあるので、それを操作できます。プログラム自体を変更せずにこれを行うには、プログラムの実際のメインの前に呼び出されるmain()関数でシムをロードする必要があります。このシムは、実引数を新しいスペースにコピーし、元の引数を上書きして、psがnulだけを表示するようにすることができます。

次のCコードはこれを行います。

_/* https://unix.stackexchange.com/a/403918/119298
 * capture calls to a routine and replace with your code
 * gcc -Wall -O2 -fpic -shared -ldl -o shim_main.so shim_main.c
 * LD_PRELOAD=/.../shim_main.so theprogram theargs...
 */
#define _GNU_SOURCE /* needed to get RTLD_NEXT defined in dlfcn.h */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <dlfcn.h>

typedef int (*pfi)(int, char **, char **);
static pfi real_main;

/* copy argv to new location */
char **copyargs(int argc, char** argv){
    char **newargv = malloc((argc+1)*sizeof(*argv));
    char *from,*to;
    int i,len;

    for(i = 0; i<argc; i++){
        from = argv[i];
        len = strlen(from)+1;
        to = malloc(len);
        memcpy(to,from,len);
        memset(from,'\0',len);    /* zap old argv space */
        newargv[i] = to;
        argv[i] = 0;
    }
    newargv[argc] = 0;
    return newargv;
}

static int mymain(int argc, char** argv, char** env) {
    fprintf(stderr, "main argc %d\n", argc);
    return real_main(argc, copyargs(argc,argv), env);
}

int __libc_start_main(pfi main, int argc,
                      char **ubp_av, void (*init) (void),
                      void (*fini)(void),
                      void (*rtld_fini)(void), void (*stack_end)){
    static int (*real___libc_start_main)() = NULL;

    if (!real___libc_start_main) {
        char *error;
        real___libc_start_main = dlsym(RTLD_NEXT, "__libc_start_main");
        if ((error = dlerror()) != NULL) {
            fprintf(stderr, "%s\n", error);
            exit(1);
        }
    }
    real_main = main;
    return real___libc_start_main(mymain, argc, ubp_av, init, fini,
            rtld_fini, stack_end);
}
_

main()に介入することはできませんが、標準Cライブラリ関数___libc_start_main_に介入して、mainを呼び出すことができます。最初のコメントに記載されているように、このファイルを_shim_main.c_をコンパイルし、図のように実行します。コードにprintfを残したので、実際に呼び出されていることを確認してください。たとえば、実行

_LD_PRELOAD=/tmp/shim_main.so /bin/sleep 100
_

次にpsを実行すると、空白のコマンドと引数が表示されます。

コマンドの引数が表示されるまでには、まだ少し時間がかかります。これを回避するには、たとえば、shimを変更してファイルからシークレットを読み取り、プログラムに渡される引数に追加します。

25
meuh
  1. 問題のアプリケーションのコマンドラインインターフェースのドキュメントを読んでください。直接引数としてではなく、ファイルからシークレットを提供するオプションがあるかもしれません。

  2. それが失敗した場合、秘密をアプリケーションに提供する安全な方法がないという理由で、アプリケーションに対してバグレポートを提出してください。

  3. あなたはいつでも慎重に(!)ソリューションを meuhの答え で特定のニーズに適合させることができます。 Stéphaneのコメント とそのフォローアップに特別な配慮を払ってください。

16
David Foerster

プログラムに引数を渡して動作させる必要がある場合、procfsでhidepidを使用できない場合は、何をしてもうまくいきません。

これはbashスクリプトであると述べたので、bashはコンパイルされた言語ではないので、すでにソースコードが利用できるはずです。

それが失敗した場合、あなたはmaygdbまたは類似のものを使用してプロセスのコマンドラインを書き換え、argc/argvを試してみることができます開始したが:

  1. プログラムの引数を変更する前に最初に公開するため、これは安全ではありません。
  2. これはかなりハッキーです、あなたがそれを機能させることができたとしても、私はそれに依存することはお勧めしません

ソースコードを入手するか、ベンダーに連絡してコードを変更することをお勧めします。 POSIXオペレーティングシステムのコマンドラインでシークレットを指定することは、安全な操作と互換性がありません。

12
Chris Down

あなたがするかもしれないことは

 export SECRET=somesecretstuff

次に、あなたが./programをCで書いている(または他の誰かが書いていて、それを変更または改善できる)と仮定して、そのプログラムで getenv(3) を使用します。

char* secret= getenv("SECRET");

exportの後には、同じシェルで./programを実行するだけです。または、環境変数名をそれに渡すことができます(./program --secret-var=SECRETなどを実行して...)

psはあなたの秘密を教えてくれませんが、 proc(5) は(少なくとも同じユーザーの他のプロセスに)多くの情報を提供できます。

プログラム引数を渡すより良い方法を設計するのに役立つ this も参照してください。

グロビングとシェルの役割についてのより良い説明は この答え を参照してください。

おそらく、あなたのprogramは、プレーンなプログラム引数よりもデータを取得する(または プロセス間通信 より賢明に使用する)いくつかの他の方法を持っています(機密情報を処理することを意図している場合は、確かにそうする必要があります) 。そのドキュメントを読んでください。または、そのプログラムを悪用している可能性があります(これは秘密のデータを処理するためのものではありません)。

秘密のデータを隠すことは本当に難しいです。プログラムの引数に渡さないだけでは不十分です。