2015年10月23日金曜日

メトリックスフィルタでLambdaから"CloudWatch Logs"に出力されたログの件数をメトリックスにする


下図のように、LambdaのログはCloudWatch Logsに出力されますが、
さらにメトリックスフィルタ機能を使うと、そのログの(パターンにマッチした)件数を
メトリックスにして、グラフ表示したりアラーム設定したりでkるようになります。


CloudWatch Logsのロググループからロググループを指定してメトリックスフィルタを
作成します。


ログをフィルタリングするパターンを指定します。


メトリックス名を設定します。


メトリックスフィルターが作成完了しました。


下記のようにCloudWatchのメトリックスとして、パターンに該当したログの件数が
グラフ等で確認することができます。


あとは、このメトリックスに対して、アラームを設定したり、他ツールと連携したりと、
いつものCloudWatchを利用したパターンが適用できるはずです。

2015年10月22日木曜日

"apache-loggen"でダミーのアクセスログを作成する


下記の"apache-loggen"というツールを利用すると、
ダミーのアクセスログを簡単に作成することができます。
apache_log_gen

Amazon Linux上だと下記のように簡単にインストールできます。
$ sudo gem install apache-loggen --no-ri --no-rdoc -V
GET https://rubygems.org/latest_specs.4.8.gz
302 Moved Temporarily
GET https://rubygems.global.ssl.fastly.net/latest_specs.4.8.gz
200 OK
GET https://rubygems.org/quick/Marshal.4.8/apache-loggen-0.0.4.gemspec.rz
302 Moved Temporarily
GET https://rubygems.global.ssl.fastly.net/quick/Marshal.4.8/apache-loggen-0.0.4.gemspec.rz
200 OK
GET https://rubygems.org/quick/Marshal.4.8/json-1.8.3.gemspec.rz
302 Moved Temporarily
GET https://rubygems.global.ssl.fastly.net/quick/Marshal.4.8/json-1.8.3.gemspec.rz
200 OK
Installing gem apache-loggen-0.0.4
Downloading gem apache-loggen-0.0.4.gem
GET https://rubygems.org/gems/apache-loggen-0.0.4.gem
302 Moved Temporarily
GET https://rubygems.global.ssl.fastly.net/gems/apache-loggen-0.0.4.gem
Fetching: apache-loggen-0.0.4.gem (100%)
200 OK
/usr/local/share/ruby/gems/2.0/gems/apache-loggen-0.0.4/Gemfile
/usr/local/share/ruby/gems/2.0/gems/apache-loggen-0.0.4/LICENSE.txt
/usr/local/share/ruby/gems/2.0/gems/apache-loggen-0.0.4/README.md
/usr/local/share/ruby/gems/2.0/gems/apache-loggen-0.0.4/Rakefile
/usr/local/share/ruby/gems/2.0/gems/apache-loggen-0.0.4/apache-loggen.gemspec
/usr/local/share/ruby/gems/2.0/gems/apache-loggen-0.0.4/bin/apache-loggen
/usr/local/share/ruby/gems/2.0/gems/apache-loggen-0.0.4/lib/apache-loggen-boot.rb
/usr/local/share/ruby/gems/2.0/gems/apache-loggen-0.0.4/lib/apache-loggen.rb
/usr/local/share/ruby/gems/2.0/gems/apache-loggen-0.0.4/lib/apache-loggen/base.rb
/usr/local/share/ruby/gems/2.0/gems/apache-loggen-0.0.4/lib/apache-loggen/version.rb
/usr/local/bin/apache-loggen
Successfully installed apache-loggen-0.0.4
1 gem installed

