忍者ブログ

プログラミングの練習

プログラミングの問題やプログラミング関連知識、ソフトウェアのテストについてのブログです

【PicoCTF】WebインスペクターとBase64解読で隠し要素を暴く!「WebDecode」攻略アプローチ



今回は、Webアプリケーションの構造調査とクライアント側のデータ隠蔽の仕組みを学ぶWeb Exploitationの入門問題「WebDecode」に挑戦しました!


ブラウザの開発者ツール(Webインスペクター)を駆使してページを構成するファイル群を走査し、HTML内に隠された難読化データを見つけ出して復元するまでのアプローチをまとめました。




1. 開発者ツールによるファイルとソースの調査

Webアプリケーションの構造を理解するため、ブラウザの標準機能である「Webインスペクター(開発者ツール)」を活用します。


  • ・リンクや関連ファイルの走査: トップページだけでなく、サイト内に含まれる別のページ(例: about.html など)のソースコードや、構造を構成するファイルをくまなく確認。


    ・カスタム属性の発見: about.html のソースコード内にあるセクションタグを調査したところ、通常の表示テキストとは別に notify_true="..." という怪しいカスタム属性が埋め込まれていることが判明。


2. Base64エンコード文字列の識別と特徴

発見した属性値には、英数字と記号で構成された独特の文字列が設定されていました。


  • エンコード方式の推測

    文字列例: cGljb0NURnt3ZWJfc3VjYzNzc2Z1bGx5X2QzYzBkZWRfZjZmNmI3OGF9


    ・特徴の把握: 大文字・小文字・数字が綺麗に並んでおり、記号の少なさと全体的な雰囲気から「Base64エンコード」であると仮説を立てる。


3. ターミナルを用いたBase64のデコード

特定したBase64文字列を、Linux環境のコマンドラインツールを使ってデコードし、本来の文字列を復元します。


  • デコードの実行

    echo "cGljb0NURnt3ZWJfc3VjYzNzc2Z1bGx5X2QzYzBkZWRfZjZmNmI3OGF9" | base64 -d


    base64 -d コマンドにより、隠されていた機密情報を正確に抽出し、目的のテキストを取得することに成功。

【実務的な教訓】
Webブラウザに読み込まれるフロントエンドのデータ(HTML、CSS、JSなど)は、ユーザーが開発者ツール等で自由に閲覧・改変できるという前提("Client-side is not trustable")があります。実務のセキュリティ診断や開発においても、機密情報をフロントエンドのコードや属性にハードコードしない設計の重要性を再認識する良い機会となりました。


4. まとめ


  • ・Webインスペクターを活用した、HTML・関連ファイル・カスタム属性の体系的な走査


    ・Base64エンコード特有の文字列フォーマットの識別と切り分け


    ・Linuxの base64 -d コマンドによるスムーズな復元手法の確立

フロントエンドの仕組みとクライアント側の検証手法を基礎から学べる素晴らしい問題でした。このアプローチを活かして、次のWeb問題もロジカルに攻略していきたいと思います!


PR

【PicoCTF】sudoの特権昇格を見抜け!「SUDO MAKE ME A SANDWICH」の攻略アプローチ

今回は、Linuxのアクセス権限と特権昇格(sudo)の仕組みが問われる問題「SUDO MAKE ME A SANDWICH」に挑戦しました!


一般ユーザーではアクセスできない保護されたファイルに対し、システムに許可された正当な権限(sudo設定)をどのように探し出し、アクセス権を突破したのか。そのアプローチとコマンドラインの操作手順をまとめておきます。




1. 現状の調査とパーミッションの確認

まずはリモート環境にログインし、自分自身のユーザー権限と、ターゲットとなるファイルの属性を調査します。


  • ・ユーザー権限の確認(id): 現在のセッションが特権を持たない一般ユーザー(例: ctf-player)であることを確認。


    ・ファイルのパーミッション確認(ls -l): ホームディレクトリにあるターゲットファイル(flag.txt)を確認すると、オーナーである root 以外からのアクセスが一切拒否(-r--r-----)されていることが判明。

