社内サービスをホワイトハックしたら機密情報が覗けてしまった話



# はじめに
* 本記事は [Develop fun!を体現する Works Human Intelligence Advent Calendar 2020](https://qiita.com/advent-calendar/2020/whi) の11日目の記事です。
* 今週は硬めのトピックが続いていたので本日はやわらかくいきます。金曜日の息抜きのおともにどうぞ。
* ややセンシティブな内容を扱う都合上、本筋に影響のない範囲でフェイクを混ぜています。あしからずご了承ください。

# 1. 背景
時代はXX年前までさかのぼります。
当時弊社[^WHI]で開発を行っていたBtoB向けの新規システム製品(以下、新規システム)がリリース前にある程度形になってきたので
先行して社内での仮運用を始めようという話になりました。

その製品は比較的小さなものでしたが、多くの企業のバックエンドに存在する業務をカバーする機能を搭載していました。
もちろん弊社にもその業務は存在するため、次の業務を該当の製品で回してみることで製品の質をさらに高められれば、という目論見です。

当時自分は別の製品開発部門に所属していましたが、該当製品の開発者たちとは席が近く
意気揚々と仮運用の準備を進める彼らの姿を頼もしく見ていました。

社内の人事システムデータを連携するための許可を取り[^permit]、筐体を運び込み、各種設定を施し…1ヵ月ほどの準備期間を経て、該当の製品は社内向けWebサービスとして公開されます。

# 2. システム構成
上記のような経緯で公開された社内向けサービス、まずは当時の構成図を簡単に見てみましょう。
![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/857910/d3f1afe0-9d45-c93b-0a48-6e055fd055eb.png)
牧歌的ですね。
クライアントアプリケーション、アプリケーションサーバー、そしてデータベースといういわゆる3層構造です。
エンドユーザー向けの機能はブラウザに、設定担当者向けの機能はクライアントアプリケーションのexe群にそれぞれ振り分けられています。
クライアント側には共通基盤のexeがあり、共通基盤から個別の機能のexeを子プロセスとして呼び出す仕組みになっています。

各サーバーは全てオンプレです。
当時既にAmazon EC2をはじめとしたIaaS[^IaaS]の提供は始まりつつありましたが、まだまだオンプレ構成も現役の時代です。

画像内の青枠で示されている箇所は既存の社内人事システムです。
既に本運用が行われており、__機微情報含めた弊社従業員の生データが投入されています。__

画像内の黄枠で示されている箇所が今回の新規システムに相当する箇所になります。
元々あった三層構造の人事システム構成に「間借り」するような形で構築されています。

* アプリケーションサーバー・データベースサーバーは別建て
* 設定クライアントは人事システムの共通基盤の上で動作するexeを1つ追加

という形になっています。
ただし、共通基盤上のexeはそのままだと人事システムのAPIを叩きに行ってしまうので、新規サービスの設定用exeが叩くAPI用のURLをクライアント側で切り替えられるようにしています。
その設定は暗号化ファイルの形でクライアントexeを実行する端末にローカル保存されています。

# 3. 認証認可の構成
次に当時の[^past]認証認可まわりの構成を見てみます。こちらも簡単に。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/857910/94e8124b-6118-deff-d46c-f4108db105e3.png)
牧歌的ですね。SSOなんてなかった[^SSO]。
ブラウザ側とクライアント側でそれぞれ独立した認証が存在します。
ブラウザ側は特に説明の必要もないかと思うので割愛します。
クライアント側は前述した共通基盤が認証機構を持っており、社内人事システムの持つ認証認可サーバーに問い合わせて「OK/NG(認証)」と「起動可能なexeのリストや各exe内で何が出来るかの情報(認可情報)」を取得する仕組みとなっています。

今回の新規システムは設定クライアントexeを共通基盤上に、アプリケーションサーバーを独自に、という構成なので

* ブラウザ側の認証認可は独自実装
* クライアント側の認証認可は人事システムの共通基盤が提供する認証認可を流用し、新サービスでは管理しない

という形で認証認可を実現しています。


# 4. ホワイトハックしてみた
ここまで書いてきて既にお気づきの方もいらっしゃるかと思いますが、上記の構成にはセキュリティ上の脆弱性が存在します。

当時の私がそれに気づいたのは、仮運用が始まってから数日後に上記の構成をサービス開発者から教えてもらったタイミングでした。

「あれ、これもしかしていくつかの条件が揃えば__弊社開発者なら__設定側をハックできる可能性ありますね？」
「マジすか」
__「さっそく試してみましょう」__

やんちゃですね[^arrangement]。若気の至りということで大目に見てください。

先程の図を再掲しながらハックのための前提条件とゴールを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/857910/94e8124b-6118-deff-d46c-f4108db105e3.png)
上記の図のうち、設定クライアント側に着目すると

1. 共通基盤がアクセスする認証認可サーバーの場所は非公開
1. 同様にID/Passも非公開
1. 人事システムのAPI用URLは非公開
1. 新規システムのAPI用URLも非公開

となっています。

今回のハックのゴールは
__「自分がアクセスできる設定クライアントのexe」から「4. 新規システムのAPI用URL」にアクセスする__
です。これを実現できれば、社内の人事情報が覗けるはずです。

では、ハックしていきます。

