Challenge

"You called it a jail camp. To me, this city's a whole lot worse.”

import os

path = input("Example: hello.sh\\n$ bash ")
if os.path.isfile(path):
    os.system(f"bash {path}")
else:
    print("File not found")

入力したファイルの存在を確認し、bashでシェルスクリプト相当のものを実行するプログラムです。

また読み出したいフラグは /flag-$(md5sum flag.txt | cut -c-32).txtであり、完全なファイル名は分かりません。

Solution

isfile()はシェルで使うようなグロブ展開(*)はできないので完全なファイル名を入れる必要があります。

浮かんだ方針は3つでした。

① ファイル名を漏洩させた後、ファイル名を指定してエラー文からフラグを取得

② /f* を含むファイルを探して実行し、ファイル名を指定してエラー文からフラグを取得

③ 任意コマンド実行や任意ファイル読み出しが可能な対話可能なコマンドを実行し、フラグを読み出す

①の検討

ファイル名を漏洩させる最もシンプルな方法はls /を実行することです。

このような内容が記載されたファイルは見当たらず没となりました。

<aside> 💡

os.path.isfile(path)

自分はこれまで「ファイルが存在するか」という関数だと思っていましたが正確には違いました。

実装は下記のようになっています。

def isfile(path):
    """Test whether a path is a regular file"""
    try:
        st = os.stat(path)
    except (OSError, ValueError):
        return False
    return stat.S_ISREG(st.st_mode)

os.stat(path) はLinux環境ならstat(2)系システムコール相当で、ファイル情報を取得します。

そして、 stat.S_ISREG(st.st_mode)で”通常の”ファイルかを判定しています。

つまり、ディレクトリはもちろん、デバイスファイルやソケットファイルも通さない仕様でした。

なので/dev配下のものは使えないことになります。

~~/dev/urandomを数百万回たたいて運よくls / sh /f*などを出すのは無理~~

</aside>

②の検討

/f*/*tなどを含む行を持つファイルをgrepしたが見つからず断念。