Flatt Security Blog

株式会社Flatt Securityの公式ブログです。プロダクト開発やプロダクトセキュリティに関する技術的な知見・トレンドを伝える記事を発信しています。

株式会社Flatt Securityの公式ブログです。
プロダクト開発やプロダクトセキュリティに関する技術的な知見・トレンドを伝える記事を発信しています。

Flatt Security Developers' Quiz #2 解説

はじめに

下記のTweetで出題させていただいた、Flatt Security Developers' Quiz #2にご参加いただきありがとうございました!

景品の獲得条件を満たした方には追ってメールでご連絡を差し上げますので、ご確認いただけますと幸いです。なお、景品獲得条件を満たさなかった方にはご連絡いたしません。ご了承ください。

今回のクイズでFlatt Securityに興味を持ってくださった方は是非下記のバナーよりサービス詳細をご覧ください。

Flatt Securityのセキュリティ診断

今回のクイズの確認

ソースコード

const express = require("express");
const { execSync } = require("child_process");
const app = express();

/*
    local ping check
*/
app.get("/", function(req, res) {
    const ip_address = req.query.ip;

    if(!ip_address){
        res.send("?ip=[your_ip]");
        return;
    }

    if(ip_address.length > 16){
        res.send("Error! IP is too long.");
        return;
    }

    if(/[!@#$%\^&*()\-_+=\[\] {}'";:,:?~\\]/.exec(ip_address)){
        res.send("Error! Your request is filtered!");
        return;
    }

    const cmd = "sh -c 'ping -c 1 " + ip_address + "' 2>&1 >/dev/null; true";
    const stderr = execSync(cmd, {"timeout": 1000});
    if(stderr != ""){
        res.send("Error! " + stderr);
        return;
    }

    res.send("Your IP is in a good state!");
});

app.listen(1337);

デモ環境

https://2207okapi.twitter-quiz.flatt.training/

出題形式

JavaScriptコードの脆弱性を突き ls コマンドを実行することで隠されたファイルを発見し、ファイル名を回答する。

難易度

開発者にとっても「かんたん」という想定で設定しました。セキュリティエンジニアであれば一瞬で解けてしまうかもしれません。

解答例

https://2207okapi.twitter-quiz.flatt.training/?ip=%60ls%60 のようにパラメータを付与したURLにアクセスすると、エラーメッセージ中に ls コマンドの実行結果が含まれ、隠されたファイル名を奪取することができます。

Error! ping: wow_congrats_you_executed_a_system_command.txt: Name or service not known

よって、wow_congrats_you_executed_a_system_command.txt が正答となります。

解説

今回のQuizは非常にシンプルで、バッククォート ` がフィルタされていないことに気づけるかがポイントです。

まずは正規表現による記号のフィルタの実装を注視してください。バッククォートがブロックされていませんね。

    if(/[!@#$%\^&*()\-_+=\[\] {}'";:,:?~\\]/.exec(ip_address)){
        res.send("Error! Your request is filtered!");
        return;
    }

そうすると、以下の行で組み立てられているシェルコマンドに `ls` を渡すことで、我々が求めている ls コマンドの実行結果を紛れ込ませることができそうです。

const cmd = "sh -c 'ping -c 1 " + ip_address + "' 2>&1 >/dev/null; true";

ip_address 部分が ls コマンドの実行結果の文字列になれば当然pingコマンドはエラーを起こしますので、 stderr 経由で隠されたデータを獲得することが可能です。

ですので、解答方法の例としては

https://2207okapi.twitter-quiz.flatt.training/?ip=%60ls%60

もしくは

https://2207okapi.twitter-quiz.flatt.training/?ip=`ls`

にアクセスすることとなるでしょう。

このような脆弱性が起こるパターンへの対策方法

Quiz #1 でも同様の脆弱性が存在しましたが、「拒否リストを用いて特定の文字列の入力を阻害する」という手法は開発者の想定外なバイパスをされる可能性が残ってしまいます。

もしユーザーの入力を想定する箇所において「特定の文字列だけ受け付けたい」というような場合は「許可リストを作成し、入力された文字列がそのリストに一致する文字列かどうか比較する」といった方法で対策することが可能です。

特に今回のようにOSコマンドを用いる場合は、以下のような対応を考えてみるのもよさそうです。

  • そもそもOSコマンドを使わないような実装に置き換えられないか検討する
  • OSコマンドを利用するなら、シェルを起動しない関数を利用する
    • Node.js ならexec ではなく execFile を利用する

終わりに

Quizは2回目ですが、前回に引き続きたくさんの方にご参加いただけて大変嬉しかったです。

なお、Quiz #1 に関してはこちらの記事をご覧ください。

また、我々株式会社Flatt Securityはセキュリティ診断サービスを提供しています。

セキュリティエンジニアによる手動診断によって高い精度で脆弱性を洗い出すことが可能です。実際、今回題材にしたような脆弱性はツールのスキャンのみでは発見は難しいことが多く、セキュリティエンジニアによる手動検査が効果的です。

ツールによる診断しか過去実施しておらず認証や決済といった重要な機能のセキュリティに不安があったり、既存のベンダーとは違う会社に依頼したいと考えていたりする方はお気軽にご相談ください。

数百万円からスタートの大掛かりなものばかりを想像されるかもしれませんが、上記のデータが示すように、診断は幅広いご予算帯に応じて実施が可能です。ご興味のある方向けに下記バナーより料金に関する資料もダウンロード可能です。

また、Flatt Securityはセキュリティに関する様々な発信を行っています。 最新情報を見逃さないよう、公式Twitterのフォローをぜひお願いします!

twitter.com

ここまでお読みいただきありがとうございました。