rails
Challenge
Imported from local notes.md.
Solution
Original Notes
rails
Challenge Summary
- Given: A live web service at
https://rails.squ1rrel.devand a source archivegooner.zip. - Goal: Retrieve the hidden flag in the Rails app.
- Constraints: Flag format is
squ1rrel{...}.
Initial Recon / Triage
- Observations: The app exposes a public
GET /show/:resourceroute and an admin-onlyGET /admin/postsroute. - File identification: The archive contains a Rails app with custom middleware and a small dynamic module loader.
- Entry points:
app/controllers/show_controller.rb,lib/middleware/admin_auth.rb,config/jwt.rb,config/initializers/misc.rb, andapp/controllers/admin/posts_controller.rb.
Hypotheses & Approach
- Hypothesis 1: The
show/:resourceroute can instantiate unintended classes because it doesconstantizeon attacker-controlled input. - Hypothesis 2: If the JWT secret used by the admin middleware can be disclosed, any valid cookie will satisfy admin auth because the middleware only verifies signature validity.
Execution Steps (Reproducible)
Stage 1
Commands:
cd /root/squ1rrel2026CTF/rails/artifacts/rails-ctf-dist
sed -n '1,120p' app/controllers/show_controller.rb
sed -n '1,120p' config/jwt.rb
sed -n '1,120p' config/initializers/misc.rb
sed -n '1,160p' lib/middleware/admin_auth.rb
sed -n '1,120p' app/controllers/admin/posts_controller.rb
Results:
ShowController#indexbuildsresource_name = params[:resource] + "Module"and callsresource_name.constantize.new.show.config/initializers/misc.rbdefinesclass JWTModule < JWTSecret; end.JWTSecret#showreturns the signing secret.- The admin middleware decodes the
authcookie with that secret but never checks claims. Admin::PostsController#indexblocks only the exact string"1", then runsPost.where(id: params[:id]).first.
Stage 2
Commands:
python3 artifacts/exploit.py
Results:
- The script fetches
https://rails.squ1rrel.dev/show/JWTto leak the signing secret. - It forges a valid HS256 JWT for the
authcookie. - It requests
https://rails.squ1rrel.dev/admin/posts?id[]=1so the guardid == "1"is bypassed while ActiveRecord still resolves post1. - The response returns the reserved post containing the flag.
Artifacts Produced
artifacts/rails-ctf-dist/- extracted source archive.artifacts/exploit.py- end-to-end exploit script.
Flag
squ1rrel{rails?_in_my_ctf???}