web-dev-qa-db-ja.com

Sudoを保護する方法-パワースクリプト

権限のないユーザーとしてrootコマンドを実行するためのソリューション-Sudo 'ing script-簡単にセキュリティ違反の可能性を開き、予期しない動作と結果(これはすべての場合にも当てはまります) setuidを使用したバイナリラッパーなどの他のソリューション

このように、visudoを使用してスクリプトが追加されたことは明らかです。

www-data ALL=(ALL) NOPASSWD: /usr/local/sbin/mycommand
  • 読み取り可能書き込み可能およびrootだけが実行可能-所有者とグループの両方(chown root:root mycommand; chmod 700 mycommand
  • 親ディレクトリの所有権root:root755モード
  • 入力を検証する必要があります-引数と標準入力-拒否して実行を中止します無効/予期しないデータが提供されます
  • 相対パス/エイリアスではなく絶対パスを使用する必要があります(?)
  • Defaults env_reset in /etc/sudoersを設定する必要があります(?help here here)

Sudoを使用したスクリプトを保護するために他に何ができますか?

6

スクリプトを保護するための基準のリストを少し修正します。 /etc/sudoersのこれまたは同様のエントリを考えてみます。

www-data ALL=(ALL) NOPASSWD: /usr/local/sbin/mycommand

スクリプトは次のように記述できます。

  • rootユーザーのみが書き込み可能である必要があります
  • rootユーザーが読み取りおよび実行できる必要があります
  • ルートのみが書き込めるディレクトリの階層にある必要があります
  • 入力を使用するために「十分に」検証し、それ以外は拒否する必要があります
  • そのタスクを実行するために必要な最小限の特権セットを持っている必要があります(setuid rootである必要はありません)
  • 外部コマンドを使用する前にPATHを定義する必要があります
  • すべての変数を使用する前に既知の値に設定する必要があります
  • いつ、どのように呼び出されたかだけでなく、結果のアクションも示す監査証跡を生成する必要があります(loggerと考えてください)

さらに、多くの場合、スクリプトをrootとして実行する必要はありません-スクリプトは他のアカウントに対してsetgidまたはsetuidを実行できます。一般的なケースでは、これらのオプションを検討して、スクリプトへの完全なrootアクセスを許可しないようにします。

SELinux環境の場合、スクリプトが予期しない動作をしないようにするポリシーを作成できる可能性があります。 CAP_NET_ADMINなどの機能は、包括的なroot権限よりも細かく、検討する価値があります。

単一のIPv4アドレスを検証してiptablesに渡したいという特定のケースでは、might一連の非特定オクテットとしてのIPアドレスの検証を回避できます。この場合、iptables自体が実際のIPアドレスではないものをすべて拒否することがわかっているため、444.555.666.999はもっともらしいものとして受け入れられる可能性があります。極端な場合、RE /^[0-9.]+$/に一致するだけで値をiptablesに渡しても問題ないと判断するかもしれません。一方、StackExchangeと その他の場所 には、IPアドレスの検証の問題に対応する answers がたくさんあります。いくつかは他よりも優れています。

考慮すべき特殊なケースは、RFC1918アドレス、マルチキャストアドレス、および独自の外部IPアドレス範囲です。ああ、以前はクラスEと呼ばれていた予約ブロックです。IPv6サポートは必要ですか?

スクリプトが1分間に数百回呼び出されるとどうなりますか?この不測の事態に備える必要がありますか? iptablesチェーンはオーバーフローしますか?チェーンに何百ものルールが必要になると思われる場合は、線形リストではなく、[ ipset extension to iptablesを使用する方が効率的です。 。これが 良いチュートリアル です。保護に関しては、ルールセットを通過するトラフィックを大幅に遅くすることなく実行できる同様のルールの数千(そうでない場合は 数万 )のセットを構築できます。

突然、単純明快な要件は非常に複雑になります。

6
roaima

名前付きパイプアプローチ。ルートとして、実行します

mkfifo -m 666 /tmp/foo
/tmp/readpipe.sh &

そして、ユーザーwww-dataとしてパイプに書き込むことができます

echo test >>/tmp/foo

最も単純な形式のreadpipe.sh(汚染のあるPerlの方が良いでしょう):

#!/bin/sh
while read A </tmp/foo
do
 echo received $A     
done
4
steve

最良のことの1つは、sudoersファイルで「Digest_Spec」の可能性を使用して、実行可能ファイルのチェックサムを検証することです

Manページの抜粋:

コマンド名の前にDigest_Specが付いている場合、コマンドは、指定されたSHA-2ダイジェストを使用して検証できる場合にのみ、正常に一致します。

Opensslを使用して、チェックサムを生成します。

$ openssl dgst -sha224 /usr/local/sbin/mycommand
 SHA224(/usr/local/sbin/mycommand)=
         52246fd78f692554c9f6be9c8ea001c9131c3426c27c88dbbad08365 

次に、sudoersファイルで(同じ行に):

 www-data ALL=(ALL) NOPASSWD: 
    ssha224:52246fd78f692554c9f6be9c8ea001c9131c3426c27c88dbbad08365
    /usr/local/sbin/mycommand
4
Adam

Setuidプログラムに影響を与える可能性のあるもの

呼び出し元のユーザーがsetuidプロセスの動作に影響を与える可能性があるいくつかの方法を考えてみましょう。考慮すべき事項を3つのグループに分けます。1)プログラム自体、2)プログラムへの入力、3)プログラムが実行される環境です。