こんな感じでログを作成できます。
$ apache-loggen --rotate=300 test.log
可能な限りログを"test.log"に出力し続け、300秒でログファイル(test.log)を
ローテーションしてます。
"t2.micro"インスタンス(gp2 8G)で実行していますが、下記のようなログが、
300秒で1500万行ほど作成されました。
$ head test.log
116.168.225.172 - - [19/Oct/2015:18:17:44 +0000] "GET /item/electronics/3607 HTTP/1.1" 200 125 "/item/books/70" "Mozilla/5.0 (Windows NT 6.0; rv:10.0.1) Gecko/20100101 Firefox/10.0.1"
92.36.171.201 - - [19/Oct/2015:18:17:44 +0000] "GET /item/sports/4471 HTTP/1.1" 200 87 "/category/jewelry" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.77 Safari/535.7"
152.174.149.220 - - [19/Oct/2015:18:17:44 +0000] "GET /category/toys HTTP/1.1" 200 72 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; YTB730; GTB7.2; EasyBits GO v1.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C)"
96.195.53.225 - - [19/Oct/2015:18:17:44 +0000] "GET /category/finance HTTP/1.1" 200 114 "/item/books/597" "Mozilla/5.0 (Windows NT 6.0; rv:10.0.1) Gecko/20100101 Firefox/10.0.1"
156.48.113.173 - - [19/Oct/2015:18:17:44 +0000] "GET /item/toys/2687 HTTP/1.1" 200 129 "/category/books" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; YTB730; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C)"
28.192.173.67 - - [19/Oct/2015:18:17:44 +0000] "GET /category/software HTTP/1.1" 200 117 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.77 Safari/535.7"
52.36.40.92 - - [19/Oct/2015:18:17:44 +0000] "POST /search/?c=Electronics HTTP/1.1" 200 120 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
148.99.222.197 - - [19/Oct/2015:18:17:44 +0000] "GET /category/music HTTP/1.1" 200 128 "/category/finance" "Mozilla/5.0 (Windows NT 6.0; rv:10.0.1) Gecko/20100101 Firefox/10.0.1"
200.156.28.119 - - [19/Oct/2015:18:17:44 +0000] "GET /category/toys HTTP/1.1" 200 107 "/category/giftcards" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1"
188.132.216.195 - - [19/Oct/2015:18:17:44 +0000] "GET /item/electronics/3284 HTTP/1.1" 200 123 "/search/?c=Electronics" "Mozilla/5.0 (Windows NT 6.0; rv:10.0.1) Gecko/20100101 Firefox/10.0.1"

せっかくなので、"grep"を使って特定の(最初の2行の)IP以外のログを
簡単に抽出してみます。
 grep -v -e '116\.168\.225\.172' -e '92\.36\.171\.201' test.log | head
152.174.149.220 - - [19/Oct/2015:18:17:44 +0000] "GET /category/toys HTTP/1.1" 200 72 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; YTB730; GTB7.2; EasyBits GO v1.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C)"
96.195.53.225 - - [19/Oct/2015:18:17:44 +0000] "GET /category/finance HTTP/1.1" 200 114 "/item/books/597" "Mozilla/5.0 (Windows NT 6.0; rv:10.0.1) Gecko/20100101 Firefox/10.0.1"
156.48.113.173 - - [19/Oct/2015:18:17:44 +0000] "GET /item/toys/2687 HTTP/1.1" 200 129 "/category/books" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; YTB730; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C)"
28.192.173.67 - - [19/Oct/2015:18:17:44 +0000] "GET /category/software HTTP/1.1" 200 117 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.77 Safari/535.7"
52.36.40.92 - - [19/Oct/2015:18:17:44 +0000] "POST /search/?c=Electronics HTTP/1.1" 200 120 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
148.99.222.197 - - [19/Oct/2015:18:17:44 +0000] "GET /category/music HTTP/1.1" 200 128 "/category/finance" "Mozilla/5.0 (Windows NT 6.0; rv:10.0.1) Gecko/20100101 Firefox/10.0.1"
200.156.28.119 - - [19/Oct/2015:18:17:44 +0000] "GET /category/toys HTTP/1.1" 200 107 "/category/giftcards" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1"
188.132.216.195 - - [19/Oct/2015:18:17:44 +0000] "GET /item/electronics/3284 HTTP/1.1" 200 123 "/search/?c=Electronics" "Mozilla/5.0 (Windows NT 6.0; rv:10.0.1) Gecko/20100101 Firefox/10.0.1"
176.87.120.37 - - [19/Oct/2015:18:17:44 +0000] "POST /search/?c=Games+Music HTTP/1.1" 200 98 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11"
64.150.185.107 - - [19/Oct/2015:18:17:44 +0000] "GET /category/books HTTP/1.1" 200 113 "-" "Mozilla/5.0 (Windows NT 6.0; rv:10.0.1) Gecko/20100101 Firefox/10.0.1"
問題なく該当するIPを含む行(最初の2行)が除外されました。

