ポートをリッスンしているプロセスを知る - いますぐ実践! Linuxシステム管理 / Vol.110
[バックナンバーのトップへ] [Linux システム管理のトップへ]
いますぐ実践! Linux システム管理 / Vol.110 / 読者数:1090名
こんばんは、うすだです。
先週、サーチマン佐藤さん(※)に、 当メルマガを紹介していただきましたが、直後に、 まぐまぐで不達アドレスの整理があったためか(憶測)、 読者数がごっそり減ってしまいました…。
しばらく営業活動してませんでしたので、 相互紹介でどのくらい読者さんが増えるのか、ちょい期待していたのですが、 ああ、もうって感じです。
まあ、相互紹介をするのに、 いいタイミングと悪いタイミングがあるってことを知ることができて、 いい勉強になったと思います。
…と無理矢理思うことにします。(ちょっと斜めなポジティブ思考)
※ ちなみに、サーチマン佐藤さんのサイトは、以下です。
各種メルマガだけでなく、いろんな情報がありますよ。
そんなわけで、地道に精進しようと思った1週間でした。
それでは、今週も、はりきってまいりますよ!
今週のお題 - ポートをリッスンしているプロセスを知る
インターネットから直接見えるサーバは、いけないクラッカーさんからの攻撃を、 極力受けないようにする必要がありますよね。
そのためには、いろいろな対策を行う必要がありますが、その中でも重要な対策に、 余計なサービスを起動しない、というものがあります。
TCP や UDP で待ち受けているポートの数が少なければ少ないほど、 攻撃される対象が少なくなりますので、管理もしやすくなります。
しかし、そのポートを使用しているのが誰なのか、わからないことがあります。 (たとえば、22273番はどのプロセスが使ってるんだ? みたいな。)
サービスが重要なのかどうかを判断する前に、だれがそのポートを使っているのか、 ということがわからないと、どうしようもありません。
ですので、今週は、とあるポートを待ち受けているプロセスがなにかを、 調べてみたいと思います。
それって lsof を使えばいいのでは? と思われた貴兄は、おっしゃる通りですので、 宿題まですっとばしていただいて結構です。
…あ、いや、lsof がなくて、自力で調べる必要があるときに、有用かもしれません。 パッケージのないディストリビューションもありますし。
というわけで、以降は、lsof がなくて自力で調べる必要のあるかたや、 lsof が中でやっていることを知りたいかたに、お送りいたします。
ちなみに、lsof は、以下から入手可能です。
msdfmap.iniは何ですか
まずは、現在待ち受けているポートを調べてみましょう。
それには、netstat コマンドを使用します。
netstat コマンドを、-an オプションつきで実行すると、 TCP や UDP 等のソケットの状態を知ることができます。
(IPアドレスで出力するため、ここでは -a でなく -an を使用します。)
% netstat -an 稼働中のインターネット接続 (サーバと確立) Proto 受信-Q 送信-Q 内部アドレス 外部アドレス 状態 tcp 0 0 0.0.0.0:110 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:22273 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN tcp 0 0 192.168.1.1:53 0.0.0.0:* LISTEN ... udp 0 0 0.0.0.0:111 0.0.0.0:* udp 0 0 192.168.1.1:53 0.0.0.0:* ...
ここで注目すべきは、 外部(インターネット)から見えるポートをオープンして待ち受けているものです。
具体的には、内部アドレスが 0:0:0:0:ポート番号 か、 外部から参照可能なアドレスで始まっているものです。
また、tcp の場合は、状態が LISTEN となっている必要があります。
(蛇足ですが、udp はステートレスですので、状態はありません。)
上記の場合、内部アドレスが 192.168.1.1:53 以外のものすべてが、 該当することになります。
以降では、TCP のポート80番を待ち受けているプロセス(って、 アレしか考えられませんが…)を調べたいと思います。
では次に、調べたいポートのソケットの iノード番号を求めます。
そのためには、/proc/net/tcp や /proc/net/udp を参照してください。
(行末を ¥ で折り返しているところは、実際は1行です。)
% cat /proc/net/tcp sl local_address rem_address st tx_queue rx_queue tr tm->when ¥ retrnsmt uid timeout inode 0: 00000000:006E 00000000:0000 0A 00000000:00000000 00:00000000 ¥ 00000000 0 0 4064 1 e5f759e0 750 0 0 2 -1 1: 00000000:5701 00000000:0000 0A 00000000:00000000 00:00000000 ¥ 00000000 49 0 5001 1 e47c75e0 750 0 0 2 -1 2: 00000000:0050 00000000:0000 0A 00000000:00000000 00:00000000 ¥ 00000000 0 0 4978 1 e47c7a20 750 0 0 2 -1 3: 0101A8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 ¥ 00000000 25 0 139992 1 e5f748e0 750 0 0 2 -1 ...
ここでは、/proc/net/tcp を参照していますが、/proc/net/udp も、形式は同じです。
詳細は割愛しますが、2つ目の local_address が、 内部アドレスとポート番号を16進数で表したものです。
たとえば、0: で始まる行は、110番(=0x6E)を待ち受けています。
そして、10番目の inode が、iノード番号です。
たとえば、0: で始まる行の iノード番号は、4064 番です。
さて、今調べたいのは、80番のプロセスの場合でした。
80 を16進数で表すと 0x50 ですので、 grep コマンドを使ってその行だけを出力するには、以下のように実行します。
utificationと何がそれを防ぐことができます
% grep :0050 /proc/net/tcp 2: 00000000:0050 00000000:0000 0A 00000000:00000000 00:00000000 ¥ 00000000 0 0 4978 1 e47c7a20 750 0 0 2 -1
ポート番号が80番のソケットの iノード番号は、4978 だということが、 これでわかりました。
あとは、この iノード番号を使用しているプロセスを見つけるだけです。
そのためには、/proc/プロセスID/fd/ の下のファイルを参照します。
たとえば、プロセスID が 8672 の場合、わたしの環境では、 以下のようになっています。
% ls -l /proc/8672/fd/ 合計 5K lrwx------ 1 usu adm 64 7月 1日 22:47 0 -> /dev/pts/1 lrwx------ 1 usu adm 64 7月 1日 22:47 1 -> /dev/pts/1 lrwx------ 1 usu adm 64 7月 1日 22:47 2 -> /dev/pts/1 lrwx------ 1 usu adm 64 7月 1日 22:47 255 -> /dev/pts/1 lrwx------ 1 usu adm 64 7月 1日 22:47 5 -> /dev/pts/1
実は、このプロセスの実体は bash です。
この bash は、pts/1 という仮想端末の上で動作しています。
ですので、0(標準入力)や1(標準出力)などが、みな /dev/pts/1 になっています。
では、これを利用して、ソケットの iノード番号が 4978 のプロセスを、 探してみましょう。
…とはいえ、肝心のプロセスID がわかりませんよね。
ですので、ここは力業で実現してみようと思います。
つまり、全部のプロセスの、/proc/プロセスID/fd/ 以下を参照します。
(root の権限が必要です。sudo などを経由して実行してください。)
# ls -l /proc/[1-9]*/fd/[1-9]* lrwx------ 1 root root 64 7月 1日 22:47 /proc/1/fd/10 -> ¥ /dev/initctl| ...
大量に出力されたと思います。手で調べるには多すぎますね。
そこで、以下のように、grep コマンドで絞ることにしましょう。
# ls -l /proc/[1-9]*/fd/[1-9]* | grep 'socket:¥[4978¥]' lrwx------ 1 root root 64 7月 1日 22:47 /proc/2530/fd/17 -> ¥ socket:[4978] lrwx------ 1 root root 64 7月 1日 22:47 /proc/3754/fd/17 -> ¥ socket:[4978] lrwx------ 1 root root 64 7月 1日 22:47 /proc/3755/fd/17 -> ¥ socket:[4978]
どうやら、プロセスID が 2530, 3754 と 3755 のプロセスっぽいぞ、 ということがわかります。ps コマンドで確認してみましょう。
% ps -p 2530,3754,3755 PID TTY TIME CMD 2530 ? 00:00:00 httpd 3754 ? 00:00:00 httpd 3755 ? 00:00:00 httpd
はい、みなさんのご想像の通り、httpd さんでした。
以上、とあるポートをリッスンしているプロセスを調べる方法について、 だらだらっとご紹介しました。
きちんと管理されているところなら、余計なサービスは動作していないと思いますが、 念のため、netstat コマンドで調べてみてください。
そして、もし万が一、これはなんだ? というポートがありましたら、 上記のようにプロセスを特定して、よきように処理してくださいませ。
私はPS3でどのようなルータを使用しない
宿題の答え
先週の宿題は、
ホンモノのコマンドを実行されないようにする方法を考えましょう。
でした。
たとえば、/bin/foo というコマンド(実際にはないと思います)があり、 これをシェルスクリプトでラップしているとしましょう。
本物のコマンドは、/bin/.real_foo だとします。
ラッパーなスクリプトでオブラートに包んでも、 スクリプトの中を見れば本物のコマンドがばれてしまいます。
かといって、スクリプトの中を見えないようにしますと、
% chmod a=x /bin/foo % cat /bin/foo cat /bin/foo: 許可がありません
見えないのはいいのですが、実行もできなくなってしまいます。
% /bin/foo /bin/foo: /bin/foo: 許可がありません
しかたがありませんので、さらにラップするものを、C 言語で、 さらっと書いてみました。
#include#include #include int main(int argc, char *argv[], char *env[]) { pid_t pid; if((pid = fork()) == -1) { /* 子プロセスの生成 */ perror("fork"); /* エラーならメッセージを出力 */ } else if(pid > 0) { wait(NULL); /* 親プロセスは待つ */ } else { /* 子プロセスは本物を実行 */ execve("/bin/.real_foo", argv, env); } return 0; }
これを foo.c という名前で保存したら、コンパイルして、 /bin/foo_wrap という実行ファイルにします。
# cc -O -o /bin/foo_wrap foo.c
そして、/bin/foo_wrap は、実行だけを許可します。
# chmod a=x /bin/foo_wrap
ラッパーは、この /bin/foo_wrap を実行するようにします。
すると、本物のコマンドを隠蔽できます。
% cat /bin/foo #!/bin/sh /usr/bin/logger -i -t foo -p auth.notice "options: $*" exec /bin/foo_wrap $* % /bin/foo (実行結果) % strings /bin/foo_wrap strings: /bin/foo_wrap: 許可がありません
しかし、/bin/.real_foo というファイルに気づかれてしまうと、 実行はできてしまいますよね。
石橋を叩いて渡りたい貴兄は、本物を、 実行しかできないディレクトリの下に置いてしまいましょう。
ここでは、/bin/secret というディレクトリを作成して、そこに置くことにします。
# mkdir /bin/secret # chmod a=x /bin/secret # mv /bin/.real_foo /bin/secret/
さっきの foo.c の "/bin/.real_foo" を、"/bin/secret/.real_foo" にして、 /bin/foo_wrap を作りなおせば、完成です。
もちろん、パスを知っている場合は、どうしようもありませんが…。
(こればっかりは、どうしようもないと思います…。)
% ls -l /bin/secret/.real_foo -rwxr-xr-x 1 root root 101264 6月13日 2006 /bin/secret/.real_foo % /bin/secret/.real_foo (実行結果)
以上ですが…微妙な回答で、申し訳ありません…。
C 言語使いのかたは、ラッパー自体を C で書いてしまえばいいですね。
今週の宿題
今週の宿題は、
UDP のポートを使用しているプロセスを調べてみましょう。
です。
本題では、TCP のポートを調べましたが、UDP の場合も同様に調べることができます。 ご自身の管理されているサーバ上で、よくわからないやつがありましたら、 実際に調べてみてください。
あとがき
さっき、今年はじめての、黒い忌まわしき存在に遭遇しました。
新築と同時に住みはじめ、いままで、 大きな1匹しか出現したことがありませんでしたので、ここ数年は、 ちょっと油断していました。
幸い、小さくて、かなり弱っていらっしゃったようでしたので、 超苦手なわたくしでも、撃退することができました。
今後は、このようなことがないように、硼酸ダンゴなどを用意して、 備えたいと思いました。
しかし、こればっかりは、どれだけ備えていても、絶対に起こらない! という保証はありません。憂いなし、とは口がさけても言えません。
あ、これって、システム管理と似ていますね。
どちらも、もし万が一遭遇したら、うろたえずに対処できるようにしたいと思います。
…強引なオチで申し訳ありませんが、まだ若干動揺していますので、 これでご容赦いただきたいと存じます。(-ε-;;;;;
今週も、ここまで読んでいただき、ありがとうございました。
それでは、また来週に、お会いしましょう!
「いますぐ実践! Linux システム管理」の解除は、以下からできます。
(まぐまぐ ID:149633)
バックナンバーは、こちらにほぼ全部そろっています。
「栗日記」−今さらですが、毎日栗の絵を描いているわけです。
(まぐまぐ ID:126454)
(栗日記ブログ)
[バックナンバーのトップへ] [Linux システム管理のトップへ]
0 コメント:
コメントを投稿