ログの監視:このような脆弱なログ、または同僚に豚を飼う方法

セキュリティ、負荷分析、営業担当者の統計や分析の作成、ニューラルネットワークのフィードなど、ログの監視や分析は、多くの問題に関連しています。







残念ながら、これは多くの場合、ヒューマンファクター、つまり、ログの監視に必要な情報を記録するプログラム、API、およびサービスの多くの開発者による非常に単純なことの不本意または誤解に関連しています。

以下は、これが頻繁に行われる方法と、そのように生きられない理由です。 ログ形式について話し、いくつかの例を分析し、いくつかの正規表現を書きます...







親愛なる同僚、もちろんそれはあなたのビジネス、プログラムのログにどのように、何を書き込むかですが、あなた自身のためだけにそれを行うかどうかを考える価値はまだあります。プログラム、さらには賢いものから不可能なものまでありますが、無駄にボットすることを誓います。







分析が困難なログ形式の別のファイルでこの投稿を書くことを余儀なくされたため、検索プロセスで既成のエクスプロイトを作成するまで、別の「脆弱性」が発生しました。







そして、ある開発者にこの記事について考えさせたら、それは大したことです。そして、おそらく彼のプログラムによって書かれた雑誌を分析するとき、彼らは彼を汚い言葉で覚えておらず、むしろ彼を感謝します。







まず、わいせつな...







クリック(警告された)...
clear; echo -e "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\nboYc0xU9sUMX7w2goPauyw==" | openssl enc -aes-128-cbc -a -d -salt -pass pass:wtf
      
      





おそらくgit-bashまたはmingwの下で啓示が開きますが、Windowsを使用している同僚に謝罪します...







すべて落ち着いて行きました...







(スキッドの脚注:言及されたエクスプロイトは記事にありません-自分で考えて書いてください)







それで、ロギングに関して開発世界で何が起こるか:









特定のケースで対処しなければならないこと(例としてfail2banを使用)と、これが少なくとも良くない理由についての私の小さな分析(eng)です。







次に詳細を示します。例として、次の2行を見てください。







 Aug 18 08:04:51 srv sshd[2131]: Failed password for invalid user test from 1.2.3.4 port 46589 ssh2 from 4.3.2.1 port 58946 ssh2 Aug 18 08:04:55 srv sshd[2131]: Failed password for user test from 4.3.2.1 port 58946 ssh2: ruser from 1.2.3.4 port 46589 ssh2
      
      





ログアナライザー(別名ボット)をしばらく忘れて、人間の目で見てください。 ここですべてを理解していますか?

いいえ、彼らは何かを「悪用する」か、脆弱性を見つけようとしています。それは肉眼で見ることができます。 つまり 少なくとも、それぞれに2つの異なるIPアドレスが存在することを混同する必要があります。







問題は異なります。これら2つのアドレスのうち、どちらが悪いのでしょうか。







OpenSSHの興味深いソース( auth.c



モジュール)、つまりこれらの行が作成された場所を簡単に見てみましょう(はい、はい、あなたは正しく理解しました-それらは1つの関数によって作成されました)。







 authmsg = authenticated ? "Accepted" : "Failed"; authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s", authmsg, method, submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, authctxt->valid ? "" : "invalid user ", authctxt->user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), authctxt->info != NULL ? ": " : "", authctxt->info != NULL ? authctxt->info : "");
      
      





すでにはるかに明確ですよね? さて、あなたはすでに答えを知っていますか? それでもない?..うーん...







さて、私は陰謀を長引かせません:これは4.3.2.1です







最初のケースでは、ホスト4.3.2.1から「 authctxt->user



on username」( authctxt->user



)をユーザー名- "test from 1.2.3.4 port 46589 ssh2"



実行しようとし"test from 1.2.3.4 port 46589 ssh2"





2番目のケースでは、ホスト4.3.2.1から、 "ruser from 1.2.3.4 port 46589 ssh2"



等しい値で"ruser from 1.2.3.4 port 46589 ssh2"



into info」( authctxt->info



)を実行しようとし"ruser from 1.2.3.4 port 46589 ssh2"









直感的な記録形式ですか?







この特定のケースを解決する鍵は、 authctxt->info != NULL ? ": " : "",



