Challenge / Web

ReactOOPS

ReactOOPS is a Web challenge built with Next.js 16.0.6 and React 19. The package name is react2shell, and the app uses the App Router / React Server Components stack. The intended bug is React2Shell, tracked upstream as <secret redacted>. The provided source...

Very EasyPublished 2025-10-12Sanitized local writeup

Scenario

ReactOOPS attack path

ReactOOPS is a Web challenge built with Next.js 16.0.6 and React 19. The package name is react2shell, and the app uses the App Router / React Server Components stack. The intended bug is React2Shell, tracked upstream as . The provided source...

Objective

Challenge walkthrough focused on Web evidence, validation, and reusable operator lessons.

ReactOOPS sanitized attack graph

Walkthrough flow

01

Source and route audit

02

Trust boundary flaw

03

Exploit request chain

04

Admin or proof proof

Source coverage

Moderate source coverage

Status: partial. This article is generated from 4 sanitized Markdown sources and keeps raw flags, credentials, keys, cookies, and reusable secrets out of the rendered blog.

77% coverage
Evidence verdict

Moderate confidence: the page is useful for review, but it should be treated as partial because the available source material is thinner or less narrative-complete.

  • Web/ReactOOPS/writeup.md
  • htb-challenge/Web/ReactOOPS/notes.md
  • htb-challenge/Web/ReactOOPS/memory-summary.md
  • htb-challenge/Web/ReactOOPS/hypothesis-board.md

Technical Walkthrough

ReactOOPS - Writeup

Summary

ReactOOPS is a Web challenge built with Next.js 16.0.6 and React 19. The package name is react2shell, and the app uses the App Router / React Server Components stack. The intended bug is React2Shell, tracked upstream as <secret redacted>.

Analysis

The provided source has no custom input handling, API routes, middleware, or user-defined server actions. The Dockerfile copies the flag to /app/flag.txt and runs the standalone Next.js server.

The live response exposes RSC/App Router behavior via headers such as Vary: rsc, next-router-state-tree and embedded flight data. Next.js 16.0.6 is in the vulnerable range; fixed versions include 16.0.7.

Exploit

The exploit sends a crafted multipart/form-data request with a fake React Flight chunk. The payload walks prototype references to obtain the Function constructor, then uses the $B blob handler gadget to execute JavaScript in the Node.js process.

The command copies /app/flag.txt over an existing served static chunk. Requesting that chunk then returns the flag.

bash
python3 solve/exploit.py http://<TARGET>:32509/

Result

The flag was captured and saved to loot/flag.txt.

Source-Backed Dossier

The sections below are merged from companion Markdown notes for the same case. They are rendered after sanitization so the article stays precise without publishing raw flags, credentials, or target-specific secrets.

Notes

Scope

  • Challenge: ReactOOPS
  • Category: Web
  • Difficulty: Very Easy
  • Target: http://<TARGET>:32509/
  • Workspace: <local workspace>

File Inventory

  • files/web_reactoops/challenge/package.json: Next.js 16.0.6, React ^19, package name react2shell.
  • files/web_reactoops/challenge/app/page.tsx: static page; no user routes, API routes, or server actions.
  • files/web_reactoops/Dockerfile: copies challenge flag to /app/flag.txt; runs standalone Next server on port 1337.

Evidence Ledger

TimestampActionOutput FileFindingNext Step
2026-05-07Reviewed package/sourcefiles/web_reactoops/challenge/package.jsonNext.js 16.0.6 + React 19 + react2shell naming points to React2ShellValidate against live instance
2026-05-07Fetched /analysis/index-response.txtRSC/App Router headers and flight data presentResearch matching CVE
2026-05-07Researched React2ShellWeb sources<secret redacted> affects React 19 RSC and Next.js 16.0.6; exploit uses multipart Server Action requestBuild payload
2026-05-07Sent crafted multipart requestterminal outputReact2Shell RCE executed; newly-created static files were not servedUse existing chunk as readback channel
2026-05-07Overwrote existing static chunk with /app/flag.txtsolve/exploit.pyExisting _next/static/chunks/*.js route returned flag contentSave flag
2026-05-07Verified flag formatloot/flag.txt<flag stored in loot/flag.txt> flag capturedWrite reproducible solution
2026-05-07Rechecked target after captureterminal outputRemote instance at <TARGET>:32509 no longer accepted connectionsKeep local solve and loot as final evidence

Key Insight

There is no application-specific bug in the page source. The vulnerable surface is the framework itself: React Server Components deserialization in React 19 / Next.js 16.0.6.

The practical readback channel was to copy /app/flag.txt over an already-served Next.js static chunk, then request that chunk path.

Sources Used

  • Next.js GitHub advisory: https://github.com/vercel/next.js/security/advisories/GHSA-9qr9-h5gf-34mp
  • Next.js CVE page: https://nextjs.org/blog/<secret redacted>
  • Public React2Shell exploit analysis mirrored by Sploitus: https://sploitus.com/exploit?id=160CB49F-3A19-5F23-<secret redacted>
  • Miggo technical breakdown: https://www.miggo.io/post/react2shell-cve-2025-55182-technical-breakdown

| 2026-05-27T23:35:18Z | backfill | challenge-state.json | Legacy workspace backfilled with deterministic state | High | Validate before further work |

Memory Summary

Metadata

  • Platform: HackTheBox Challenges
  • Category:
  • Challenge:
  • Difficulty:
  • Source workspace:

Validated Solve Chain

Concepts only. Do not include raw flags, reusable credentials, tokens, cookies, private keys, or live secrets.

1.

Reusable Lessons

-

Dead Ends

-

Tool Quirks

-

Evidence Paths

-

Ingestion Decision

  • Proposed for LightRAG: yes/no
  • Requires user approval before ingestion: yes

Hypothesis Board

RankPathEvidenceMissing ProofCheapest ValidationConfidenceStatus

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit Condition

Technical analogy

How to remember this solve

Think of the web app like a building with signs on every door. The solve usually comes from reading the map carefully, finding the door the app forgot to hide, then sending the exact request that proves you understand the route.

For ReactOOPS, keep the mental model simple: identify the trusted assumption, prove it with the smallest safe test, then automate or repeat only the part that directly leads to the flag.