アカウントが乗っ取られる!? IDORを実際に試してみた【HackTheBox Armaxis writeup】

アカウントが乗っ取られる!? IDORを実際に試してみた【HackTheBox Armaxis writeup】
  • URLをコピーしました!

Webアプリでは、認証やトークンといった仕組みが導入されているだけで「安全になった」と判断されがちです。
しかし実際には、どのユーザーのデータを操作してよいかという認可の設計を誤るだけで、アカウント乗っ取りに直結するケースは少なくありません。

特に IDOR(Insecure Direct Object Reference)は、ユーザー入力をそのまま内部オブジェクトの参照に使ってしまうことで発生する脆弱性であり、認証やトークンが存在していても成立してしまう可能性があります。
その結果、他人のアカウント操作や権限奪取が可能になるケースもあります。

本記事では Hack The Box の CTF チャレンジ Armaxis を題材に、パスワードリセット機能に潜んでいた IDOR を実際に再現し、どのようにしてアカウント乗っ取りが成立するのかを検証していきます。

目次

HackTheBoxについて

今回は、実際にHackTheBox(HTB)というプラットフォームを使って、脆弱性の検証を行っています。

HackTheBoxは、Webアプリケーションやサーバ、ネットワークなど、さまざまなセキュリティ分野の演習ができる実践型CTFプラットフォームです。
実際に攻撃対象となるマシンやアプリケーションにアクセスして、手を動かしながら学べるのが最大の特徴です。

今回取り上げる「Armaxis」は、HackTheBoxで過去に提供されていたChallengeカテゴリの1つで、現在はVIPプラン以上に加入しているユーザーのみがアクセス可能なマシンです(※無料プランではアクティブなチャレンジのみが対象になります)。

他にも、Web、Reversing、Pwn、Forensicsなど多様なカテゴリのマシンやチャレンジが揃っており、自分のレベルに合わせて取り組めるのが魅力です。

HackTheBoxで本格的にスキルを磨きたい方は、ぜひVIPプランに登録して、過去のマシンやChallengeを存分に活用してみてください。

👉 HackTheBoxの公式サイトはこちら

セキュリティは「攻撃者の視点」で実践してこそ身につく

リファレンスを読むだけでは不十分。実際に攻撃してみることで初めて、 「なぜ脆弱なのか」「どう守るべきか」がリアルに理解できます。

HackTheBox なら、仮想マシン上で安全に脆弱性を体験できる演習環境が揃っています。
初心者でもOK、ステップアップしながら攻撃者の思考が身につきます。

  • リアルな攻撃シナリオに沿った仮想マシン演習
  • RCE・SQLi・XSSなど多彩な脆弱性に対応
  • VIPプランで過去のマシンにもアクセス可能

※HackTheBoxには Academy(教材型)と Labs(演習環境型)があり、課金体系が異なります。
実践を重視したい方には「Labs」の VIP プラン以上が圧倒的におすすめです。

👉 HackTheBoxの詳しい登録方法や、プランの違いはこちらをご確認ください。

チャレンジ概要:Armaxis

このチャレンジは、架空の兵器管理システム 「Armaxis」 を題材としたWebアプリケーション型のCTF課題です。
プレイヤーは一般ユーザーとしてシステムにアクセスし、用意された機能を調査しながら内部に潜む脆弱性を突いていくことになります。

Armaxis では、ユーザー登録・ログイン機能に加えて、パスワードリセット機能と、管理者のみが利用可能な 武器の配備(dispatch)機能 が実装されています。
武器配備時にはメモ欄として Markdown を入力でき、その内容はサーバ側で処理されたうえで保存・表示されます。

一見すると一般的なWebアプリケーションですが、パスワードリセット処理においてユーザーの認可チェックが不十分な実装となっており、特定の条件下で IDOR(Insecure Direct Object Reference) が成立します。
この問題を利用すると、本来操作できないはずの別ユーザー、さらには管理者アカウントの操作が可能になります。

管理者権限を取得すると、新たに利用できる機能が増え、その中には追加の攻撃面が存在します。
最終的にプレイヤーは、複数の設計不備が連鎖することで引き起こされる影響を利用し、サーバ内部の情報を取得することが目標となります。

ポイント

  • チャレンジ種別:Webアプリケーション
  • 脆弱性:IDOR、LFI
  • 攻撃の流れ:
    • 一般ユーザとして機能を調査
    • パスワードリセット処理の不備を利用して権限を奪取(IDOR)
    • 管理者機能にアクセスし、追加の攻撃面を発見
    • サーバー内部情報を奪取(LFI)
  • 学べるポイント
    • 認証と認可の違い
    • IDORがどのように成立するか

