From a919fe6dc40ff0867268c227295852d4e9ca1208 Mon Sep 17 00:00:00 2001 From: HackTricks News Bot Date: Wed, 20 Aug 2025 06:36:55 +0000 Subject: [PATCH 1/2] Add content from: Marshal madness: A brief history of Ruby deserialization exp... --- src/pentesting-web/deserialization/README.md | 82 +++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/src/pentesting-web/deserialization/README.md b/src/pentesting-web/deserialization/README.md index 9cf3f8d08..9d7b0eecd 100644 --- a/src/pentesting-web/deserialization/README.md +++ b/src/pentesting-web/deserialization/README.md @@ -1082,7 +1082,87 @@ This payload is compiled into binary Ruby code and concatenated with a carefully Using the arbitrary file write vulnerability, the attacker writes the crafted cache file to the computed location. Next, they trigger a server restart (by writing to tmp/restart.txt, which is monitored by Puma). During restart, when Rails requires the targeted file, the malicious cache file is loaded, resulting in remote code execution (RCE). -{{#include ../../banners/hacktricks-training.md}} + +### Ruby Marshal exploitation in practice (updated) + +Treat any path where untrusted bytes reach `Marshal.load`/`marshal_load` as an RCE sink. Marshal reconstructs arbitrary object graphs and triggers library/gem callbacks during materialization. + +- Minimal vulnerable Rails code path: + +```ruby +class UserRestoreController < ApplicationController + def show + user_data = params[:data] + if user_data.present? + deserialized_user = Marshal.load(Base64.decode64(user_data)) + render plain: "OK: #{deserialized_user.inspect}" + else + render plain: "No data", status: :bad_request + end + end +end +``` + +- Common gadget classes seen in real chains: `Gem::SpecFetcher`, `Gem::Version`, `Gem::RequestSet::Lockfile`, `Gem::Resolver::GitSpecification`, `Gem::Source::Git`. +- Typical side-effect marker embedded in payloads (executed during unmarshal): + +``` +*-TmTT="$(id>/tmp/marshal-poc)"any.zip +``` + +Where it surfaces in real apps: +- Rails cache stores and session stores historically using Marshal +- Background job backends and file-backed object stores +- Any custom persistence or transport of binary object blobs + +Industrialized gadget discovery: +- Grep for constructors, `hash`, `_load`, `init_with`, or side-effectful methods invoked during unmarshal +- Use CodeQL’s Ruby unsafe deserialization queries to trace sources → sinks and surface gadgets +- Validate with public multi-format PoCs (JSON/XML/YAML/Marshal) + +Detection (SAST): +- Semgrep rules: + - rails-cache-store-marshal: https://github.com/trailofbits/semgrep-rules/blob/main/ruby/rails-cache-store-marshal.yaml + - marshal-load-method: https://github.com/trailofbits/semgrep-rules/blob/main/ruby/marshal-load-method.yaml + - json-create-deserialization: https://github.com/trailofbits/semgrep-rules/blob/main/ruby/json-create-deserialization.yaml + - yaml-unsafe-load: https://github.com/trailofbits/semgrep-rules/blob/main/ruby/yaml-unsafe-load.yaml +- CodeQL: + - Query help: https://codeql.github.com/codeql-query-help/ruby/rb-unsafe-deserialization/ + - Payload PoCs: https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization + +Mitigations (what to do): +- Never pass attacker-controlled bytes to `Marshal.load`/`marshal_load` +- Prefer safe formats and APIs: + - YAML.safe_load with strict `permitted_classes` + - JSON with manual object construction + - Typed DB columns instead of opaque blobs +- Ecosystem hardening proposal: + - Introduce `Marshal.safe_load` (primitive-only by default, with `permitted_classes`) + - Warn on `Marshal.load`, switch defaults to safe behavior, and gate legacy behavior behind `Marshal.unsafe_load` + +Notes on recent timeline (selected): +- 2018–2022: Universal gadget chains across Ruby 2.x–3.x (elttam, Bowling) and patches through Ruby 3.1/3.2 +- 2019: Rails 5.2 insecure deserialization (CVE-2019-5420) +- 2024: Include Security shows gadget discovery via grep; GitHub Security Lab ships CodeQL rules + multi-format PoCs +- 2024-12: Ruby 3.4.0-rc1 near-miss in `rubygems` code path patched before GA (PR #12444) +- 2024-11/12: New Ruby 3.4 Marshal chains and SafeMarshal escape published and subsequently patched +## References +- Trail of Bits – Marshal madness: A brief history of Ruby deserialization exploits: https://blog.trailofbits.com/2025/08/20/marshal-madness-a-brief-history-of-ruby-deserialization-exploits/ +- elttam – Ruby 2.x Universal RCE Deserialization Gadget Chain: https://www.elttam.com/blog/ruby-deserialization/ +- Phrack #69 – Rails 3/4 Marshal chain: https://phrack.org/issues/69/12.html +- CVE-2019-5420 (Rails 5.2 insecure deserialization): https://nvd.nist.gov/vuln/detail/CVE-2019-5420 +- ZDI – RCE via Ruby on Rails Active Storage insecure deserialization: https://www.zerodayinitiative.com/blog/2019/6/20/remote-code-execution-via-ruby-on-rails-active-storage-insecure-deserialization +- Include Security – Discovering gadget chains in Rubyland: https://blog.includesecurity.com/2024/03/discovering-deserialization-gadget-chains-in-rubyland/ +- GitHub Security Lab – Ruby unsafe deserialization (query help): https://codeql.github.com/codeql-query-help/ruby/rb-unsafe-deserialization/ +- GitHub Security Lab – PoCs repo: https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization +- Doyensec PR – Ruby 3.4 gadget: https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization/pull/1 +- Luke Jahnke – Ruby 3.4 universal chain: https://nastystereo.com/security/ruby-3.4-deserialization.html +- Luke Jahnke – Gem::SafeMarshal escape: https://nastystereo.com/security/ruby-safe-marshal-escape.html +- Ruby 3.4.0-rc1 release: https://github.com/ruby/ruby/releases/tag/v3_4_0_rc1 +- Ruby fix PR #12444: https://github.com/ruby/ruby/pull/12444 +- Trail of Bits – Auditing RubyGems.org (Marshal findings): https://blog.trailofbits.com/2024/12/11/auditing-the-ruby-ecosystems-central-package-repository/ + +{{#include ../../banners/hacktricks-training.md}} \ No newline at end of file From b48c4084e50596f317acd20b35d320051eccf417 Mon Sep 17 00:00:00 2001 From: SirBroccoli Date: Wed, 20 Aug 2025 12:53:48 +0200 Subject: [PATCH 2/2] Update README.md --- src/pentesting-web/deserialization/README.md | 29 +------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/src/pentesting-web/deserialization/README.md b/src/pentesting-web/deserialization/README.md index 9d7b0eecd..0eed2838a 100644 --- a/src/pentesting-web/deserialization/README.md +++ b/src/pentesting-web/deserialization/README.md @@ -1120,33 +1120,6 @@ Industrialized gadget discovery: - Use CodeQL’s Ruby unsafe deserialization queries to trace sources → sinks and surface gadgets - Validate with public multi-format PoCs (JSON/XML/YAML/Marshal) -Detection (SAST): -- Semgrep rules: - - rails-cache-store-marshal: https://github.com/trailofbits/semgrep-rules/blob/main/ruby/rails-cache-store-marshal.yaml - - marshal-load-method: https://github.com/trailofbits/semgrep-rules/blob/main/ruby/marshal-load-method.yaml - - json-create-deserialization: https://github.com/trailofbits/semgrep-rules/blob/main/ruby/json-create-deserialization.yaml - - yaml-unsafe-load: https://github.com/trailofbits/semgrep-rules/blob/main/ruby/yaml-unsafe-load.yaml -- CodeQL: - - Query help: https://codeql.github.com/codeql-query-help/ruby/rb-unsafe-deserialization/ - - Payload PoCs: https://github.com/GitHubSecurityLab/ruby-unsafe-deserialization - -Mitigations (what to do): -- Never pass attacker-controlled bytes to `Marshal.load`/`marshal_load` -- Prefer safe formats and APIs: - - YAML.safe_load with strict `permitted_classes` - - JSON with manual object construction - - Typed DB columns instead of opaque blobs -- Ecosystem hardening proposal: - - Introduce `Marshal.safe_load` (primitive-only by default, with `permitted_classes`) - - Warn on `Marshal.load`, switch defaults to safe behavior, and gate legacy behavior behind `Marshal.unsafe_load` - -Notes on recent timeline (selected): -- 2018–2022: Universal gadget chains across Ruby 2.x–3.x (elttam, Bowling) and patches through Ruby 3.1/3.2 -- 2019: Rails 5.2 insecure deserialization (CVE-2019-5420) -- 2024: Include Security shows gadget discovery via grep; GitHub Security Lab ships CodeQL rules + multi-format PoCs -- 2024-12: Ruby 3.4.0-rc1 near-miss in `rubygems` code path patched before GA (PR #12444) -- 2024-11/12: New Ruby 3.4 Marshal chains and SafeMarshal escape published and subsequently patched - ## References @@ -1165,4 +1138,4 @@ Notes on recent timeline (selected): - Ruby fix PR #12444: https://github.com/ruby/ruby/pull/12444 - Trail of Bits – Auditing RubyGems.org (Marshal findings): https://blog.trailofbits.com/2024/12/11/auditing-the-ruby-ecosystems-central-package-repository/ -{{#include ../../banners/hacktricks-training.md}} \ No newline at end of file +{{#include ../../banners/hacktricks-training.md}}