一般ユーザーの権限のままでは直接中身を読むことができないため、システム上で許可された特権昇格のパスを探す必要が生じます。




2. sudo -l による実行可能コマンドの特定

Linux環境において、現在のアカウントに許可されている `sudo` 権限を調べるためには以下のコマンドを使用します。


  • 特権リストの照会

    sudo -l


    出力結果を確認すると、パスワードの入力を必要とせず(NOPASSWD)、最高権限(ALL)で特定のプログラム(例: /bin/emacs)を実行できる設定が組み込まれていることが分かります。


3. 許可されたツールを用いたファイルの安全な閲覧

許可されたパスのプログラムを sudo 経由で呼び出すことで、root権限でファイルを直接読み込みます。


  • root権限でのエディタ起動

    sudo /bin/emacs flag.txt


    システム管理者が許可した正規のコマンドルートを通り、root権限でテキストエディタを起動してターゲットファイルをオープンします。

【ポイント】
「システム上の権限設定(sudoers)を読み解き、許可されたバイナリを通じて制限されたデータにアクセスする」というアプローチは、脆弱性診断やペネトレーションテストにおいて基本かつ非常に重要なスキルです。パーミッションと設定の不備(あるいは意図された許可設定)がいかにシステム挙動に影響するかを学ぶ好例となりました。


4. まとめ


  • ・id および ls -l による環境の初期偵察と、アクセス制御の仕組みの把握


    ・sudo -l を用いた、一般ユーザーに許可されている特権コマンドの精査


    ・許可されたプログラムパスを正確に指定したroot権限でのファイルオープン手法の確立

Linuxの権限周りの仕組みを体系的に実感できる素晴らしい問題でした。次回のチャレンジも、一歩ずつロジカルに攻略していきたいと思います!



【PicoCTF】分割ファイルを復元せよ!「Piece by Piece」のファイル結合とアーカイブ抽出アプローチ



前回に続き、愛用のM3 MacBook Airのターミナルを相棒に、CyLab Security Academy(旧PicoCTF)のカテゴリにある問題「Piece by Piece」に挑戦しました!


今回のテーマは、リモートサーバー上に散らばった複数のファイルパーツを回収し、正しく結合・解凍して中身を暴く「Linuxのファイル操作とアーカイブの復元」です。どのようなコマンドを組み立てて解決に至ったのか、そのアプローチをまとめておきます。




1. 「Piece by Piece」とはどんな問題?

指定されたホストとポートへSSHでリモート接続し、ログイン後のホームディレクトリを確認します。


  • ・接続方法: SSHを用いた非標準ポートへのリモートログイン


    ・確認されたファイル: ホームディレクトリには、実行手順が書かれた指示書(instructions.txt)と、アルファベット順に分割された複数のファイルパーツ(part_aa 〜 part_ae)が配置されていました。

指示書(instructions.txt)のヒントを読むと、「ファイルは複数のパーツに分割されたZIPファイルであること」「指定されたパスワードを用いて解凍する必要があること」が示されており、ここから具体的なコマンド操作の組み立てに入ります。




2. 2ステップで進めるファイル復元プロセス

ターミナルから標準コマンドを組み合わせて、断片化したデータを1つのアーカイブとして復元・抽出します。


  • 1. 分割ファイルの結合(Concatenation)

    cat part_aa part_ab part_ac part_ad part_ae > archive.zip


    catコマンドと標準出力のリダイレクト(>)を使い、順序通りに並んだ複数のパーツファイルを1つのZIPアーカイブファイルへと完全に結合します。

  • 2. パスワード保護されたアーカイブの解凍

    unzip archive.zip


    指示書で指定された保護パスワードを入力し、結合して復元したZIPファイルを解凍。内部に封入されていたターゲットファイルを抽出します。

【ポイント】
「分割されたデータの構造を正しく理解し、適切な順序で結合して復元する」というプロセスは、データリカバリやインシデント調査(フォレンジック)の現場でも求められる極めて実用的なスキルです。地味ながらLinuxの基本コマンドの応用力が試される好例ですね!


