AWS提供のマネージドルールでDevelopersIOへの攻撃を検出してみた
AWSチームのすずきです。
Developers.IO の コンテンツ配信環境に対する攻撃の緩和対策としての有効性を確認するため、 AWS提供のマネージドルールを IDS(不正侵入検知システム)相当とした AWS WAFを設定、 そのフルログを Athen と QuickSight を利用して解析する機会がありましたので、紹介させていただきます。
環境について
構成図
WordPress 宛の リクエストを AWS WAF の対象としました。
環境の詳細は以下記事をご覧ください。
経緯
2016年頃
過去の Developers.IO、大量アクセスによるサーバダウンが起きやすい環境であったため、 AWS WAFのレートルールや、Kinesis、Norikra を 利用した 異常アクセスの遮断を実施していました。
2020年春
2020年春のリニューアル後、WAFによる保護を必要とする機会は減少しましたが、 大量のクロールや 脆弱性のスキャン については AWS WAFのカスタムルールによる対処が必要となる場合がありました。
2020年夏
AWS WAFの 実費のみで 利用できる AWS 提供の マネージドルール について、その有効性を評価するため、 Windows OS用 以外のルール、攻撃判定したリクエストを 全て「カウント」とする設定にした AWS WAF を用意し、ALBを通過するリクエストの判定を実施していました。
正規アクセスに対してはごく少数しか発生しない AWS WAFのカウント判定ログ、 効率的な処理を実現するため、判定結果に応じたログを事前に処理する簡易ETLを用意しました。
Athena
テーブル作成
AWS WAFのログ を解析する Athena の設定は、AWS ドキュメント記載の定義を利用しました。
S3の指定は「カウント」判定済みのものを対象としたため、パーティション設定などは省略しています。 大容量の WAFログ(フルログ)を処理する場合には、Athena の費用に注意してご利用ください。
CREATE EXTERNAL TABLE `waf_logs`( `timestamp` bigint, `formatversion` int, `webaclid` string, `terminatingruleid` string, `terminatingruletype` string, `action` string, `terminatingrulematchdetails` array< struct< conditiontype:string, location:string, matcheddata:array<string> > >, `httpsourcename` string, `httpsourceid` string, `rulegrouplist` array<string>, `ratebasedrulelist` array< struct< ratebasedruleid:string, limitkey:string, maxrateallowed:int > >, `nonterminatingmatchingrules` array< struct< ruleid:string, action:string > >, `httprequest` struct< clientip:string, country:string, headers:array< struct< name:string, value:string > >, uri:string, args:string, httpversion:string, httpmethod:string, requestid:string > ) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' WITH SERDEPROPERTIES ( 'paths'='action,formatVersion,httpRequest,httpSourceId,httpSourceName,nonTerminatingMatchingRules,rateBasedRuleList,ruleGroupList,terminatingRuleId,terminatingRuleMatchDetails,terminatingRuleType,timestamp,webaclId') STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' LOCATION 's3://athenawaflogs/WebACL/'
テーブル変換
カウントと判定されたログレコードは、UNNEST、CROSS JOIN を実施して解析がしやすい状態に変換しました。
変換結果は「CTASクエリ」を利用してテーブルに出力しています。
CREATE TABLE waf_logs_count AS SELECT "date_format"("from_unixtime"(("timestamp" / 1000)), '%Y-%m-%dT%h:%i:%s') "timestamp_utc", "t"."nonterminatingmatchingrule"."ruleid" as ruleid, "httpRequest"."clientip" as clientip, "httpRequest"."country" as country, "useragent"."value" as "UserAgent", "httpRequest"."uri" as uri, split_part("httpRequest"."uri", '/', 2) as path_1, split_part("httpRequest"."uri", '/', cardinality(split("httpRequest"."uri", '/'))) as path_last FROM (waf_logs CROSS JOIN UNNEST("nonterminatingmatchingrules") t(nonterminatingmatchingrule)), UNNEST("httpRequest"."headers") u(useragent) WHERE ((( ( "nonterminatingmatchingrule"."action" = 'COUNT' ) AND ( "useragent"."name" = 'User-Agent' ) )))
- 変換前サンプル
{ "timestamp": 1598361187218, "formatVersion": 1, "webaclId": "arn:aws:wafv2:ap-northeast-1:000000000000:regional/webacl/wafv2-webacl/0000-0000-0000-0000", "terminatingRuleId": "Default_Action", "terminatingRuleType": "REGULAR", "action": "ALLOW", "terminatingRuleMatchDetails": [], "nonTerminatingMatchingRules": [ { "action": "COUNT", "ruleId": "AWS-AWSManagedRulesCommonRuleSet" }, { "action": "COUNT", "ruleId": "AWS-AWSManagedRulesAdminProtectionRuleSet" } ], "httpRequest": { "clientIp": "0.0.0.0", "country": "RO", "headers": [ { "name": "Host", "value": "dev.classmethod.jp" }, { "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36" } ], "uri": "/articles/introduction-of-devcleaner/", "args": "", "httpVersion": "HTTP/1.0", "httpMethod": "GET", "requestId": null } }
- 変換後サンプル
{ "timestamp": "2020-08-25T13:13:07", "ruleId": "AWS-AWSManagedRulesCommonRuleSet" "clientIp": "0.0.0.0", "country": "RO", "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36" "uri": "/articles/introduction-of-devcleaner/", } { "timestamp": "2020-08-25T13:13:07",, "ruleId": "AWS-AWSManagedRulesAdminProtectionRuleSet" "clientIp": "0.0.0.0", "country": "RO", "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36" "uri": "/articles/introduction-of-devcleaner/", }
件数確認
今回、約2週間分のWAFログを対象に確認を試みました。
SELECT max(timestamp_utc), min(timestamp_utc), count(1) FROM waf_logs_count
- 開始日: 2020-08-26T11:59:04
- 終了日: 2020-09-10T12:59:58
- カウント件数: 566276
QuickSight
Athena の「CTASクエリ」で作成した解析用のテーブル、Amazon QuickSight の SPiCE (無料枠)にインポートして利用しました。
結果
ルール別判定数
コアルールセット と 管理者保護 のルール がカウント判定の殆どを占める事が確認できました。
SELECT count(1), ruleid FROM waf_logs_count group by ruleid
カウント数 | ルール名 | ManagedRuleGroupName | WCU |
---|---|---|---|
330335 | コアルールセット | AWSManagedRulesCommonRuleSet | 700 |
10870 | 管理者保護 | AWSManagedRulesAdminProtectionRuleSet | 100 |
725 | PHPアプリケーション | AWSManagedRulesPHPRuleSet | 100 |
179 | SQL データベース | AWSManagedRulesSQLiRuleSet | 200 |
105 | Linux オペレーティングシステム | AWSManagedRulesLinuxRuleSet | 200 |
98 | Amazon IP 評価リスト | AWSManagedRulesAmazonIpReputationList | 25 |
68 | 匿名 IP リスト | AWSManagedRulesAnonymousIpList | 50 |
68 | POSIXオペレーティングシステム | AWSManagedRulesUnixRuleSet | 100 |
68 | WordPress アプリケーション | AWSManagedRulesWordPressRuleSet | 100 |
29 | 既知の不正な入力 | AWSManagedRulesKnownBadInputsRuleSet | 200 |
国別解析
「JP」の判定はベスト10圏外でした。
SELECT count(1), ruleid FROM waf_logs_count group by ruleid order by count(1) desc limit 10
順位 | 件数 | country |
---|---|---|
1 | 178006 | US |
2 | 45916 | DE |
3 | 25178 | CA |
4 | 18093 | AU |
5 | 13010 | IL |
6 | 21556 | CA |
7 | 9633 | RU |
8 | 9094 | SG |
9 | 7005 | FR |
10 | 6199 | HK |
UserAgent
Botを名乗る「User-Agent」に限定して、カウントされた件数を数えてみました。
SELECT count(1), useragent FROM waf_logs_count where useragent like '%bot%' group by useragent order by count(1) desc limit 10
順位 | 件数 | useragent |
---|---|---|
1 | 39649 | Mozilla/5.0 (compatible; MJ12bot/v1.4.8; http://mj12bot.com/) |
2 | 22596 | Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) |
3 | 17342 | rogerbot/1.0 (http://www.moz.com/dp/rogerbot, rogerbot-crawler@moz.com) |
4 | 6065 | Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.92 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) |
5 | 3664 | Mozilla/5.0 (compatible; AhrefsBot/6.1; +http://ahrefs.com/robot/) |
6 | 1280 | Mozilla/5.0 (compatible; AhrefsBot/7.0; +http://ahrefs.com/robot/) |
7 | 472 | rogerbot/1.0 (http://moz.com/help/pro/what-is-rogerbot-, rogerbot-crawler+shiny@moz.com) |
8 | 445 | Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm) |
9 | 114 | ITnews-bot |
10 | 105 | Mozilla/5.0 (compatible; SemrushBot/6~bl; +http://www.semrush.com/bot.html) |
詐称の可能性もありますが有益なBotが含まれている可能性があるため、継続調査予定です。
URI
uri のパスの第一階層とファイル名を抽出して、集計を試みました。
SELECT count(1),path_1, path_last FROM waf_logs_count group by path_1, path_last order by count(1) desc limit 10
順位 | 件数 | パス(1) | ファイル名 |
---|---|---|---|
1 | 243791 | xmlrpc.php | |
2 | 17309 | category | - |
3 | 15264 | articles | - |
4 | 11965 | cloud | - |
5 | 5303 | tag | - |
6 | 4434 | etc | - |
7 | 3532 | phpmyadmin | - |
8 | 2696 | clerical | - |
9 | 2432 | smartphone | - |
10 | 1449 | server-side | - |
「/xmlrpc.php」「/phpmyadmin/」宛のリクエストがカウントされている事が確認できました。
xmlrpc.php
「xmlrpc.php」のリクエストに限定して、接続元IP、国別の確認を試みてみました。
- IPアドレス
- 国別
- 「xmlrpc.php」を除くファイル名
PHPアプリの脆弱性スキャンと推測されるリクエストが多く検出されました。
まとめ
AWS が提供するマネージドルール、多数のリクエストが検知されました。 ブロックモードで利用する事で、ウェブ攻撃の緩和が期待できる事が確認できました。
検出数の大半を占めた WordPress の脆弱性(xmlrpc.php) や、ブログ環境として必要としない事が明確なパス宛のリクエストについては、 AWS WAFの カスタムルールでの 遮断を実施する予定です。
直近、システム障害に至る規模のウェブ攻撃は発生していないため、 引き続き AWS WAFのマネージドルールは IDS 相当で利用し、カウント判定のログ回収を継続する予定です。
- PerformanceInsight(DBLoad)
誤判定が無い利用ができる目処がついたマネージドルールから順次ブロックを有効とし AWS WAF を IPS (不正侵入防止システム)として活用する方法についても、おって紹介させていただきたいと思います。