IDORとは?

Webアプリケーションにおけるセキュリティの議論では、認証(Authentication)認可(Authorization)が混同されがちです。
しかし、IDORを理解する上では、この違いを正しく区別することが不可欠になります。

認証とは「あなたは誰か」を確認する仕組みであり、ログイン処理やトークンの検証はこの役割を担っています。
一方で、認可とは「あなたは何をしてよいか」を判断する仕組みです。

IDOR(Insecure Direct Object Reference)は、この認可のチェックが欠落した状態で発生する脆弱性です。
ユーザーが指定した値(ID、メールアドレス、ファイル名など)を使って、サーバ内部のオブジェクトを直接参照しているにもかかわらず、それが本当にそのユーザーのものかを確認していない場合に成立します。

重要なのは、IDORは認証が存在していても成立するという点です。
ログイン済みであっても、あるいは有効なトークンを持っていても、参照先のオブジェクトに対する権限確認が行われていなければ意味がありません。

例えば、リクエスト中のメールアドレスをそのまま用いて、ユーザー情報を検索・更新するような実装では、
入力値を差し替えるだけで他人のアカウント操作が可能になります。
これがIDORの典型的な発生パターンです。

本記事で扱うCTFチャレンジ「Armaxis」も、パスワードリセット機能においてこの認可チェックが欠落しており、
結果としてアカウント乗っ取りに繋がっていました。

実際にIDORを試してみた!

攻撃に入る前に、まず画面を確認しておこうと思います。

1つ目は、Armaxisというシステムのログイン画面です。
adminユーザも一般ユーザも同じログイン画面を利用するようです。

2つ目は、メールボックスです。こちらは、攻撃者用のメールアドレスが用意されている形になっています。
test@email.htbが私たちのメールアドレスなので、確認しておきましょう。

偵察フェーズ:test@email.htbでアカウントを作る

まずは、test@email.htbが用意されているので、このメールアドレスでアカウントを作ってみましょう。
EMAILとPASSWORDを入力して、Registerボタンを押下するだけの簡単な登録です。

登録ができれば、「Registeration Successful」が表示されると思います。

登録ができたら、実際にログインをしてみましょう。

現時点では、「No weapons dispatfched yet.」となっていると思います。
この後、admin権限を取得して、このアカウントにweaponをdispatchしていくことになるかなと予想できます。

偵察フェーズ:ソースコードの確認

まだまだ偵察フェーズは続きます。続いては、ソースコードを確認していきます。

色々見ていく中で気になる実装が、「/reset-password」の中にありました。

router.post("/reset-password", async (req, res) => {
  const { token, newPassword, email } = req.body; // Added 'email' parameter
  if (!token || !newPassword || !email)
    return res.status(400).send("Token, email, and new password are required.");

  try {
    const reset = await getPasswordReset(token);
    if (!reset) return res.status(400).send("Invalid or expired token.");

    const user = await getUserByEmail(email);
    if (!user) return res.status(404).send("User not found.");

    await updateUserPassword(user.id, newPassword);
    await deletePasswordReset(token);

    res.send("Password reset successful.");
  } catch (err) {
    console.error("Error resetting password:", err);
    res.status(500).send("Error resetting password.");
  }
});

tokenのチェックをするまでは良いと思いますが、トークンにuserが紐づいていないのか、emailからユーザを取得しようとしています。
getUserByEmailを確認してみます。

async function getUserByEmail(email) {
  const query = `SELECT * FROM users WHERE email = ?`;
  try {
    const user = await get(query, [email]);
    return user;
  } catch (error) {
    throw error;
  }
}

SQLを確認してみても、emailのみからuserを取得していそうです。

updateUserPasswordは、emailから取得したuserIdとnewPasswordで呼び出されていますね。
こちらも確認してみると。

async function updateUserPassword(id, newPassword) {
  const query = `UPDATE users SET password = ? WHERE id = ?`;
  try {
    await run(query, [newPassword, id]);
  } catch (error) {
    throw error;
  }
}

特にtokenでの制御はないため、パラメータで指定したemailとnewPasswordで別のユーザのパスワードを変更できることがわかりました。

また、ソースコードにadminのemailアドレスがありました。
「admin@armaxis.htb」は、今後adminアカウントにログインする際に必要になるので、メモをしておきましょう。