3. まとめ


  • ・「Piece by Piece」は、リモートサーバー上の断片化したファイル群をcatコマンドの連結によって1つのアーカイブへ復元する手法を学ぶ問題


    ・パスワード付きアーカイブに対する適切な解凍アプローチにより、隠されたターゲットファイルを抽出


    ・CUI環境でのファイル結合やアーカイブ操作など、エンジニアの基礎体力となる必須の操作手順を確認

ターミナル上での直感的なファイル操作と、ヒントから正解のコマンドを組み立てていくプロセスは非常に爽快です。次回のチャレンジもコマンドラインを駆使して華麗に攻略していきたいと思います!


【リファクタリング入門】Code Smell(コードの臭い)とは?代表例7選と危険なコードの見分け方

プログラムが「一応動く」状態であっても、内部構造に問題を抱えていることがあります。そのような将来的にバグや不具合の原因となり得るコードの不吉な兆候を「Code Smell(コードの臭い)」と呼びます。

今回は代表的な Code Smell の例と、それを解消するための考え方を解説します。





1. Code Smell(コードの臭い)とは?

Code Smell とは、直ちにエラーになるわけではないものの、「可読性の低下」「修正のしづらさ(保守性の悪化)」「バグの温床」につながるコード設計上の警告サインです。

早期に察知してリファクタリング(内部構造の改善)を行うことが、健全なソフトウェア開発を保つキーとなります。





2. 代表的な Code Smell の例(7選)


  • ① コードの重複(Duplicated Code)

    【解説】同じ処理やよく似た記述が複数の場所にコピペされている状態。

    【リスク】仕様変更があった際に修正漏れが発生し、バグの原因になります。

    【改善案】共通処理をメソッドやクラスへ抽出・共通化(DRY原則の適用)します。

  • ② 長いクラス(Large Class / God Class)

    【解説】1つのクラスに大量のフィールドやメソッドが詰め込まれ、膨大な行数になっている状態。

    【リスク】クラスの全容を把握するのが困難になり、影響範囲の特定が難しくなります。

    【改善案】関連する機能ごとにクラスを分割・抽出します。

  • ③ 長いメソッド(Long Method)

    【解説】1つの関数やメソッドの中に何百行もの処理が詰め込まれている状態。

    【リスク】「このメソッドが何をしているか」を一目で理解できず、テストも書きづらくなります。

    【改善案】処理のまとまりごとに小さなメソッドへ分割(関数の抽出)します。

  • ④ 不適切なコメント(Bad Comments)

    【解説】「コードを見ればわかること」をそのまま書いた冗長なコメントや、古い仕様のまま残された嘘のコメント。

    【リスク】コードの変更に伴いコメントが陳腐化し、読み手を混乱させます。

    【改善案】「何をしているか(How)」ではなく「なぜそうしたか(Why)」を書き、コード自体を自己説明的に修正します。

  • ⑤ 単一責務違反(Single Responsibility Principle Violation)

    【解説】1つのクラスやメソッドが複数の異なる役割(例:データ取得・計算・ファイル保存など)を兼ね備えている状態。

    【リスク】一部の修正がまったく無関係な機能に影響を与えてしまいます。

    【改善案】SOLID原則の「単一責任の原則(SRP)」に従い、1つのコンポーネントには「変更する理由が1つだけ」になるよう分割します。

  • ⑥ 複雑な判定条件(Complex Conditional Logic)

    【解説】if 文の条件式に && や || が何重にも連なり、ネスト(深さ)が深くなっている状態。

    【リスク】どの条件で真・偽になるかの視認性が悪く、境界値の不具合が発生しやすくなります。

    【改善案】ガード節の利用、条件判定を独立したメソッドへ抽出、またはポリモーフィズムを活用します。

  • ⑦ 不適切なネーミング(Bad Naming)

    【解説】data, temp, x などの意図が不明な名前や、実際の挙動と異なる不正確な命名。

    【リスク】コードの意図を汲み取るために処理を精査する必要が生じ、解読の時間が大幅に増えます。

    【改善案】変数・関数・クラスの役割や戻り値が明確に伝わる、自己説明的な名前を付けます。



