Vulnerabilities in ASP.NET Web Applications

High-Risk Vulnerabilities Found in ASP.NET Web Applications

Munish Walia

Munish Walia

Sr. Technical Manager

Published Jul 28 2019

In this blog, we will discuss the vulnerabilities that are found in ASP.Net application specific to Local File Inclusion and SQL Injection and how we can mitigate them.

Local File Inclusion (LFI) vulnerability occurs in ASP.NET web application when web application allows a user to read any file from web server irrespective of its extension. It may lead to sensitive information disclosure which may allow a malicious user to gain complete control of the web server when used with conjunction of other vulnerabilities, like remote execution.

SQL Injection vulnerability occurs when the user input is not sanitized and is sent as a parameter to SQL statements. Finding a chance, a malicious user may alter the data which can lead to session hijacking (account takeover) or injection of harmful scripts in the data to install malware (malicious software) on end-user system when they visit the website. One of the major consequences of SQL Injection vulnerability in web application is that the malicious user may take control of the entire web server or leak data to the public to bring down the business of an organization and hurt them financially.

Developers must be trained in coding standards so that they can write code in a secure way. Code review procedures must be in place so that such vulnerabilities can be identified early during the development/testing phase. The testing phase must also include security checks to ensure that applications are free from such vulnerabilities.

SQL Injection in ASP.net Applications

xxxxxxxxxxxxxxxxxxxxxxxx ASP.NET Code Snippet start xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server"> <form id="Form1" runat="server"> <table> <tr> <td>User:</td><td><asp:TextBox ID="user" runat="server"></asp:TextBox></td> </tr> <tr> <td>Password:</td><td><br /><asp:textbox TextMode="password" id="pass" runat="server" /></td> </tr> <tr> <td><asp:button Text="Login" runat="server" id="btn" onClick="submit"/></td> </tr> </table> </form> </asp:Content> //server side Submit button method protected void submit (object sender, EventArgs e) { string query1 = "Select username, password from admin where username <> 'admin' and password = '" + pass.Text.Trim() + "' "; try { DataSet dSet1 = new DataSet(); dSet1 = fetchWebDB(query1); } DataSet fetchWebDB(string query) { // connect to data source OleDbConnection myConn = new OleDbConnection("Provider=SQLOLEDB;Data Source=.;Initial Catalog=AMS;User ID=sa;Password=pass@123"); myConn.Open(); // initialize dataadapter with query OleDbDataAdapter myAdapter = new OleDbDataAdapter(query, myConn); // initalize and fill dataset with query results DataSet myData = new DataSet(); myAdapter.Fill(myData); myConn.Close(); // return dataset return myData; } } xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ASP.Net Code snippet end xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

The code mentioned above is vulnerable to SQL Injection attacks since the developer has not sanitized the user input before sending data to the SQL statement. Value of User and Pass variables are passed as it is to SQL statement, which should be avoided in all the cases. User input must and always be sanitized; it must escape all special character that is not intended to be there. For example – username will never have less than “<” or double quotes (“). User input must be encoded before it is saved in the database.

Secondly, the developer has used “system admin” user to connect with MS SQL database to fetch the data. In this case, all SQL statements will be executed under the context of “sa”(system admin) user. In MS SQL Server, “sa” user has the highest level of privileges. If a malicious user gains access to this application or somehow the password of “sa” user is known to him, he can perform certain actions which can help him to gain system-level access on windows server.

Thirdly, it is not recommended to keep the connection string in an application page because the revelation of source code will also reveal the connection string. It is recommended to keep it in web.config under < connectionstring/ > key in an encrypted form. Just in case a malicious user gets access to the web.config file, he would not be able to decrypt the connection string.

How to encrypt the connection string in ASP.net web application?

It is recommended that system administrator/developers should encrypt the connection strings and MachineKey in web.config before moving the application to production. Plain text passwords should always be avoided in configuration files as they become the primary targets during web attacks.

MachineKey itself must be encrypted since this key is used to encrypt/decrypt and validate ASP.NET Cookies and anti-forgery tokens.

MachineKey is as sensitive as connection strings because once this key is obtained by a malicious user, he can create an authenticated cookie which can allow him to log in as any user.

To encrypt the MachineKey element in web.config, run the following command:

aspnet_regiis -pe "system.web/machineKey" -app "[Your Application Name]"

aspnet_regiis.exe is located at following path on the web server:

c:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe

To encrypt connection strings using RSA Key Container, we will follow the below approach:

We will use the existing RSA Key Container which is created by default when .Net is installed “NetFrameworkConfigurationKey“

First of all, to read the RSA key container, ASP.NET identity of the web application must be authorized:

Web App Authorization

To encrypt the sensitive data element “connectionstring” in web.config, run the following command:

aspnet_regiis -pe "connectionStrings" -app "[Your Application Name]"

Encripting Sensitive Data Element

Below is the result of above command when web.config is opened:

Web Configuration

Another way is - Adding “Trusted connection=true” in connection string:


<connectionStrings>
<add name=”DefaultConnection” connectionString=”Server=localhost;Database=mydb;Trusted_Connection=True”
</connectionStrings>



IIS Screenshot

Above screenshot is taken from Internet Information Services (IIS) by selecting the App Pool used to run the web application. A custom account (service account) can be configured to run for Application Pool Identity. The web application will now use this identity to connect to the database and run under the context of this service account. This account must have access to MSSQL Server so that it can run SQL queries and to save data in the database.

If a malicious user collects different credentials, he may use them to brute force other services that are running at the web server level or at OS level, for example – FTP or SMB service. SQL Injection vulnerabilities are ‘input validation’ vulnerabilities and can be prevented by enforcing input validation on any user-controlled parameter.

Another important thing to take care is to disable the anonymous access to the website and enabled authentication so that the events which took place during their visit can be traced and tracked later on.

Also, directory listing should be disabled in IIS for the website:

  • Open IIS Manager.
  • Select the website to disable the listing of files.
  • Double-click Directory Browsing icon in the IIS section.

Admin should also restrict the access to specific directories that has confidential/configuration-related data. Access to a specific file can be denied which is placed in a specific folder:


<location path="confidential">
     <system.webServer>
         <security>
             <authorization>
                 <remove users="*" roles="" verbs="" />
                 <add accessType="Allow" roles="Administrators" />
             </authorization>
         </security>
     </system.webServer>
 </location>>


Mitigation Steps:

Sometimes, developers think that they can save a web application from SQL Injection vulnerabilities by using stored procedures. However, a poorly written stored procedure can be the reason for exploiting SQL Injection vulnerability in the web application.

Consider the below-stored procedure:


ALTER PROCEDURE [dbo].[SearchLeaves]
  @searchleavetype VARCHAR(50) = ''
AS
BEGIN
DECLARE @query VARCHAR(100)
SET @query = 'SELECT * FROM LEAVES WHERE category LIKE ''%' + @searchleavetype + '%''';
EXEC(@query)
END


In the above stored procedure, string concatenation is a problem and the stored procedure can be exploited to read data from any table in the database.

Parameterization can be the solution to the above-mentioned problem: Above stored procedure can be rewritten to mitigate SQL Injection vulnerability.


ALTER PROCEDURE [dbo].[SearchLeaves]
  @searchleavetype NVARCHAR(50) = ''
AS
BEGIN
  DECLARE @query NVARCHAR(100)
  DECLARE @msearch NVARCHAR(55)
 
  SET @msearch = '%' + @searchleavetype + '%'
  SET @query = 'SELECT * FROM LEAVES WHERE category LIKE @search'
  EXEC sp_executesql @query, N'@search VARCHAR(55)', @msearch
END


Instead of concatenating strings, a new string can be created adding ‘%’ characters and then pass this new string to as a parameter to SQL statement.

Another step to mitigate the SQL Injection vulnerability is to grant only limited permissions to the current user who is responsible to execute SQL statements.

Let us assume that there is a web page which is supposed to display the leaves of the employee. A new SQL user can be created in the database. By mapping a custom role, the user will only be able to to execute stored procedures. Only intended data will be re-tuned to the web page by executing stored procedures in this user’s context.

Consider the below role and user creation to mitigate SQL Injection:


CREATE ROLE CustomFetchDataRole
CREATE LOGIN TestUser WITH PASSWORD = '$Passw0rd@123##’
ALTER ROLE CustomFetchDataRole ADD MEMBER [TestUser]
IF NOT EXISTS (SELECT * FROM sys.database_principals WHERE name = N' TestUser ')
BEGIN
  CREATE USER [TestUser] FOR LOGIN [TestUser]
 
END;
GO

GRANT EXECUTE ON dbo.uspGetLeavesInfo TO TestUser
GRANT EXEC ON TYPE::DBO.MyTableType TO [CustomFetchDataRole]


Granting only specific and limited permissions to the database can go a long way in securing data. Malicious user will not be able to access any tables directly even if he is able to log in on SQL Server somehow. Now, the stored procedure (consider parameterization) will either return the intended data to the web page or will not return anything.

Another important thing to keep in mind is that the database administrators should disable “xp_cmdshell” stored procedure. Database user should not have permissions to enable this stored procedure. Developers should never use this stored procedure because a malicious user can execute operating system level commands using this procedure.