偵察フェーズ:実際にパスワード変更のリクエストを確認してみる

次に実際に画面を操作して、パスワード変更のリクエストを確認してみようと思います。
ログイン画面に「Forgot Password?」があるので、押下してReset Password画面に遷移します。

とりあえず、提供されている「test@email.htb」のメールアドレスでパスワードを更新してみましょう。
test@email.htb」を入れてRequest Codeボタンを押下します。

画面は、tokenとnew passwordを入力するダイアログが表示されたかと思います。

tokenは、メールボックスをリロードすると確認することが可能です。

tokenとnew passwordを入力してパスワードを更新してみると、下記のようなリクエストが飛んでいることがわかりました。

各パラメータを下記のようにできれば、adminのパスワードも変更できそうですね。

  • token:「test@email.htb」で発行したトークン
  • email:adminのemailアドレス
  • newPassword:任意のパスワード

すでにすべての情報を入手可能な状態になっているため、この情報をもとに攻撃をしてみましょう。

攻撃フェーズ:adminアカウントを乗っ取る

IDORの脆弱性を利用して、test@email.htbで発行したトークンを利用して、adminアカウントのパスワードを変更し、adminアカウントを乗っ取ってみましょう。

まずは、「test@email.htb」でトークンを取得します。

この画面に遷移すれば、メールボックスにトークンが届いているはずです。

こちらに無事届いておりました。(間違えて2回押したので、3通あります)

では、下記の情報でJSONを修正してみましょう。

  • token:先ほど取得したtest@email.htbのトークン
  • newPassword:任意のパスワード(test)
  • email:admin@armaxis.htb(adminのメールアドレス)

これでリクエストを送ることで、test@email.htbのトークンで、別のアカウントのパスワードを書き換えることができるはずです。

一応、200 OKのレスポンスなので、上手くいったと思います。
画面からも確認してみましょう。

EMAILはadmin@armaxis.htbで、PASSWORDはnewPasswordで設定したものを入力してLoginボタンを押下します。

これでadminアカウントを乗っ取ることができました!
Dispatch Weaponがあるので、次はこれを使ってFlagを取得します。

おまけ:LFIを利用してFlagを取得する

今回の記事は、IDORをメインとしているため、この後の流れはシンプルにまとめさせていただこうと思います。

まず、画面にはMarkdownを記入できる欄がありました。今回は、このMarkdownを入力できるところでLFIで本来アクセス不可能なサーバー上のファイルを読み込んでみます。

flag.txtは「COPY flag.txt /flag.txt」のコマンドから、ルート直下にあることがわかります。

# Use Node.js base image with Alpine Linux
FROM node:alpine

# Install required dependencies for MailHog and supervisord
RUN apk add --no-cache \
    wget \
    supervisor \
    apache2-utils \
    curl \
    build-base

# Install MailHog binary
WORKDIR /
RUN wget https://github.com/mailhog/MailHog/releases/download/v1.0.1/MailHog_linux_amd64
RUN chmod +x MailHog_linux_amd64

# Prepare email directory and copy app files
RUN mkdir -p /email
COPY email-app /email

WORKDIR /email
RUN npm install

# Generate a random password and create authentication file for MailHog
RUN RANDOM_VALUE=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1) \
    && htpasswd -nbBC 10 test "$RANDOM_VALUE" > /mailhog-auth \
    && echo $RANDOM_VALUE > /email/password.txt

# Set working directory for the main app
WORKDIR /app

# Copy challenge files and install dependencies
COPY challenge .
RUN npm install

# Copy supervisord configuration
COPY config/supervisord.conf /etc/supervisor/conf.d/supervisord.conf

# Expose ports for the app and email client
EXPOSE 8080
EXPOSE 1337

COPY flag.txt /flag.txt