3. 補足解説:Code Smell と上手に付き合うポイント


【Code Smell 探知の心構え】



■ Smell(臭い)は「バグ」そのものではない

Code Smell があるからといって、必ずしもプログラムが間違って動いているわけではありません。しかし、そのまま放置すると将来の機能追加や変更コストが肥大化します。



■ ボーイスカウト・ルールの実践

「自分が作業する前よりも、コードを少しだけきれいにして立ち去る」というボーイスカウト・ルールを意識し、日々の開発の中で少しずつ不吉な臭いを消していくのが理想的です。



4. まとめ


  • ・Code Smell:将来のトラブルを未然に防ぐための警告サイン。

    ・主な原因:コピペによる重複、膨大すぎるクラス・メソッド、意味の不透明な命名など。

    ・対策:リファクタリングを日々の開発習慣に取り入れ、可読性と保守性を高める。

コードを書く際は「動くかどうか」だけでなく、「不吉な臭いがしていないか」チェックする習慣を身につけましょう!



【プログラミング基礎】アルゴリズム表現の共通言語「疑似コード(Pseudocode)」の読み方・書き方ガイド

アルゴリズムの解説書や基本情報技術者試験などでよく使われる「疑似コード(Pseudocode)」の書き方・読み方の基本ガイドです。

特定のプログラミング言語に依存せず、処理のロジックを直感的に表現するための共通文法を分かりやすくまとめました。





1. 入出力と関数の宣言

アルゴリズムの前提条件(入力)と、最終的に得られる結果(出力)を明記するための記述です。


  • Input / Output / return

    Input: 〇〇     // 入力や関数の引数などを記述

    Output: 〇〇    // 出力や関数の返り値を記述



    return 値       // 関数の返り値として、値を返す



2. 制御構造(繰り返し・条件分岐)

処理の流れ(ループや分岐)を構造化して表現します。


  • ① for文(指定回数の繰り返し)

    for 変数 = 値1 to 値2 do

        処理

    end for
    変数の値を「値1」から「値2」まで、1ずつ増やしながら処理を実行します。

  • ② while文(条件を満たす間の繰り返し)

    while 条件 do

        処理

    end while
    条件が「真(True)」の間、処理を実行し続けます。

  • ③ if文(条件分岐)

    if 条件 then

        処理1

    else

        処理2

    end if
    条件が真ならば「処理1」を、偽(False)ならば「処理2」を実行します。



3. 演算子とデータ構造

代入、比較、論理演算、および配列の参照方法です。


  • 代入・比較・論理演算・配列

    # 代入演算

    変数 = 値              // 変数に値を代入



    # 比較演算

    値1 == 値2            // 値1と値2が等しければ真、異なれば偽

    値1 != 値2            // 値1と値2が等しくなければ真、等しければ偽



    # 論理演算

    条件1 and 条件2       // 条件1と条件2がともに真のとき真(AND)

    条件1 or 条件2        // 条件1または条件2のいずれかが真のとき真(OR)



    # 配列構造

    配列名[添字]           // 配列の指定された添字(インデックス)番目の要素を参照



4. 補足:疑似コードを実際のプログラムに落とし込む例


【疑似コードを使ったアルゴリズム例(配列の合計値を求める)】

文法例を組み合わせて作成したサンプル疑似コードです。



Input: 配列 A, 要素数 N

Output: 合計値 total



total = 0

for i = 0 to N - 1 do

    total = total + A[i]

end for

return total


■ 疑似コードを使うメリット

Python、Java、C言語など、言語ごとに異なる文法差異を気にせず、「アルゴリズムの本質的なロジック(解法手順)」だけに集中して設計・共有できるのが最大の強みです。



5. まとめ


  • ・基本構文:for / while による繰り返しと if ... else による条件分岐を明示する。

    ・終了タグ:end for や end if でスコープの終わりを明確にする。

    ・演算と参照:== や != で比較し、配列名[添字] で要素を取り出す。

アルゴリズムを学ぶ際やアイデアをコードに落とし込む前の整理に、ぜひ疑似コードを活用してみましょう!