ログに残りにくい攻撃について(2019-11-21)
今回はSYN FloodやらIP詐称やらがメインです。
ふつうに(?)アクセスを止める話は
静的IPフィルタの作成 とか、
fail2banでアクセスログ監視とかでメモします。
各アプリ(apache、postfix、wtmpとか)でログとして残る攻撃は、
fail2banなどで監視&拒否すれば良いわけですが、
それができるのは、あくまでアプリとの通信が成立した場合だけであって
例えば、
SYN Floodとかポートスキャンとかpingのような攻撃は
ログに痕跡が残らなかったりするわけです。
図が示すのは、通信が成立する過程で、
外から通信を受ける時は下から順に登ってくる、
アプリから外へ発信する時は上から下へ降りていくイメージです。
だからpingとか(=ICMP)、SYN Floodとか(=TCPの接続前)による攻撃は
一番上のアプリ層までデータが登って来ないから、ログにも載らないのです。
SYN Floodの例†
80や443ポートめがけてひたすらSYNだけを投げてきます。
TCP接続時の3Wayハンドシェイク
|<- 1.SYN ------| 1.SYNが届く
|-- 2.SYN-ACK ->| 2.受信確認のACKと、こちら側からのSYNをセットで返す
|<- 3.ACK ------| 3.こちらのSYNに対するACKが届く
| | (が、3は投げずに1.SYNを投げ続けるのがSYN Flood)
- さらに、送信元IPは詐称して投げてきます
- その上、送信元ポートも80番(=http)とかに詐称して投げてきます
- その結果、こちらのAck応答がどこかの知らない企業のWebサーバへ送られます
- 80(http)や443(https)に限らず、TCPポートならどこでも良いので、見境なく大量に投げてきます
(telnet/ssh/http/smtpなどはポートが開いている確率が高いので狙われ易い)
はじめの部分を、それっぽい絵で説明・補足すると...
TCPセッションの1つ1つが資源を消費するわけですし、
大量に来るとリソースがいっぱいになって、正規の通信も不可能になる、
というのがDoS攻撃の手法の一つです。
たとえばapacheなどのWebサーバでは
セッション数/プロセス数/スレッド数等の上限を設定するのですが、
ここを多めに設定したとしても、OSにも各ユーザ毎に上限はあって
("ulimit -a" コマンドでプロセス数やらメモリやらの上限が表示できます)
いずれにせよ資源には限界があります。
そんな無駄な通信はできるだけ減らしたいところですが、
そもそも、攻撃されていることに気が付かなかったり気がついたりする、
以下、そういう内容のメモです。
具体的な確認例†
ケース1:snortに載る謎のSYN-ACK†
偶然みつけたログですが。
うちのサーバでは外に向けての通信はほとんどやらないので、
ほんの遊びゴコロセキュリティ対策として外への80, 443通信をsnortで監視していたら、
たまに、よそのWebサーバ目がけてSYN-ACKを飛ばしていることが分かりました。
TCP接続時の3Wayハンドシェイク
|<- 1.SYN ------| 1.詐称IPからSYNが届く
|-- 2.SYN-ACK ->| 2.これがsnortで検出されていた
|<- 3.ACK ------|
|-(TCP connect)-|
つまり、どこかの攻撃者が送信元ポートに80番を指定して(詐称して)うちのサーバへ攻撃してきた感じです。
うちのWebサーバは本物か偽物かにかかわらず、とりあえずSYN-ACKを返した、と。
通常は送信元ポートにWell-knownポート(1023番以下)あるいは低い番号帯を使うことは無いので
攻撃者はどこかのWebサーバへの嫌がらせが目的で、偽のSYNを世界中にばらまいているのだと思います。
(Well-knownポートで相手からSYNを受けることはあっても、SYNを投げるために使うことはない、たぶん)
そのため、
1023以下*1から来る通信はfirewallで止めてしまうことも一考したほうが良いと思います。
そして、
これと同じ理屈がICMPにも言えます...つまり、詐称したpingをばらまいて、応答をどこかのサーバへ一斉にぶつける攻撃など。
ICMP自体は調査やら保守やらには必須なので、止めるかどうかは用途次第ですよね...
たとえばWebに繋いでいるが公開はしていない(特定少数の人しかアクセスしない)目的のサーバなら、存在自体を隠すためにICMPは止める
のかもしれませんし。OSによってはデフォルトでICMP拒否していますし。
(みんなどうしているのか疑問に思ってWeb検索してみると、どうするべきとは一概には言えないことは分かりました)
ケース2:netstat に載る「大量の」SYN_RECV†
なんか、大量のSYNが飛んできて、netstat(後述)を見てびっくりしました。
IPアドレスで言えば xx.xx.xx.1、xx.xx.xx.2 (中略) xx.xx.xx.255 のように
特定のアドレス帯を連番で、あるいはランダムに詐称して攻撃してきます。
その(詐称されているっぽい)IPアドレスを "dig -x IPアドレス" で確認すると、
特定の大手企業が所有する一群だったり(=その企業を攻撃するのが目的?)、
なんの脈絡もなくただ連番だったり、様々でした。
偶然多いのではなく、明らかに攻撃である、というのは
接続数の違いを見れば分かります。
通常はTCPハンドシェイクは一瞬で終わるので、SYN_RECVのまま残る数は少ないはずです(途中で通信断とかでまれに残るのかも)
netstat -tan
# t は TCP接続
# a は ぜんぶ(all)。ユーザ自身以外の接続も見る。
# n は名前変換をしない。IPアドレスやポート番号を数字のままで出す
(いつもはこんな感じだと思います。LISTENとか、ESTABLISHEDとか)
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 0 0 219.94.xx.xx:80 xx.xx.xx.xx:32323 ESTABLISHED
※これが、SYN Floodだと大量のSYN_RECVが発生します
攻撃をまさに受けている時の注意点として、 -n オプションを忘れずに。
これを付けないとIPアドレス1つ1つに対して名前解決が発生して、動作がとても重くなってしまうからです。
一時的な調査ではなく、定期的に見たりツール化したりするなら、
(netstat は動作が重いコマンドだと思うので)
他のシステムコールや、/proc から情報を集めるスクリプト等を作ることも試してみましょう。
ケース3:通信の総量から確認するなら†
きりがないので、ひとまずこれで最後ですが、
送受信量はsarコマンドからも取得できます。
何が取得できるかは man sar を参照。たとえば"sar -n DEV" とか。(グラフ化についてはこっちでメモします)
sar以外でも何でも、とにかく通信量やらCPU使用率やらを一定周期で取得しておくと、なんか有った時になんか分かります
取得周期は短めに設定しないと、
瞬間的なアクセス数の増大が検知できないので注意しましょう。
たとえば一時間おきだと、1分間集中砲火を受けて、59分間無風状態なら、平均値からは異常が見えません。
自分の感想だと、5秒毎とか短い数値でも困ったことはありません。
実際にそれぞれの環境で動かして、OS全体やプロセス単位の負荷(psコマンド等で見れます)を確認・調整したほうが早いでしょう。
どれが正規で、どれが非正規の通信か?†
送信元IPが詐称されたものか、本物だけど単に通信を途中で切断しただけなのか、
(Webブラウザを途中で閉じたり、Wi-Fiが途中で切れたり)
1つ1つの通信が本来のものなのか、攻撃目的のものなのかは、見分けるのが困難だと思います。
お店に、正規の客と、嫌がらせの客の両方を大量に送り込むようなものです。
営業妨害(DoS攻撃)するのって簡単ですよね...もちろん、やったらダメですが。*2
とはいえ、明らかに攻撃と分かるケースとしては...
- telnetやssh、pop3やimapの接続が海外から来るわけはありません。*3
とりあえず "dig -x 送信元IP" で確認してみましょう。
国の内外は参考情報に過ぎませんが
(国内のプロキシサーバを経由すれば、国内アクセスになるので)
それにしても海外からの攻撃は多いので、目安の1つにするのはアリだと思います。
- 前述のように、送信元ポートがsshやら、httpやらのwell-knownポートなわけもありません。
- DoS攻撃だと明らかに異常な接続数なので、すぐに解ると思います。
- Webサーバのリンクを自動巡回するツールとかで一斉にアクセスする場合もあるかもしれませんが、
それもある意味DoS攻撃なので、阻止する方向で検討しても良いかと。
- ただし、自分のWebサイトの構成は確認しましょう。
1つのページに大量の画像リンクとか貼っていれば、当然アクセス数が増えるので。
そして、対策の例としては
まめにファイアウォールで防ごう、ってだけの話にはなってしまいますが...
これまでの経験・実験を踏まえて、以下にメモしますと
- 詐称された送信元IPからのアクセスを止める場合、
どこかのタイミングで「解除」が必要なのはお忘れなく。
(たとえば携帯各社のIPを詐称してきたとき、それを止めると、携帯からアクセスできなくなる)
一時的に止める(そして解除)or 長期的に止める、は使い分けることになります。
- 送信元IPが偏っている場合は
個々のIPではなく、適当なサブネット単位で阻止することも考えましょう。
(あとで解除する前提なら、ある程度一気に止めてしまって良いんじゃないかな...?)
- 大量のログやらIPアドレスやらに対して設定&解除をやるので、手動で設定できる数ではありません。
適宜スクリプト化、ツール化していきましょう。
- 初見だと、大量のDoS攻撃アクセスに引くと思いますが、
企業相手の標的型攻撃ならともかく、大半はbotが雑に(数万の標的の1つとして?)アクセスしてきているだけ、だと思うので、
落ち着いて、できるところから少しずつ対応していきましょう。
わたしは個人のサーバなので、色々実験&勉強しながらやっていますが、
企業とかだとコンティジェンシープランとかと合わせて考えるのかもしれませんね。
firewallで止めるにしても、一時的に正規のユーザからのアクセスも止めることになったりするので。
firewall-cmdなどで、IPアドレスのリストに対して接続拒否する例はこちら。
いますぐ手動で対応しなければ!みたいな時は、
私はshellスクリプト大好きなので、awkとか使いますが、
ログからIPアドレスを抜き取る手段(awk? perl? ruby? python?)に1つくらい慣れておくと便利かもしれません。
SYN Floodが大量に増えた時は、cronとnetstatでSYN_RECVの数を数えて、あるていどのサブネット単位でfirewallで止めていたら、やがて攻撃が止まりました。
(2020.03 追記 -----)
まぁ、愚痴半分ですが、
不正アクセス検知のアルゴリズムとかの難しい話はそういう製品にお願いするとして、
結局これって...
- 検出については監視周期と閾値を、どこまで厳しくするか、バランスの問題?
(厳しくし過ぎると正規アクセスも止めたり、監視にリソースが食われたりする)
- 詐称自体は前述の通り、いくらでもできるので、
止めるなら(前述の通り)発信する場所で止める必要がある
ってこと、なんじゃないんですかね?
それで...
- 発信する場所...つまりIP基盤とかネットワークとか、
ある程度、大元の部分でも止める必要がある
(通信の傍受は嫌ですけど、送信元IPの詐称を止めようって話ですから、ね)
- で、その「大元」って...国? とかが、
その大掛かりな攻撃に対して協力しているのなら...
とか邪推しちゃう訳です。送信元IPが主にどの国なのか見ながら。
あぁ、またこの国か。国に攻撃されたらもう、かなわないなぁ~、とか。そんな訳ないんでしょうけど。
...以上、現状自分で試してみての感想です。
止める効果†
実際、送信元IPを詐称とか、詐称された場所からのアクセスとかを止めることに意味があるのか? という話ですが。
不思議なのは、
ファイアウォールで対応するたびに、攻撃全体が止まったという事実です。
SYN Floodに至っては、送信元IPを詐称しているから応答は攻撃元が受け取らないので、攻撃の成果は見えないはずなのですが...
(元々、一過性のもので、たまたま攻撃が止まっただけという可能性も否めませんが、)
昔、掲示板への不正アクセスを止めた時、
Webサーバへのスパムリファラーを止めた時、
メールサーバへの不正アクセスを止めた時、
今回のSYN Flood対応、
それぞれで目に見えて攻撃回数が減っていきました。
そして、推測ですが、
世界中のサーバをbotで巡回してこういう脆弱性を調べる名目のサイトやら組織やらが有って、
(各アプリのログから送信元IPを一定期間分集めてソートすれば、なんとなく分かります)
それら組織が集めた脆弱性情報? を無料か有料で公開して、
その公開情報を元に、
攻撃や踏み台に利用できそうなサーバを24時間365日、世界中で探し回っている人々が大勢いるのだと思います。
もちろん攻撃する側にもコスト(資源と時間)はかかるから、より弱そうなサイトが優先的に狙われる、と。
つまり、言い換えると、
攻撃を無視すると、脆弱性ありとみなされて、次の攻撃を呼び込む結果になりかねないようです。
いたちごっこなのは分かってはいますが、
脆弱性を探してその情報を売る人、買って荒らす人が近寄って来てしまうので、
日頃から少しずつ対応していった方が、結果的に手間は少なくなるのかもしれません。