って処理を、もっと大量なデータでEMR(HIVE)を使って試してみる準備です。
(最終的にはLambdaから実行)

2015年10月16日金曜日

"AWS WAF"の情報源をまとめてみた


下記の記事で、いろいろとWAFをいじってきたので、
改めてWAFの情報源をまとめてみました。

AWSブログ

【AWS発表】新サービス: AWS WAF

AWS re:Invent 2015 | (SEC323) NEW LAUNCH! Securing Web Applications with AWS WAF


SlideShare



Youtube



AWSホームページ

"AWS WAF"に対して"sqlmap"で"SQL injection"の攻撃をしてみた


下記の記事でIPアドレスでのブロックは確認できたので、
"AWS WAF"を使って特定のIPアドレスからのアクセスをブロック
今回はSQL injectionのブロックを確認してみようと思います。
次のようなQuery Stringでパラメータを渡すパターンで簡単に試してみます。
$ curl http://d3q07yq8vdynnt.cloudfront.net/test.txt?id=1
test

まずはWAFの設定です。

Condition(SQL injection match condition) の作成


Query StringをURLデコードした結果に対してSQL Injectionのチェックを行うように
設定します。

 

ルールの設定


上記のConditionに引っかかったらアクションするようにルールを設定します。


Web ACLの設定


ルールに対するアクションがBlockになっていることを確認します。


WAFにSQL injectionの攻撃


WAFの設定ができたら、実際にWAFに対してSQL injectionの攻撃を行うツールを
導入します。今回は下記のsqlmapを使いました。


上図のリンクよりダウンロード、展開して、展開したディレクトリに入り、
下記のコマンドを実行します。
$ python sqlmap.py -u http://d3q07yq8vdynnt.cloudfront.net/test.txt?id=1
         _
 ___ ___| |_____ ___ ___  {1.0-dev-nongit-20151015}
|_ -| . | |     | .'| . |
|___|_  |_|_|_|_|__,|  _|
      |_|           |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting at 08:46:17

[08:46:18] [INFO] testing connection to the target URL
[08:46:18] [INFO] heuristics detected web page charset 'ascii'
[08:46:18] [INFO] checking if the target is protected by some kind of WAF/IPS/IDS
[08:46:18] [CRITICAL] heuristics detected that the target is protected by some kind of WAF/IPS/IDS
do you want sqlmap to try to detect backend WAF/IPS/IDS? [y/N]
[08:46:24] [WARNING] dropping timeout to 10 seconds (i.e. '--timeout=10')
[08:46:24] [INFO] testing if the target URL is stable
[08:46:24] [INFO] target URL is stable
[08:46:24] [INFO] testing if GET parameter 'id' is dynamic
[08:46:24] [WARNING] GET parameter 'id' does not appear dynamic
[08:46:24] [WARNING] heuristic (basic) test shows that GET parameter 'id' might not be injectable
[08:46:24] [INFO] testing for SQL injection on GET parameter 'id'
[08:46:24] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[08:46:25] [INFO] testing 'MySQL >= 5.0 boolean-based blind - Parameter replace'
[08:46:25] [INFO] testing 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause'
[08:46:25] [INFO] testing 'PostgreSQL AND error-based - WHERE or HAVING clause'
[08:46:25] [INFO] testing 'Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING clause'
[08:46:25] [INFO] testing 'Oracle AND error-based - WHERE or HAVING clause (XMLType)'
[08:46:26] [INFO] testing 'MySQL >= 5.0 error-based - Parameter replace'
[08:46:26] [INFO] testing 'MySQL inline queries'
[08:46:26] [INFO] testing 'PostgreSQL inline queries'
[08:46:26] [INFO] testing 'Microsoft SQL Server/Sybase inline queries'
[08:46:26] [INFO] testing 'MySQL > 5.0.11 stacked queries (SELECT - comment)'
[08:46:26] [INFO] testing 'PostgreSQL > 8.1 stacked queries (comment)'
[08:46:26] [INFO] testing 'Microsoft SQL Server/Sybase stacked queries (comment)'
[08:46:26] [INFO] testing 'Oracle stacked queries (DBMS_PIPE.RECEIVE_MESSAGE - comment)'
[08:46:26] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind (SELECT)'
[08:46:27] [INFO] testing 'PostgreSQL > 8.1 AND time-based blind'
[08:46:27] [INFO] testing 'Microsoft SQL Server/Sybase time-based blind'
[08:46:27] [INFO] testing 'Oracle AND time-based blind'
[08:46:27] [INFO] testing 'Generic UNION query (NULL) - 1 to 10 columns'
[08:46:27] [WARNING] using unescaped version of the test because of zero knowledge of the back-end DBMS. You can try to explicitly set it using option '--dbms'
[08:46:30] [INFO] testing 'MySQL UNION query (NULL) - 1 to 10 columns'
[08:46:31] [WARNING] GET parameter 'id' is not injectable
[08:46:31] [CRITICAL] all tested parameters appear to be not injectable. Try to increase '--level'/'--risk' values to perform more tests. Also, you can try to rerun by providing either a valid value for option '--string' (or '--regexp') If you suspect that there is some kind of protection mechanism involved (e.g. WAF) maybe you could retry with an option '--tamper' (e.g. '--tamper=space2comment')
[08:46:31] [WARNING] HTTP error codes detected during run:
403 (Forbidden) - 209 times

