web-dev-qa-db-ja.com

どうすれば殺しにくいプロセスを作成できますか

(root権限で)起動すると(管理者でも)停止しにくいプログラムを作成したい。一度開始すると、プロセスは停止を求められるまで起動時に開始し続ける必要があります。停止プロセスには時間がかかるはずです(つまり、費用がかかるはずです)。

これは悪意のあるソフトウェアのように聞こえるかもしれませんが、本当の理由で欲しいのです。 (私が管理者である)ラップトップでサイトブロッカーを実行したい。そして、自分で止められないようにしたいと思います。

私が考えた解決策は次のとおりです-

  1. プロセスは実行されるたびに異なる名前で実行される必要があるため、プロセス名を予測して強制終了することはできません。

  2. プロセスはシャットダウン時に/etc/rc5.dに保存されます

  3. プロセスは、既知の場所にある暗号を使用してその名前を暗号化します。停止プロセスでは、ブルートフォースを使用してプログラム名を回復し、強制終了する必要があります。

このタスクの良い解決策を見つけたいと思います。

10
Miheer

1つのアプローチは、PID名前空間を使用することです。

カーネルパラメータとしてinit=/some/cmdを使用してシステムを起動します。ここで、/some/cmdは新しい名前空間(CLONE_NEWPID)でプロセスをフォークし、その中で/sbin/initを実行します(PID1がその新しい名前空間とルート名前空間のpid2)、次に親で、「プログラム」を実行します。

おそらく、何らかの方法でプログラムを制御する方法が必要になるでしょう(たとえば、TCPまたはABSTRACT Unixソケット)。

プログラムをメモリ内でロックし、ファイルシステムへのほとんどの参照を閉じて、何にも依存しないようにすることをお勧めします。

そのプロセスは、システムの他の部分からは見えません。システムの残りの部分は、事実上、コンテナのように実行されます。

そのプロセスが停止すると、カーネルがパニックになり、追加の保証が提供されます。

ただし、不便な副作用は、psの出力にカーネルスレッドが表示されないことです。

概念実証として( このトリック を使用してqemu仮想マシンでシステムのコピーを起動する):

次のような/tmp/initを作成します。

#! /bin/sh -
echo Starting
/usr/local/bin/unshare -fmp -- sh -c '
  umount /proc
  mount -nt proc p /proc
  exec bash <&2' &
ifconfig lo 127.1/8
exec socat tcp-listen:1234,fork,reuseaddr system:"ps -efH; echo still running"

(最近のバージョンのutil-linux(2.14)のunshareが必要です)。上記では、socatを「プログラム」として使用しており、ps -efHの出力でポート1234のTCP接続)で応答します。

次に、VM as:

kvm -kernel /boot/vmlinuz-$(uname -r) -initrd /boot/initrd.img-$(uname -r) \
    -m 1024 -fsdev local,id=r,path=/,security_model=none \
    -device virtio-9p-pci,fsdev=r,mount_tag=r -nographic -append \
    'root=r rootfstype=9p rootflags=trans=virtio console=ttyS0 init=/tmp/init rw'

次に、次のように表示されます。

Begin: Running /scripts/init-bottom ... done.
Starting
[...]
root@(none):/# ps -efH
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 14:24 ?        00:00:00 bash
root         4     1  0 14:24 ?        00:00:00   ps -efH
root@(none):/# telnet localhost 1234
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
UID        PID  PPID  C STIME TTY          TIME CMD
root         2     0  0 14:24 ?        00:00:00 [kthreadd]
root         3     2  0 14:24 ?        00:00:00   [ksoftirqd/0]
[...]
root         1     0  2 14:24 ?        00:00:00 socat tcp-listen:1234,fork,reuseaddr system:ps -efH; echo still running
root       204     1  0 14:24 ?        00:00:00   /usr/local/bin/unshare -fmp -- sh -c    umount /proc   mount -nt proc p /proc   exec bash <&2
root       206   204  0 14:24 ?        00:00:00     bash
root       212   206  0 14:25 ?        00:00:00       telnet localhost 1234
root       213     1  0 14:25 ?        00:00:00   socat tcp-listen:1234,fork,reuseaddr system:ps -efH; echo still running
root       214   213  0 14:25 ?        00:00:00     socat tcp-listen:1234,fork,reuseaddr system:ps -efH; echo still running
root       215   214  0 14:25 ?        00:00:00       sh -c ps -efH; echo still running
root       216   215  0 14:25 ?        00:00:00         ps -efH
still running
Connection closed by foreign Host.
root@(none):/# QEMU: Terminated
8

それが最終的な解決策なのか、それともそれを行うための最良の方法なのかわからない。私の意見:

  • initを変更します。これは、他のすべてのプロセスも停止した場合の最初のプロセスであるためです。したがって、マシンはそれでのみ使用できます。

  • カーネルモジュールを作成し、それに応じて重要なモジュールをロードします(それが強制終了されると、initの例のような連鎖反応が発生します)。

  • 特定のプロセスの強制終了要求を無視するようにカーネルを変更します。

最後の2つはカーネルモードで実行されることに注意してください(これはライブラリの点で非常に制限されているため、1つです)。 initの変更はユーザースペースで実行され、その多くの機能を使用できるようになります。

1
Tinti