# Start supervisord
CMD ["supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]

Markdownは、「![](path)」で画像を表示することができます。
通常は画像パスを入れますが、ここにtxtを設定してみましょう。

また、image://ではなく、file://となるようにpathは設定します。

![flag](file:///flag.txt)

Dispatch Weaponができたら、test@email.htbでログインします。

すると、画像はもちろん表示できていませんが、Elementsの中にBase64にエンコードされたテキストがあるかと思います。

<img src="data:image/*;base64,SFRCe200cmtkMHduX2J1Z3NfMW5fdGgzX3cxbGQhfQo=" alt="Embedded Image">

これを何でもいいですが、デコードしてみましょう。
私はCyber Chefを利用します。

無事、フラグの取得もできました!今回はflag.txtでしたがパスワードファイルなどを取得されてしまうと、大問題につながる可能性がありますので、注意しましょう。

対策:IDORを防ぐためにはどうしたらいい?

今回の Armaxis で発生していた IDOR は、トークンの生成方式やランダム性の問題ではなく、認可チェックの欠落が原因でした。そのため、対策も「トークンを強くする」方向では不十分です。

ここでは、今回の事例を踏まえた実践的な対策を整理します。

オブジェクト参照をクライアント入力に依存しない

最も重要な対策は、メールアドレスやIDといったクライアント入力を、そのままオブジェクト参照に使わないことです。

今回のパスワードリセット処理では、リクエストに含まれるメールアドレスを用いて更新対象のユーザーを検索していました。
この設計では、入力値を差し替えるだけで他人のアカウント操作が可能になります。

本来、更新対象のユーザーは、

  • ログイン中のユーザー情報
  • トークンに紐づいたユーザーID

など、サーバ側で確定できる情報から決定すべきです。

実際に稼働しているアプリでも、クライアント入力に依存したオブジェクト参照を行っているものを、個人的にいくつも見てきました。必ず注意して開発するようにしましょう。

トークンは「本人確認」ではなく「操作許可」として扱う

パスワードリセットトークンは、単に「有効かどうか」を確認するものではありません。

  • このトークンは 誰に対して発行されたのか
  • そのユーザーの操作として使われているか

必ずサーバ側で検証する必要があります

今回の問題では、トークンは確認されていましたが、どのユーザーの操作を許可するトークンなのかという情報が無視されていました。

トークンは「本人であることを示す証明」ではなく、「特定の操作を、特定のユーザーに対して許可する鍵」として扱う必要があります。

トークンをただ発行していれば問題ない。みたいな軽い考えで開発をするとこのようになりがちです。
あまりトークンの意味を理解せずに開発しているエンジニアも多いのではないでしょうか。

管理者機能・例外フローほど厳密に確認する

パスワードリセットのような例外的なフローや、管理者専用機能は、通常の処理よりも認可が緩くなりがちです。
しかし実際には、このような例外フローこそが攻撃の起点になります。

  • パスワードリセット
  • アカウント復旧
  • 管理者専用操作

といった機能ほど、「誰が」「誰のデータを」「なぜ操作できるのか」を明確に設計・実装する必要があります。

また、一般側はどうしても緩くなってしまうときもあるので、管理者専用機能は別システムにしてしまうというのもありかと思います。

まとめ:IDORと認可設計の落とし穴

今回のチャレンジでは、パスワードリセット機能において認可チェックが不十分なままユーザー入力を信頼した結果、アカウント乗っ取りが成立することを確認しました。トークンや認証があっても、それだけでは安全とは言えません。

問題の本質は、「誰のデータを操作してよいか」をサーバ側で判断していなかった点にあります。
メールアドレスを直接オブジェクト参照に使う設計は、IDORを引き起こす典型例です。

IDORを防ぐためには、操作対象をサーバ側で一意に決定し、認可を各処理ごとに明示的に確認することが重要です。
これは特別な対策ではなく、基本的な設計原則です。

CTFを通じて実際に試してみることで、認可不備がどれほど現実的な問題かを実感できました。
興味がある方は、ぜひ Hack The Box に挑戦してみてください。

セキュリティは「攻撃者の視点」で実践してこそ身につく

リファレンスを読むだけでは不十分。実際に攻撃してみることで初めて、 「なぜ脆弱なのか」「どう守るべきか」がリアルに理解できます。

HackTheBox なら、仮想マシン上で安全に脆弱性を体験できる演習環境が揃っています。
初心者でもOK、ステップアップしながら攻撃者の思考が身につきます。

  • リアルな攻撃シナリオに沿った仮想マシン演習
  • RCE・SQLi・XSSなど多彩な脆弱性に対応
  • VIPプランで過去のマシンにもアクセス可能

※HackTheBoxには Academy(教材型)と Labs(演習環境型)があり、課金体系が異なります。
実践を重視したい方には「Labs」の VIP プラン以上が圧倒的におすすめです。

👉 HackTheBoxの詳しい登録方法や、プランの違いはこちらをご確認ください。

よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

情報セキュリティを勉強するために始めたブログです。
新人のため、広い心を持って見ていただけると嬉しく思います。
楽しくプログラミングを勉強するために、「Teech Lab.」もありますので、ソフトウェア開発にも興味があればぜひ覗いて見てください!

目次