まず、上記の前提条件のうち「4. 新規システムのAPI用URL」の特定と社内ネットワークからのアクセス可否の確認を行います。
当然ながら非公開(サービス開発者も知らない)ですが、__ブラウザ側が従業員向けに公開されている__のでサーバーの特定は可能です。
APIのエンドポイントについても変更されている可能性はありますが、いったんは初期値の「/api」と仮定します。
後は__使いそうなポート番号(8080とか)を順番に手動入力してwgetを叩き、応答を探ります__[^notportscan]。

さほど時間はかからず、数回の試行で新規システムのAPI用URLは特定できました。
同時に、該当のURLには開発者の個人端末からもアクセスできることを併せて確認できました。

第一関門にして最終関門の突破です。
残る1から3の制約はevilな環境を用意することで無視できるため、その準備を進めていきます。

手始めに、__ローカル環境に開発用のクライアント共通基盤を用意します__。
これはちょうど当時の私のローカル環境に既にセットアップされていたのでそれを流用します。
続いて新規サービスの設定用exeをローカルに配置し、接続設定ファイルを書き換えます。
接続設定ファイルは復号化および暗号化が必要ですが、開発者はその方法を知っているので問題なく作業できます。
これにより__ローカル環境にある新規サービスの設定用exeが「上記で特定した社内公開環境のAPI用URL」に接続する__ようにします。

最後の仕上げとして、ローカル環境のクライアント共通基盤を立ち上げます。
このとき、__共通基盤の認証認可サーバーに「開発用の認証認可サーバー」を指定し、id/passには「開発用のフル権限ユーザー」を指定します__。
開発用のフル権限ユーザーは、開発用なのでローカルに配置されている全てのexeをフル権限で起動できます。最強です。

ここまでの手順を図で示すと以下のようになります。
![image3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/857910/ae37b04e-cec6-b9f9-a76b-aea8db0eb95c.png)

手順は多いですが、やっていることは非常にシンプルで「認証と認可の迂回」です。

(※ちなみに人事側も同じ要領でハックできないか試してみましたが、そちらはちゃんと対策されていました)

# 5. 結果
上記の手順を経て新規サービスの設定用exeを立ち上げた我々の目に飛び込んできたのは、まごうことなき社内環境の設定データでした。
起動直後の画面はダッシュボードなので個人情報は一切表示されていませんが、そこにはたくさんのボタンが表示されています。
「この画面にあるボタンをあと1回押せば、従業員の個人情報が見える」という事実を確認した我々は、そっと画面を閉じ、社内の運用担当に急ぎの内線電話をかけました。


# 6. 原因と対策
いくつかここに書けない話もありますが、以下の3つを挙げておきます。

__原因1.  認証認可を他のサービスに依存した設計になっていた__
認証元は認証先がどのサービスであるかをチェックしておらず、また新サービス側も「どの認証サービスで取り付けた認証認可であるか」をチェックしていませんでした。
加えて人事システムの開発者向けSDKや設定ファイルの復号化ツールが社内で容易に入手可能であることで
雑な認証認可をしていることが露見した際に多くの開発者に悪用されうる、というリスクを過小評価していました。

対策：アプリケーションサーバーが認可情報の正当性を認可サーバーに確認できるような機能を追加しましょう。
実現手段は多くありますが、例えば人事システムの認可サーバーがトークンを発行->共通基盤上の各exeはAPIを叩く際にトークンもアプリケーションサーバーに送信->全てのアプリケーションサーバーは受け取ったトークンの正当性を認可サーバーに都度確認する、といった方法が挙げられます。

もしくは、新規サービスのAPIに何らかの認証を実装するのも良いでしょう。
応急処置ですが、新規サービス側だけで対応が完結するのは利点です。


__原因2. ACLが無い状態で社内公開してしまっていた__
~~設定が間に合ってなかっただけかもしれませんが~~、API用のURLが社内のどこからでも叩けるのはマズイ状態でした。
対策：IPホワイトリストなど、適切に設定しましょう。

__原因3. API用URLが推測可能な状態で社内公開してしまっていた__
~~設定が間に合ってなかっただけかもしれませんが~~、「API用のURLが推測可能かも」と考えたことがハックの糸口になりました。
対策：社内開発者が推測困難な値に変えましょう。見つかってしまえば意味がないですが、やらないよりはやったほうがいいです。


# おわりに
上記の情報はすぐに社内の運用担当に共有され、運用側の必要な設定変更および機能担当者の迅速な機能追加が実施されました。
こうして、従業員の機微情報漏洩は未然に防がれたのでした。めでたしめでたし。

<br>

「いやここ数日で同じことに気付いて、実際に機微情報を取得したわるいやつが居るかもしれん、マズイマズイ」
「ですね。アクセスログ確認して我々と同じような接続が他にも無いか調べないと」

<br>


「アクセスログとってないです」
「「マジで？」」

牧歌的ですね。
そこからのてんやわんやはまた別のお話なので、今回はこの辺で。

明日は最近上海事業所から帰任した大橋さんが自身の経験と学びについて熱く語る回と聞いてます。
私も楽しみにしてます！

[^WHI]: 人事システムパッケージをつくっています。弊社は創設2年目の若い会社なので、厳密には前世(分社前)の記憶です
[^permit]: 弊社従業員の人事情報がまるごと入っているので許可をとるのは大変だったようです
[^IaaS]: 当時はまだIaaSという呼称ではなかったかも
[^past]: 今は違います。だからこそこの記事が書けるわけですね
[^SSO]: 当時からSSOはありました
[^arrangement]: 良い子の皆はホワイトハック実施前に関係各所との調整はしましょう
[^notportscan]: さすがにポートスキャンをかけない自制心はありました