によって作成されるコロンの存在authctxt->info != NULL ? ": " : "",



authctxt->info != NULL ? ": " : "",









この傑作の開発者が考えていたこと(私は本当に理解していません...







ここで、セキュリティ監視(具体的には、たとえばfail2banなど)の観点から、いわゆる「構造」のマシン分析の複雑さを評価します。 評価する際、HOST(またはIPアドレス)は私たちにとって最も重要です。この特定の例でそれを取得することの難しさは、後者の場所が予測できないためです。 はい、常にfrom



後に続きますfrom



、外部データのマスキングが欠落し、このデータの後にログに書き込まれるため(6番目!パラメーター、 ssh_remote_ipaddr(ssh)



)、現在の位置を決定することは非常に困難です。







簡単な方法を探しているわけではありません(実際、選択の余地がありませんでした)。そのため、複雑さの例として、このエントリに適した正規表現を収集しようとします。

pythonの正規表現構文を使用します(fail2banを作成する言語として)...







まず、「静的」で厳密に型指定されたコンポーネント:









それがすべて、今では「ダイナミクス」です:









つまり 両側の信頼性を固定する次の式を取得します( ^...$



):







 ^Failed (?P<meth>\S+) for (?P<valid>invalid user )?(?P<user>\S*) from (?P<host>(?:\d{1,3}\.){3}\d{1,3})(?: port \d*)?(?: ssh\d*)?(?P<info>: .*)?$
      
      





最も単純なケースが機能することを示す2つの例によるチェック:







 ##      (bash): $ _test() { python -c 'import sys, re; regex, log = sys.argv[1:]; print(log); r = re.search(regex, log); print(r.groupdict() if r else "*NOT-FOUND*")' "$1" "$2"; }; alias t=_test; ##  : $ regex='^Failed (?P<meth>\S+) for (?P<valid>invalid user )?(?P<user>\S*) from (?P<host>(?:\d{1,3}\.){3}\d{1,3})(?: port \d*)?(?: ssh\d*)?(?P<info>: .*)?$' ##  № 1 $ t "$regex" 'Failed password for invalid user test from 4.3.2.1 port 58946 ssh2' {'info': None, 'host': '4.3.2.1', 'valid': 'invalid user ', 'meth': 'password', 'user': 'test'} ##  № 2 $ t "$regex" 'Failed publickey for root from 4.3.2.1 port 58946 ssh2: RSA SHA256:v3dpapGleDaUKf...' {'info': ': RSA SHA256:v3dpapGleDaUKf...', 'host': '4.3.2.1', 'valid': None, 'meth': 'publickey', 'user': 'root'}
      
      





では、欲張りでないキャッチオールを使用して条件(ユーザー名にスペースが含まれる)を複雑にしようとしますが、私はそれらを好きではありませんが、覚えています-私たちはあまり選択肢がありませんでした。 つまり を使用します.*?



ユーザー名に\S+



代わりに。







なぜこれが良くないのか-たとえば、右側のアンカーはほとんど開いているので、 .*$



は右側のアンカーなしの開いた式に相当します。 長い行での速度とCPUロードについては、すでに沈黙しています。 しかし、今のところ、このように続けましょう(この場合、少なくともコロンが必須です):







 $ regex='^Failed (?P<meth>\S+) for (?P<valid>invalid user )?(?P<user>.*?) from (?P<host>(?:\d{1,3}\.){3}\d{1,3})(?: port \d*)?(?: ssh\d*)?(?P<info>: .*)?$' $ t "$regex" 'Failed password for invalid user hello from space from 4.3.2.1 port 58946 ssh2' {'info': None, 'host': '4.3.2.1', 'valid': 'invalid user ', 'meth': 'password', 'user': 'hello from space'}
      
      





動作します! さて、今度は注入を使って上の例を試してみましょう:







 $ t "$regex" 'Failed password for invalid user test from 1.2.3.4 port 46589 ssh2 from 4.3.2.1 port 58946 ssh2' {'info': None, 'host': '4.3.2.1', 'valid': 'invalid user ', 'meth': 'password', 'user': 'test from 1.2.3.4 port 46589 ssh2'} $ t "$regex" 'Failed password for user test from 4.3.2.1 port 58946 ssh2: ruser from 1.2.3.4 port 46589 ssh2' {'info': ': ruser from 1.2.3.4 port 46589 ssh2', 'host': '4.3.2.1', 'valid': None, 'meth': 'password', 'user': 'user test'}
      
      





私たちが見るところ、それはまた正しく動作しているようです(どちらの場合も'host': '4.3.2.1'



正しい値'host': '4.3.2.1'



を持っています)。

しかし... ...常に、「しかし」がありますよね?







これらの例はどちらも、キャッチオールの望ましくない使用を考慮しなくても最も単純であり、より複雑なインジェクションを考え出すと、式は「壊れる」か、間違ったデータをはるかに悪く返します(理論的には脆弱性ですfail2banは「エイリアン」ホストをブロックするか、「見えない」ためにパスワードを無期限に通過します)。







ここにはグラインダーを含めず、すぐに「正しい」(いいえ、むしろより適切な)表現をします。 私もあまり好きではありません(多くの理由で)が、何があるのですか-それは...







 ^Failed (?P<meth>\S+) for (?P<cond_inv>invalid user )?(?P<user>(?P<cond_user>\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)) from (?P<host>(?:\d{1,3}\.){3}\d{1,3})(?: port \d+)?(?: ssh\d*)?(?(cond_user):|(?P<info>(?:(?! from ).)*)$)
      
      





以下に、その機能について少し説明します。 しかし、なぜそれがどのような種類の注射(テストケース)でカバーされるのか、今のところは黙っています...







まあ、一種の宿題にしましょう、またはスクリプトキディを誘惑されたくない場合は、一方で彼らは何かを学ぶ必要があります...







だから-これは、Pythonでは次のように見える条件付きの「遷移」を持つ複雑な(従属)式です







 (?P<->)? ... (?(-) -1 | -2)
      
      





簡単に言えば、なぜそれが難しいのか(部下):









はい、 "(?:(?! from ).)*"



という表現は"(?:(?! from ).)*"



条件付き)キャッチオールであり、(これまでに) " from "