バイナリ:非特権ユーザーが実行されるバイナリを変更できる場合、これは特権プロセスを変更する簡単な方法です。これには、プログラムファイルへのパスがユーザーが書き込み可能なディレクトリとシンボリックリンクを通過する場合が含まれます。権限のないユーザーがプログラムファイルとそのパスに書き込みできないようにすることは必須です。 (そしてSudoはチェックしていないようです。)

Setuidビットはパスではなくiノードのプロパティであるため、setuidバイナリは実際にはこの変更による影響を受けません。そのため、シンボリックリンクのトリックは機能しません。 (また、一部のLinuxは、別のユーザーがファイルに書き込むとsetuidビットを落とすようですが、私はそれを当てにしません。)

Inputの問題には、標準入力からのデータ、コマンドライン引数など、プログラムが機能して使用するすべての入力が含まれます。

プログラムがユーザーからの入力を必要とする場合(常に1つのことだけを行うのではなく)、これを回避することはできません。ネットワークサービスも、同様に入力に注意する必要があります。 (例として、SQLインジェクションなどを目撃します。)言うまでもなく、すべてのデータがテキストであり、すべてのテキストが1つの引用符で囲まれているシェルスクリプトなどでは、入力処理は特に難しいと思います。

入力が機密である場合は、コマンドライン引数などの問題がシステム上の他のユーザーに表示されることを考慮する場合があります。

環境はより広い問題です。明らかに、環境変数が含まれており、PATH(実行するサブプロセスを変更できる)、LC_*およびPOSIXLY_CORRECT(シェルコマンドの出力形式を変更する可能性があります)、HOME(アクセスに使用される可能性がある)などが含まれます。ファイル)、およびLD_*(ダイナミックローダーの動作を変更する)などがあります。それらは簡単なことです。

ただし、リソースの制限、Linux cgroup、chroot、SELinuxコンテキスト、名前空間などを考慮してください。スタックの使用やプロセス数に厳しい制限を設定すると、特権プロセスが予期しない時点でクラッシュしたり、サブプロセスの起動に失敗したりすることがあります。プロセスが一部のリソースをロックした後、コミットしてロックを解除する前に、予期しないクラッシュが発生する可能性があります...

(ただし、後者の多くは非特権ユーザーが変更できないため、重大な問題ではない可能性があります。制限された環境からアクセス可能なsetuid実行可能ファイルは、制限された環境に適切に対処する必要がある場合があります。)

それについて何をすべきか