[*] shutting down at 08:46:31
すると、攻撃が始まります。最後に「403 (Forbidden) - 209 times」と出力され、
攻撃がブロック(403)されていることがわかります。

プロックされたリクエストの確認


下図のようにAWSコンソールから確認できます。

 

ブロックされたリクエストで実際にアクセスしてみると、ちゃんとブロックされていることがわかります。
$ curl http://d3q07yq8vdynnt.cloudfront.net/test.txt?id=1%20UNION%20ALL%20SELECT%20NULL--%20
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
Request blocked.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: dqrrId9UiGO0klLIXFZq2dnJ7VQ7mbBCeY-24G5qdx_ZaGto8WGIgA==
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>

CloudWatchとの連携


Blockの様子は次のようにCloudWatchで確認することもできます。

2015年10月15日木曜日

"Amazon Inspector"の情報のまとめ


Previewアクセスのリクエスト中につき...


AWSの発表

【AWS発表】 Amazon Inspector - 自動セキュリティアセスメントサービス

re:Inventの資料

(SEC324) NEW! Introducing Amazon Inspector

AWSドキュメント

User Guide

"AWS WAF"を使って特定のIPアドレスからのアクセスをブロック


下記でWAFの実験環境ができたので、実際に実験してみます。
WAFの実験環境(CloudFront + S3)の作成
まずは下図のように特定のIPアドレスからのアクセスをブロックしてみます。


では、具体的に設定していきます。

Condition(IP match conditions)の設定


まず、IP match conditionとして対象のIPアドレス(CIDR)を設定します。



ルールの設定


次に、上記のConditionをルールに設定します。
「アクセス元が上記で設定したIPアドレスだった場合」というルールにしています。


Web ACLの作成

最後に、Web ACLを作成します。
上記のルールに該当したらアクセスをブロック、つまり、
「アクセス元がConditionで設定したIPアドレスだった場合にブロック」
としています。


テスト


以上の設定で再度、対象のURLにアクセスすると、
今度は下記のようにブロックされました。


2015年10月14日水曜日

WAFの実験環境(CloudFront + S3)の作成


AWSからWAFのサービスが発表されました。
【AWS発表】新サービス: AWS WAF
WAFで作成したWebアクセス制御リストはCloudFrontに紐付けて使うので、
まずは、下記のような構成を作成して、WAFを実験できる環境を作ってみました。


WAFの設定



そのまま次へ。


名前(test)を入力して次へ。


そのまま次へ。


今回はルールにマッチしないリクエストは許可するように設定しました。


そのまま次へ。


Web ACLが作成されました。


S3の設定


WAFはCloudFrontに設定するので、CloudFront作成時に必要なオリジンを
用意する必要があります。今回はオリジンをS3にしました。


テスト用のファイルもアップロードしています。


CloudFrontの設定


とりあえず普通に作っていきます。

 

ここでWAFのWeb ACLを設定するところがあるので、先ほど作成した
Web ACL (test)を指定します。


テスト


CloudFront経由で先ほどS3にアップロードしたファイルにアクセスすると、
問題なく表示されます。(まだWAFのルールも設定してないので)


これで、WAFのWebアクセス制御リストやルールなどを実験する環境が整いました。