DB Admin should enable SQL Server audit logs to keep logs for Login auditing, SQL Server auditing, SQL Trace, DML, DDL, and Logon trigger events.

SQL Injection is the most dangerous attack considering the magnitude of the attack which can compromise the entire database server and the web server. This attack can be stopped by parameterization of the stored procedures and granting only limited permissions to SQL DB users.

SQL DB admins should create different users and allow them to access only specific database on the server. Only limited number of users are allowed to access a single database. Every user must have only limited permissions to access the database.

Sysadmin (SA) user should be disabled and a custom system admin user should be created instead with trimmed down privileges so that, if the malicious user somehow gets the access to database, he should not be able to gain system-level privileges using “SA” user.

ASP.NET (Local File Inclusion)

LFI vulnerability allows a malicious user to access other files on the web server. This is one of the most critical vulnerabilities listed in OWASP 10 vulnerabilities list.

Below is the sample ASP.NET code which allows certain document to be downloaded.


http://abcd.com/<vuln.page>?<vuln query string>

Consider the below code:

public partial class Downloads_Download : System.Web.UI.Page
{
  string sBasePath="";
  protected void Page_Load(object sender, EventArgs e)
  {

    try
    {
      string filename = Request.QueryString["fname"];
      string sBasePath = System.Web.HttpContext.Current.Request.ServerVariables["APPL_PHYSICAL_PATH"];
      if (sBasePath.EndsWith("\\"))
        sBasePath = sBasePath.Substring(0, sBasePath.Length - 1);
      sBasePath = sBasePath + "\\" + ConfigurationManager.AppSettings["FilesPath"] + "\\" + filename; 
      Response.AddHeader("content-disposition", String.Format("attachment;filename={0}", filename));
      Response.WriteFile(sBasePath);
    }
    catch (Exception ex)
    {
Response.Redirect("~/Error.aspx?message=" + ex.Message.ToString() + " path=" + sBasePath);
    }
  }
}


Let us walk through the above code and find out what is wrong with it.

“fname” parameter is accepted as it is without any validation or sanitization. This code is vulnerable for Directory Traversal vulnerability and information disclosure which can reveal sensitive data that may lead to further attacks.

Code should be written in such a way that only specific file extensions are allowed to download. Content type: application/octet-stream is unsafe and should not be set as default content-type defined in the switch case function.

Have a look the code below which is more secured than the earlier one:


protected void Page_Load(object sender, EventArgs e)
  {
    //string file = Server.MapPath(HttpUtility.UrlEncode(functions.RF("file")));
    string file = Server.MapPath(functions.RQ("file"));
    if (File.Exists(file))
    {
      Regex reg = new Regex(@"\.(\w+)$");
      string ext = reg.Match(file).Groups[1].Value;
      switch (ext)
      {
        case "xls":
          Response.ContentType = "application/vnd.ms-excel";
          break;
        case "xlsx":
          Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
          break;
        case "ppt":
          Response.ContentType = "application/vnd.ms-powerpoint";
          break;
        case "pptx":
          Response.ContentType = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
          break;
        default:
      Response.ContentType = " application/pdf ";
          break;
      }
      byte[] buffer = File.ReadAllBytes(file);
      Response.OutputStream.Write(buffer, 0, buffer.Length);
      Response.AddHeader("Content-Disposition", "attachment;filename=" + Path.GetFileName(file));
    }
    else
    {      
      Response.Write("This file Extension is not allowed");
    }
  }


In the above code, user can download files only with these extensions: xls, xlsx, ppt, pptx and pdf.

Developer has set a ‘content type’ for each file extension, which means for PDF file types, the content type is application/pdf and will only allow PDF files to download.

MIME (Multipurpose Internet Mail Extensions) content types describe the media type of the content/file which helps browsers to correctly process and display the content. The application must describe the ‘Content Type’ of the files while downloading or uploading the file, otherwise, the browser would have no idea about the intended content to be processed which is different from reported MIME type.

Default content type should not be “application/octet-stream”. Developers should not use this content type in their code until it is intended to.

Apart from the issues mentioned above, there are other critical vulnerabilities that exist in ASP.Net web applications. While the mitigation steps mentioned are not enough to secure the ASP.Net web applications as a whole, by following these steps, one can close at least basic vulnerabilities in ASP.NET web applications. We will discuss the remaining high-risk vulnerabilities in our upcoming blogs.

To learn more about vulnerabilities in PHP web applications, you can have a look at my other blog “High-Risk Vulnerabilities in PHP Web Applications”.