少なくともあなたはすべきです

  • 実行可能ファイルは、ファイル自体とそのファイルへのパスの両方を含め、許可されたユーザーのみが書き込み可能であることを確認してください。プログラムに秘密が埋め込まれていない限り、それを読み取り不可能にすることは実際には必要ありません。
  • 開始時に、PATHを既知の値に設定するなど、環境をリセットします。絶対パスを使用することは安全だと感じますが、検索パスがわかっている場合にどのような影響があるかはわかりません。 Sudoenv_resetはそれを行う必要があります。
  • LD_*変数は、それらを設定解除する機会を得る前に動的リンカーによって処理されますが、リンカーはsetuidプロセスではそれらを無視する必要があります。)
  • 入力を検証します。もちろん。シェルスクリプトにユーザー入力を与えることを検討している場合は特に、それは言うよりも簡単です。
  • パイプまたは標準入力を介して機密入力(パスワード)を取得します。
  • リソース制限をリセットするか、予期しない時点で失敗するリスクを負ってください。

理論的には、従来の環境で「安全な」setuidプログラムまたはSudo-ranプログラムを作成することは可能ですが、あまり一般的ではないシステム固有の機能を検証するのは難しい場合があります。

(ちなみに、多くのシステムにはpasswdsuSudo自体がsetuidされているものの、比較的安全とは見なされていないため、setuidプログラムはalwaysでセキュリティ侵害を簡単に開くことはできません。 。)

Setuidの代替

Sudoまたはsetuid以外の他の可能性は、パイプ(またはソケット)を介して特権プロセスと通信することです。これには、実行中のバイナリが簡単に保護され、その実行環境が既知であり、権限のないユーザーがバイナリに影響を与えることができないという利点があります。

ただし、パイプを使用すると、すべてのライターからの入力が分離せずにスタックされます。改行で区切るリクエストを定義することもできますが、誰かがパイプに部分的な行を書き込んで、別のプロセスからの次のリクエストにデータを付加することができます。また、パイプは双方向通信を簡単に許可しないため、特権プロセスからステータス応答を取得することは簡単ではありません。

ソケットにはこの問題はありませんが、通常のファイルシステム関数からはアクセスできません。代わりに、ソケット関数を介してアクセスする必要があります。 (つまり、echo foo > /my/socketは機能しません。socatはスクリプトで役立つ場合があります)。

3
ilkkachu

Sudoを利用したスクリプトを保護するために他に何ができるか:PAM-プラグ可能な認証モジュールを使用します。

PAM管理者ガイド: http://www.linux-pam.org/Linux-PAM-html/Linux-PAM_SAG.html

PAMモジュール作成者向けガイド: http://www.linux-pam.org/Linux-PAM-html/Linux-PAM_MWG.html

PAMアプリケーション開発者ガイド: http://www.linux-pam.org/Linux-PAM-html/Linux-PAM_ADG.html

また、システムの/usr/share/doc/packages/pam/pdfをチェックして、システムのPAMのバージョンに関連するこれらのドキュメントを確認してください。

PAMはLinuxの基本的なセキュリティメカニズムの1つです。これは、多くのことを保護およびロックダウンするために使用されます。2つの例は、ログインプロセスとパスワード変更プロセスです。最小文字数や有効期限などのパスワード制限を実施する場合、それはPAMで行われます。 PAMがコアシステムプロセスに十分である場合、それは確かにスクリプトに十分です。まず、PAMシステム管理ガイドを参照して、すでに活用できるもの、いくつかの例を理解してください。

  • pam_time:ユーザーを認証しませんが、代わりに、システムや特定のアプリケーションへの1日のさまざまな時間、特定の日のアクセス、またはさまざまな端末回線へのアクセスを制限します。このモジュールは、名前、時刻、曜日、ユーザーが申請しているサービス、ユーザーがリクエストを送信している端末に基づいて、(個々の)ユーザーへのアクセスを拒否するように構成できます。

  • pam_env:呼び出されたときに環境変数の設定または設定解除を引き起こします。これを使用して、pamモジュールを作成するときに利点があります。

  • pam_localuser:通常、ネットワークのユーザーのサブセットと特定のワークステーションにローカルないくつかのアカウントを含む、サイト全体のログインポリシーの実装に役立ちます。 pam_localuserとpam_wheelまたはpam_listfileを使用することは、ローカルユーザーまたはネットワークのユーザーのサブセット、あるいはその両方へのアクセスを制限する効果的な方法です。

  • リストが続く、システム管理者のガイドを参照し、必要に応じて使用してください。

