curlは、ps出力にパスワードが表示されないようにどのように保護しますか?


68

curlコマンドライン引数として指定されたユーザー名とパスワードがps出力に表示されないことに少し前に気付きました(もちろん、bash履歴に表示される場合があります)。

彼らも同様に現れません/proc/PID/cmdline

(ただし、ユーザー名とパスワードを組み合わせた引数の長さは導出できます。)

以下のデモ:

[root@localhost ~]# nc -l 80 &
[1] 3342
[root@localhost ~]# curl -u iamsam:samiam localhost &
[2] 3343
[root@localhost ~]# GET / HTTP/1.1
Authorization: Basic aWFtc2FtOnNhbWlhbQ==
User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.15.3 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Host: localhost
Accept: */*



[1]+  Stopped                 nc -l 80
[root@localhost ~]# jobs
[1]+  Stopped                 nc -l 80
[2]-  Running                 curl -u iamsam:samiam localhost &
[root@localhost ~]# ps -ef | grep curl
root      3343  3258  0 22:37 pts/1    00:00:00 curl -u               localhost
root      3347  3258  0 22:38 pts/1    00:00:00 grep curl
[root@localhost ~]# od -xa /proc/3343/cmdline 
0000000    7563    6c72    2d00    0075    2020    2020    2020    2020
          c   u   r   l nul   -   u nul  sp  sp  sp  sp  sp  sp  sp  sp
0000020    2020    2020    0020    6f6c    6163    686c    736f    0074
         sp  sp  sp  sp  sp nul   l   o   c   a   l   h   o   s   t nul
0000040
[root@localhost ~]# 

この効果はどのように達成されますか? それはソースコードのどこかにありcurlますか?(私はそれがcurl機能ではなくps機能だと思いますか?それとも何らかのカーネル機能ですか?)


また、これはバイナリ実行可能ファイルのソースコードの外部から達成できますか? たとえば、シェルコマンドを使用して、おそらくルート権限と組み合わせて使用​​しますか?

言い換えれば、任意のシェルコマンドに渡し/procps出力(または同じことだと思います)に出てくる引数を何らかの方法でマスクできますか?(これに対する答えは「いいえ」であると思いますが、この余分な半質問を含める価値があるようです。)



16
ない答えが、このアプローチがあることに注意して安全ではありません。プログラムの起動と、ユーザーがパスワードを読み取ることができる引数文字列のクリアの間には、競合ウィンドウがあります。コマンドラインで機密パスワードを受け入れないでください。
R ..

1
大まかに関連:環境変数は誰のものですか?そして、実際に誰かがenviron直接環境変数にアクセスするために使用していますか?—一番下の行:引数リストは、環境変数のリストと同様に、読み取り/書き込みユーザープロセスメモリ内にあり、ユーザープロセスによって変更できます。
スコット

1
@ JPhi1618は、ちょうどあなたの最初の文字にするgrepパターン文字クラスを。例ps -ef | grep '[c]url'
ワイルドカード

1
@ mpy、tはそれほど複雑ではありません。一部の正規表現は自分自身と一致し、一部は一致しません。 curlは一致しますcurlが一致[c]urlしません[c]url。さらに詳しい情報が必要な場合は、新しい質問をしてください。喜んでお答えします。
ワイルドカード

回答:


78

カーネルはプロセスを実行するときに、コマンドライン引数をプロセスに属する読み書きメモリにコピーします(少なくともLinuxの場合はスタック上)。プロセスは、他のメモリと同様にそのメモリに書き込むことができます。ときにps引数を表示し、それはプロセスのメモリ内のその特定のアドレスに格納されているものは何でも読み戻します。ほとんどのプログラムは元の引数を保持しますが、変更することは可能です。状態のPOSIX記述ps

表現された文字列が、コマンドの起動時にコマンドに渡されたバージョンの引数リストであるか、アプリケーションによって変更された可能性のあるバージョンの引数であるかは不明です。アプリケーションは、引数リストを変更し、その変更をpsの出力に反映させることに依存することはできません。

これが言及されている理由は、ほとんどのUNIXバリアントが変更を反映するが、他のタイプのオペレーティングシステムでのPOSIX実装は反映しない可能性があるためです。

プロセスは任意の変更を加えることができないため、この機能の使用は制限されています。少なくとも、プログラムpsは引数を取得する場所を変更できず、元のサイズを超えて領域を拡張できないため、引数の合計長を増やすことはできません。引数はCスタイルのヌル終了文字列であるため、ヌルバイトを末尾に置くことで長さを効果的に短縮できます(これは、末尾に空の引数がたくさんあることと区別できません)。

本当に掘り下げたい場合は、オープンソース実装のソースを見ることができます。Linuxでは、のソースは、psあなたが表示されますすべてはそれがからコマンドライン引数読み込むことがあり、興味深いものではありませんprocファイルシステムをして、。このファイルのコンテンツを生成するコードは、カーネル内のにあります。プロセスのメモリの一部(でアクセス)は、アドレスからに移動します。これらのアドレスはプロセスの開始時にカーネルに記録され、その後変更することはできません。/proc/PID/cmdlineproc_pid_cmdline_readfs/proc/base.caccess_remote_vmmm->arg_startmm->arg_end

いくつかのデーモンがその状態を反映するために、この機能を使用して、例えば、それらは彼らを変更するargv[1]ような文字列にstartingavailableまたはexiting。多くのUNIXバリアントには、setproctitleこれを行う機能があります。一部のプログラムは、この機能を使用して機密データを隠します。プロセスの開始中にコマンドライン引数が表示されるため、これは限定的な使用に注意してください。

ほとんどの高レベル言語は、引数を文字列オブジェクトにコピーし、元のストレージを変更する方法を提供しません。argv要素を直接変更することでこの機能を実証するCプログラムを次に示します。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
    int i;
    system("ps -p $PPID -o args=");
    for (i = 0; i < argc; i++)
    {
        memset(argv[i], '0' + (i % 10), strlen(argv[i]));
    }
    system("ps -p $PPID -o args=");
    return 0;
}

サンプル出力:

./a.out hello world
0000000 11111 22222

argvcurlのソースコードで変更を確認できます。Curlは、を使用して引数をすべてのスペースに変更するために使用される関数cleanargsrc/tool_paramhlp.c定義しますmemset。ではsrc/tool_getparam.c、この機能redactingするなど、数回使用されているユーザーのパスワードを。この関数はパラメーター解析から呼び出されるため、curl呼び出しの早い段階で発生しますが、これが発生する前にコマンドラインをダンプすると、引き続きパスワードが表示されます。

引数はプロセス固有のメモリに格納されるため、デバッガーを使用しない限り、外部から変更することはできません。


すばらしいです!そのため、その仕様スニペットに関しては、カーネルにプロセスの元のコマンドライン引数をプロセスの読み書きメモリ(読み書きメモリのコピーに加えて)の外側に保存させることがPOSIX準拠であることを意味すると理解しています?そして、プロセスの読み取り/書き込みメモリで行われた変更を無視して、カーネルのメモリの一部からレポート引数を持っていますか?しかし(もし私が正しければ?)ほとんどのUNIXバリエーションは前者さえもしないので、元のデータはどこにも保持されないので、カーネルの修正なしに後者を実装することはできませんか?psps
ワイルドカード

1
@Wildcard正しい。オリジナルを保持するUnix実装があるかもしれませんが、私は一般的な実装のどれもそうしないと思います。C言語では、argvエントリの内容を変更できます(を設定することはできませんがargv[i]argv[i][0]を通して書き込むことはできますargv[i][strlen(argv[i])])ので、プロセスのメモリにコピーが必要です。
ジル

2
カールソースコード内の関連機能:github.com/curl/curl/blob/master/src/tool_paramhlp.c#L139
sebasth

4
@ Wildcard、Solarisはこれを行います。/ usr / ucb / psに表示されるコマンドラインは、プロセスが所有する(変更可能な)コピーです。/ usr / bin / psから見えるコマンドラインは、カーネルが所有する(不変の)コピーです。ただし、カーネルは最初の80文字のみを保持します。それ以外は切り捨てられます。
BowlOfRed

1
@Wildcard実際、末尾のヌルは空の引数です。ではps、出力が何もないように、空の引数の多くは見えますが、はい、それはあなたがそこにあるどのように多くのスペースをチェックして、あなたからより直接的に観察することができるかどうかの違いを作るん/proc/PID/cmdline
ジル

14

他の回答は、一般的な方法で質問によく答えます。「この効果はどのように達成されますか? curlのソースコードのどこかにありますか?

curlソースコード引数解析セクションでは-uオプションは次のように処理されます。

    case 'u':
      /* user:password  */
      GetStr(&config->userpwd, nextarg);
      cleanarg(nextarg);
      break;