一致しない場合にすべてを収集します。







実際、原理的には通常のルールでは理解されていない、または完全に構造的なログまで、指定された例よりもはるかに複雑なログがあります(または、その複雑さのために、3階建ての条件付き遷移があなたの代わりに脳を取り去ってしまいます)。 トレーラーによって複数のレコードからデータを収集できる場合があります(それらに共通の識別子がある場合)。







残念ながら、ニューラルネットワークも万能薬ではありません。 原則として、最初に必要な情報を提供する必要があります。学習プロセスでは、理想的には「ごみ」を収集してはいけません。







残念ながら、そのようなログは私たちが望むよりも一般的であり、ログの「メーカー」には他の多くの質問がしばしばあります。 論争はしばしばこの理由で起こります(たとえば、 ヤリコプティック牧師の謙hな僕)-レギュラーシーズンをどのように(どれだけ厳密に)設計するのが良いか:









結論の代わりに、もう少し詳細に、私が信じているように、あなたはロギングを行う必要があります(それがAPIであれ、最も複雑なサーバーであれ):









さて、この特定のエントリでは、次のようになります(すべてが先頭に「強く型付け」され、ユーザー名とその他の動的情報が末尾に、たとえば引用符で囲まれます;さて、上記のurl_encodeのようにマスクします(引用符、スペース):







 Auth attempt: Failed password from 4.3.2.1 port 58946 ssh2, invalid user: "test+from+1.2.3.4+port+46589+ssh2" Auth attempt: Failed password from 4.3.2.1 port 58946 ssh2, user: "test", info: "ruser+from+1.2.3.4+port+46589+ssh2" Auth attempt: Failed publickey from 4.3.2.1 port 58946 ssh2, user: "root", info: "RSA+SHA256:v3dpapGleDaUKf..."
      
      





実際、このようなポイントはさらに多くありますが、少なくともこれらのルールまたはそれらの一部に従うと、多くの人々(だけでなく)の世界が再び新しい色で輝きます。







感謝の気持ちのあるユーザー、ログに精通している同僚、特に一部(人工知能、あらゆる種類のニューラルネットワーク、その他のボットの負担)からの多くの感謝は、カルマに感謝の意を表します。








All Articles