これも便利な場合があります: http://freecode.com/projects/pam_script/

ここから、モジュールライターのガイドとアプリ開発ガイドを読む必要があります。これがPAM ...pluggable認証モジュールの目的です。あなたは効果的にコードを書いています、そしてあなたがまだなら、あなたが終わったときにプログラマーになるでしょう。これは、Microsoft Windowsのように有効/無効にするチェックボックスをクリックする「IT」のものではありません。 PAMを使用する理由は、システム管理者がセキュリティ上の理由でモジュールをプラグインして(場合によっては簡単で、場合によっては記述しなくてもよいため)、何でも実行できるようにするためです。たとえば、ユーザーがpasswdを使用して自分のパスワードを変更した場合、セキュリティの観点からPAMが使用され、パスワードを変更するために「Sudo passwd」と入力しません。 /usr/bin/passwdと同じように、PAMを適切に使用し、スクリプトの所有権とSUID/GUIDを設定すれば、スクリプトで実行する必要がある内容によっては、Sudoさえ必要ない場合があります。

これを保護するために他に何ができるかを[自分自身]に尋ねた場合、何かを行うための最良の方法ではないことを示している可能性があります。この場合、Sudoを使用して、スクリプト/実行可能ファイルを実行するための昇格された特権を付与します。代わりに、Linuxがすでにこのようなことをどのように処理するかについて確立されたメカニズムを調べてください...ポイントの場合、ユーザーが/usr/bin/passwdを使用して、rootが所有し、root権限が必要な/etc/passwdおよび/etc/shadowファイルを編集します変更されます。 PAMを使用すると、ユーザーID、グループID、ローカルユーザーアカウント、特定の時間などに基づいて、スクリプトを実行できるユーザーを制限できます。さらに、それらのユーザーのみを含むスクリプトを実行することのみを目的として、独自のパスワードを使用して別のグループアカウントを作成できることを確認し、スクリプトを実行するためにrootパスワードを指定しないでください。 rootにsuできるユーザーのみ、wheelグループのスキームに従います。お役に立てれば。

0
ron

これを追加します:

スクリプトを直接呼び出さないでください。ただし、2次スクリプトを呼び出すには、最初のスクリプトを使用してログを作成します

#!/bin/bash

[ "$USER" != "www-data" ] && exit
set -a 
Sudo realscript &>/var/log/myscript.log 

そして脚本:

[ "$USER" != "root" ] && exit 

Sudoでは、realscriptを、使用しているように呼び出されたスクリプトではなく、Sudoを許可するものとして配置します。

そして、www-dataが所有しているとしてmyscript.logをタッチしますが、222の権限があります(書き込みのみ可能です!)。 cronでログのバックアップを行います。

www-dataにmyscriptの内容を表示させないで、実行するだけです!

chmod 111 mylogscript
chmod 111 myrealscript

ユーザーにスクリプトを読み取らせたくないが、実行するだけなので、アクセス許可111は適切です。

可能であれば、シェルスクリプトをコンパイルしてみてください:

shc mylogscript
shc myrealscript

はい、shcはシェルコンパイラなので、スクリプトをバイナリに変換できます。安全ですが、場合によっては不安定になるため、注意してください。

$ 1 $ 2のようなシェルスクリプト内のパラメーターを使用しないようにしてください。これはスクリプトインジェクションに使用できます。その代わりに、環境変数をエクスポートしようとするのではなく、シェルが見ることができる、または一時ファイルです。ある種のopenssl暗号化でパラメータを使用するか、すべて使用しないか(この投稿を参照してください: opensslでphpなどのパスワードをコマンドラインで暗号化する方法

アプローチが良いかどうかはさておき、mycommandがインタラクティブな場合は、noexecディレクティブを使用してシェルエスケープを禁止する必要があります。これは、exec()システムコールを事前設定して何もしないようにすることで、他のコマンドの実行を防ぎます。 (これは、LD_PRELOADのメカニズムによって実現されます。Sudo.conf(5)を参照してください。)警告:これは完全なものではありません-mycommandが静的にリンクされている場合、これは機能しません。

0
countermode