また、cleanarg()関数は次のように定義されます。

void cleanarg(char *str)
{
#ifdef HAVE_WRITABLE_ARGV
  /* now that GetStr has copied the contents of nextarg, wipe the next
   * argument out so that the username:password isn't displayed in the
   * system process list */
  if(str) {
    size_t len = strlen(str);
    memset(str, ' ', len);
  }
#else
  (void)str;
#endif
}

そのargvため、他の回答で説明されているように、username:password引数がスペースで上書きされていることが明示的にわかります。


のコメントがcleanarg、質問がしていることをしていることを明確に述べているのが好きです!
フローリス

3

プロセスは、パラメータを読み取るだけでなく、書き込むこともできます。

私は開発者ではないので、このことについては詳しくありませんが、環境パラメーターの変更に似たアプローチで外部から可能になる場合があります。

https://stackoverflow.com/questions/205064/is-there-a-way-to-change-another-processs-environment-variables


わかりましたが、たとえばbash -c 'awk 1 /proc/$$/cmdline; set -- something; awk 1 /proc/$$/cmdline'シェルを実行することで、パラメーターを設定することは、カーネルがプロセスパラメーターとして認識するものを変更することとは異なることがわかります。
ワイルドカード

4
@Wildcardシェルスクリプトの位置引数は、最初 はシェルプロセスのコマンドライン引数の一部コピーです。ほとんどのシェルでは、スクリプトが元の引数を変更することはできません。
ジル

@Gilles、はい、それが私のコメントのポイントでした。:) プロセスがそれを行うことができるという一般的な声明(この回答の最初の文)は、これが既存のシェル機能によって達成できるかどうかには答えません。これに対する答えは「いいえ」であるように見えます。これは私の質問の一番下で推測したものです。
ワイルドカード
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.