はじめに
前回の2章「偵察」に続いて、3章もアウトプットとしてまとめてみます。
(3章は色々手を動かしてテスト環境で攻撃できたりして面白かったです。)
漏洩データの情報はまとまっている
どちらも、過去に発生したデータ漏洩(ブリーチ)の情報を検索できるサービス。
メールアドレスなどを入力すると、そのアカウントが過去の漏洩事件に含まれていないかを調べられる。
攻撃者視点だと、ターゲットのメールアドレスが過去に漏洩していないかを調べ、そこで出てきたパスワードを別サービスでも試す「パスワードリスト攻撃」の材料集めに使われてるらしい?。
ブルートフォース攻撃
パスワードリストは普通に公開されているのが驚き。以下参照。
-
rockyou.txt: 2009年のRockYou社の情報漏洩事件で流出した実際のパスワード群をまとめたリストで、Kali Linuxに標準で同梱されているらしい(
/usr/share/wordlists/rockyou.txt.gz)。実在した約1,434万件のパスワードが入っているので、辞書攻撃の定番として使われている。 - SecLists: GitHubで公開されているセキュリティテスト用のリスト集で、パスワードリストだけでなくユーザー名リストやペイロード集なども含まれている。こちらもKaliに同梱されているらしい。
ツールとしてはHydraなどでターゲットに対してブルートフォース(総当たり)攻撃を仕掛けられる。
こうした攻撃を許可なく実行すると不正アクセス禁止法などに抵触する可能性が高い(というか抵触する)ので、必ず対象の管理者と法的な合意(スコープの合意書など)を取った上で実施するもの。
パスワードリセット機能の脆弱性
ログインと違ってパスワードそのものを知っている必要がないぶん、設計にミスがあると突破口になりやすい。
(こういった画面を実装するときは注意して実装していきたい)
DBの照合順序(照合順)や暗黙的な型変換に注意
-
照合順序(コレーション)によっては大文字小文字を区別しない
- 例えば
utf8mb4_general_ciは大文字小文字を区別しない照合順序で、'Hello' = 'hello'が真となる。パスワードリセットのトークンなど、本来は完全一致で照合すべき値をこの照合順序のカラムで扱っていると、意図せず一致判定が緩くなってしまう可能性があり、攻撃者に付け込まれる隙となる
- 例えば
-
総当たり攻撃対策としてCSPRNG(暗号論的擬似乱数生成器)を使う
- 予測可能な乱数生成器でトークンを作ると、生成パターンを推測されて総当たりされるリスクがあるため、暗号学的に安全な乱数生成器を使うべき、という話。あわせてトークンの有効期限を短くし、試行回数にも制限をかけるという多層防御の考え方も紹介されていた
-
トークンをそのままDB検索に使う実装は危険:
- 通信経路上でトークンの値が書き換えられて、文字列ではなく数値の
0などが送られてきた場合、DBMS側で型変換が起きることで「最初が文字で始まらないトークンが全部ヒットしてしまう」という現象が起きるという内容。
実際にMySQLの公式ドキュメントで確認したところ、この挙動の明記あり。
mysql> SELECT 0 = 'x6'; -> 1数値として解釈できない文字列は暗黙的に
0に変換されて比較されるため、token = 0のようなクエリになった瞬間、0に変換される全ての数字で始まらないトークンがヒットしてしまう。(恐ろしい。。。。) - 通信経路上でトークンの値が書き換えられて、文字列ではなく数値の
-
Mass Assignment(マスアサインメント):
- 更新処理を実装する際、リクエストで受け取ったフィールドをそのままオブジェクトの更新に使ってしまうと、本来更新させたくないフィールド(権限フラグなど)まで書き換えられてしまう脆弱性です。権限昇格につながりやすい
パストラバーサル
以下のようなディレクトリ構成のWebサーバーがあった場合に、相対パス・絶対パスを使って本来アクセスできないはずの上位ディレクトリのファイルを覗きに行けてしまう攻撃。
/ (システムルート)
├── etc/
│ └── passwd
├── app/
│ ├── app.py
│ └── templates/
└── var/
- DBサーバーとアプリケーションサーバーが同じホストに同居している場合、条件次第ではDB側のファイル読み込みコマンドから直接ファイルを覗かれてしまうことがある
- zipファイルのアップロード機能で、zipの中にシンボリックリンクを仕込んでおくことで、展開時にシンボリックリンクが有効になり、リンク先のファイルが読み取られてしまうことがある
SSRF(Server-Side Request Forgery)
ユーザーがURLを入力できて、そのURLに対してサーバー側がリクエストを送るような機能があった場合にリンクローカルアドレスなど本来外部から直接アクセスできないはずのアドレスを指定することで
、サーバー内部の情報(クラウド環境の認証情報など)を窃取しようとする攻撃。
OSコマンドインジェクション
アプリケーション側でOSコマンドを実行している箇所を狙って、意図しないコマンドを紛れ込ませて実行させる攻撃。
-
shell=False(Pythonのsubprocessなどでの設定)にすることでシェル経由の実行を避けられる - どうしても
shell=Trueにする必要がある場合は、入力値のエスケープ処理が必須
というシンプルながら重要な対策が紹介されており勉強になった。
安全でないデシリアライゼーション
デシリアライズ(直列化されたデータをオブジェクトに復元する処理)を行っている箇所を狙って、
事前に悪意のあるコードを仕込んだデータを登録しておき、次にそのデータがデシリアライズされたタイミングでコードが実行されてしまう、という攻撃。
「クラスの生成」と「自動実行」の仕組みの連鎖をうまく利用して攻撃コードを発火させる、という考え方が紹介されており勉強になった。
学んでみて感じたこと
3章を通して一番感じたのは、実装する際に使うDBやフレームワークの機能を「深く」理解しておくことの大切さでした。
DBの型変換の挙動、シリアライズの仕組み、シェル実行の仕組み——どれも「なんとなく動く」レベルの理解のまま実装してしまうと、そこが脆弱性としてそのまま突かれてしまうんだなと痛感しました。
正直、自分もまだそのレベルまで理解できていない部分が多いと感じたので、
今後は「動けばOK」で終わらせず、使っている機能の裏側の挙動まで意識して実装していきたいと強く思いました。