How to fix directory traversal security vulnerability in C# asp.net? - asp.net

Find Snapshot here While running the [IBM Security AppScan] tool for one of my asp.net mvc web applications, I am getting path traversal vulnerabilities in my code. Please see snapshot attached and sample code to understand the issue better. Is there a way to fix such issues?
Sample Code:
var storagePath = ConfigurationManager.AppSettings.Get("DOCS_STORAGE_PATH") + #"\Attachments";
var strMonth = DateTime.Now.Month.ToString().Length == 1 ? "0" + DateTime.Now.Month : DateTime.Now.Month.ToString();
var strYear = DateTime.Now.Year.ToString();
var strFolder = strYear + #"\" + strMonth + #"\";
storagePath = storagePath + #"\" + strFolder;
if (!Directory.Exists(#"" + storagePath))
{
Directory.CreateDirectory(#"" + storagePath);
}

You need to enforce your input validation to solve your issue.
you should validate storagePath in the first line after the reading of the configuration.
But, anyway, If the path is store in a configuration on your server, I suspect a False Postive from AppScan Source

If you are using asp.net MVC framework then you don't need to worry about directory traversal at-least for the config files, dll , cshtml files etc. IIS will not server these types of sensitive information at any cost. But still its always better to encrypt your config files if it has some sensitive information like password , connection string etc ..
It's better to encrypt the machine key and connection string info in config files for ease of use.
The next point if the files we save our self, it may be in database or in server path.
In both cases we have to be careful about the attacks. Not only directory attack but also file upload attack.
If your file share is readable by the user that your app pool is
running under (Network Service by default) you can remove the virtual
directory completely and create an ASP.NET(any framework)application
that will stream the files to the browser. If you're using MVC it's
simply returning a file result. This has an added benefit in that you
will be able to restrict the users from downloading the files
Note : Since you are taking the path from web.config doesn't meant that, the files under that path are safe against directory attack. If a hacker somehow get the path , then he can try that directly in the browser\hacking tools\etc.. So the objective should be to secure the files not the path
Simple idea is to create another application/method which is capable of serving the file stream based on request. There you can validate the user and serve the file, file can even be saved in database or file system (there app pool user's doesn't have direct access)

Related

Encrypt and Decrypt documents through asp.net application

My asp.net application is in Web Server A and displays and let download MS-Word or PDF documents that are stored in Web Server B.
For security reasons, I was advised to encrypt and decrypt those documents when serving them up on the webserver A.
Could anyone give me some clue on how to do that?
I've never seen some utility before. My code just give value to a link control and let the user to click on it to display a MS-Word or PDF document, like:
Dim RemoteFolder As String
Dim RemoteFileName As String
RemoteFolder = "http://192.168.32.98/Application/Documents/"
RemoteFileName = "MyWordDocument.doc"
lnkOpenDocument.NavigateUrl = RemoteFolder + RemoteFileName
Using SSL might help, that protects all request/responses between the two servers. Otherwise .Net does have a encryption/decryption library under System.Security:
http://support.microsoft.com/kb/307010 also see this previous post What's the easiest way to encrypt a file in c#?
you can always grab the file from the user, encrypt using one of the above methods, and drop the encrypted file on webserver B. when reading it rather than link directly to the .doc file, link to another asp.net page, pass the ID of the file into that new page and have it pull the file from Webserver B decrypt it and display to the user.

Authentication Issue when accesing Reporting Service

Well, I already tried a lot of stuff to solve this issue, but none did.
I developed a Reporting Service (2005) and deployed it.
This report will be used by everyone who access a website (it's a internet site, so, won't be accessed by intranet) developed on the framework 3.5 (but I think the framework's version is not the source of the problem).
When the user clicks on the button to download the .pdf which the Reporting automatically generates (the end-user never sees the html version of the Report), it asks for windows credentials.
If the user enters a valid credential (and this credential must be a valid credential on the server which the Reporting Service is deployed), the .pdf is obviously downloaded.
But this can't happen. The end-user must download the .pdf directly, without asking for credentials. Afterall, he doesn't even have the credentials.
Response.Redirect("http://MyServer/ReportServer/Pages/ReportViewer.aspx?%2fReportLuiza%2fReportContract&rs:Format=PDF&NMB_CONTRACT=" + txtNmbContractReport.Text);
The code snippet above, shows the first version of my code when the user clicks the button. This one propmts for the Windows credentials.
I already tried to change on IIS the Authentication of the virtual directory ReportServer, but the only one which works is the Windows Credentials. The other ones doesn't even let me open the virtual directory of the Report or the Report Manager's virtual directory.
When I tried to change it to Anonymous Authentication he couldn't access the DataBase. Then I choose the option to Credentials stored securely on the report server. Still doesn't work.
The physical directory of my ReportServer virtual directory points to the reporting server folder on the Hard Disk (C:\Program Files\Microsoft SQL Server\MSSQL.5\Reporting Services\ReportServer). I moved the same folder to my wwwroot directory.
Didn't work. The virtual directory didn't even open. Then I read this could be a problem because I had the same name on two folders (one in C: and other in wwwroot). So I changed the name of the one in wwwroot. Same issue of the DataBase connection couldn't be done.
I returned the physical path to C:
Below, is the second version of my button's event code:
ReportExecutionService rs = new ReportExecutionService();
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
rs.Url = "http://MyServer/ReportServer/ReportExecution2005.asmx";
// Render arguments
byte[] result = null;
string reportPath = "/ReportLuiza/ReportContract";
string format = "PDF";
// Prepare report parameter.
ParameterValue[] parameters = new ParameterValue[1];
parameters[0] = new ParameterValue();
parameters[0].Name = "NMB_CONTRACT";
parameters[0].Value = txtNmbContractReport.Text;
string encoding;
string mimeType;
string extension;
Warning[] warnings = null;
string[] streamIDs = null;
ExecutionInfo execInfo = new ExecutionInfo();
ExecutionHeader execHeader = new ExecutionHeader();
rs.ExecutionHeaderValue = execHeader;
execInfo = rs.LoadReport(reportPath, null);
rs.SetExecutionParameters(parameters, "pt-br");
String SessionId = rs.ExecutionHeaderValue.ExecutionID;
try
{
result = rs.Render(format, null, out extension, out encoding, out mimeType, out warnings, out streamIDs);
execInfo = rs.GetExecutionInfo();
}
catch (SoapException se)
{
ShowMessage(se.Detail.OuterXml);
}
// Write the contents of the report to an pdf file.
try
{
using (FileStream stream = new FileStream(#"c:\report.pdf", FileMode.Create, FileAccess.ReadWrite))
{
stream.Write(result, 0, result.Length);
stream.Close();
}
}
catch (Exception ex)
{
ShowMessage(ex.Message);
}
For this code, I had to add a WebReference to the .asmx file mentioned in it.
When I'm debugging (on Visual Studio 2010), the code above works fine, doesn't asking for credentials (unfortunately, it doesn't prompt the option to open, save or cancel de file download. But this is another problem, no need to worry with it now) and save the file on C:.
When published, the code doesn't work. An erros says: The permission granted to user 'IIS APPPOOL\ASP.NET v4.0' are insuficient for performing this operation. So I added to the Reporting Service's users this user. When I tried again, the error is: Login failed for user IISAPPPOOL\ASP.NET v4.0. Cannot create a connection to data source 'MyDataSourceName'.
Both Report and WebSite are deployed/published on the same server with a IIS 7.5 version.
Summarizing: I need a solution where there is no credential prompt, and the user can choose where it wants to save the .pdf file.
Any help will be appreciated.
If you need more information to help me, just ask.
Thanks in advance.
One solution would be to create a new App Pool with an account that has the rights to access your restricted resources and then assign your web application to it.

copy file from local to remote server

I'm dynamically creating html files on my local system (using HTMLTEXTWRITER, then save them using streamwriter to local file system). I want to copy this file to my remote server withour user interaction, so that my users can read file. I use C#
for instance I want to copy from d:\myfile.html to mysite.com\myfile.html, how can I do it?
I have used this and it worked. may be useful
for holding path of local
rPath = "\\" & Request.UserHostAddress & "\c$\temp\"
for output file
rOutput = Session.SessionID & "_" & Format(Date.Now(), "ddMMyyhhmmss") & ".pdf"
now: report will be created at localhost\c\temp
You can't use the System.IO classes for this (unless you have access to the remote server as a network drive), but you can programmatically POST the file from the client to the remote server over HTTP using System.Net.
Here's a snippet using the WebRequest class:
WebRequest request = WebRequest.Create( url );
request.Timeout = 1000; // some appropriate value
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = 0; // set a length here
using( StreamWriter requestStream = new StreamWriter( request.GetRequestStream(), System.Text.Encoding.UTF8) ) {
// write to the stream here using requestStream.Write();
requestStream.Close();
}
More info for HTTP: http://msdn.microsoft.com/en-us/library/debx8sh9.aspx
Alternatively, you could use a protocol designed for transferring files like FTP (or something more secure) which isn't that hard to do in code.
FTP options: http://msdn.microsoft.com/en-us/library/ms229718
Is you remote server based on Windows and in the same workgroup or domain with you working machine ? If so, you can turn on the Windows File Sharing on the server. Then you can copy your file with cmd like this:
copy c:\test.txt \\mysite.com
The path "\\mysite.com" is also valid used by File.Copy in C#.
Otherwise, you need to set up a FTP environment on you server and use the FTP related API in C#.
You could set-up an FTP server and copy the files programmatically via FTP.
An example would be found here or here.
There are three ways by which you can copy the file to remote server.
Using normal file copy mode. Here you need to have access to the the webserver shared path. If the webserver is in same network as your application, then you can share the webroot and provide write access to the user who is running the application. He can then use File.Copy("source.txt", "\\Servername\SharedFolderName\target.txt").
The second approach is to use FTP to copy the file to the remote server. This MSDN example would help you on how to do this. This will work with most of the shared hosting providers.
You can use HTTP POST as noted by Tim. But this would let any user to perform the post. You may have to take care of user provisioning, authentication and authorization. IMO, keep this as last option as provisioning user and providing rights to certain path, may become cumbersome.

401 Unauthorised errors when attempting to download ASP page to file

Issue
Msxml2.ServerXMLHTTP keeps returning 401 - Unauthorised errors each time we attempt to read the contents of a file (ASP) from a web server.
Source server is running IIS6, using NTLM integrated login.
This process has been used successfully before, but only in as far as extracting XML files from external websites, not internal ones.
The proxy settings in the registry of the server on which the script is run has also been updated to bypass the website in question, but to no avail.
All paths identified in the VBScript have been checked and tested, and are correct.
User running the script has correct read/write permissions for all locations referenced in the script.
Solution needed
To identify the cause of the HTTP 401 Unauthorised messages, so that the script will work as intended.
Description
Our organisation operates an intranet, where the content is replicated to servers at each of our remote sites. This ensures these sites have continued fast access to important information, documentation and data, even in the event of losing connectivity.
We are in the middle of improving the listing and management of Forms (those pesky pieces of paper that have to be filled in for specific tasks). This involves establising a database of all our forms.
However, as the organisation hasn't been smart enough to invest in MSSQL Server instances at each site, replication of the database and accessing it from the local SQL server isn't an option.
To work around this, I have constructed a series of views (ASP pages) which display the required data. I then intend to use Msxml2.ServerXMLHTTP by VBScript, so I can read the resulting pages and save the output to a static file back on the server.
From there, the existing replication process can stream these files out to the site - with users having no idea that they're looking at a static page that just happened to be generated from database output.
Code
' Forms - Static Page Generator
' Implimented 2011-02-15 by Michael Harris
' Purpose: To download the contents of a page, and save that page to a static file.
' Target category: 1 (Contracts)
' Target Page:
' http://sharename.fpc.wa.gov.au/corporate/forms/generator/index.asp
' Target path: \\servername\sharename\corporate\forms\index.asp
' Resulting URL: http://sharename.fpc.wa.gov.au/corporate/forms/index.asp
' Remove read only
' Remove read only flag on file if present to allow editing
' If file has been set to read only by automated process, turn off read only
Const READ_ONLY = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.GetFile("\\server\sharename\corporate\forms\index.asp")
If objFile.Attributes AND READ_ONLY Then
objFile.Attributes = objFile.Attributes XOR READ_ONLY
End If
Dim webObj, strURL
Set webObj = CreateObject("Msxml2.ServerXMLHTTP")
strURL = "http://sharename.fpc.wa.gov.au/corporate/forms/generator/index.asp"
webObj.Open "GET", strURL
webObj.send
If webObj.Status=200 Then
Set objFso = CreateObject("Scripting.FileSystemObject")
Set txtFile = objFso.OpenTextFile("file:\\servername.fpc.wa.gov.au\sharename\corporate\forms\index.asp", 2, True)
txtFile.WriteLine webObj.responseText
txtFile.close
ElseIf webObj.Status >= 400 And webObj.Status <= 599 Then
MsgBox "Error Occurred : " & webObj.Status & " - " & webObj.statusText
Else
MsgBox webObj.ResponseText
End If
Replace your line:
webObj.Open "GET", strURL
With:
webObj.Open "GET", strURL, False, "username", "password"
In most cases 401 Unauthorized means you haven't supplied credentials. Also you should specifiy False to indicate you don't want async mode.
It sounds like the O.P. got this working with the correct proxy settings in the registry (http://support.microsoft.com/kb/291008 explains why proxy configuration will fix this). Newer versions of ServerXMLHTTP have a setProxy method that can be used to set the necessary proxy configuration in your code instead.
In the O.P. code above, after webObj is created, the following line of code would set up the proxy correctly:
webObj.setProxy 2, "0.0.0.0:80", "*.fpc.wa.gov.au"
ServerXMLHTTP will pass on the credentials of the user running the code if it is configured with a proxy, and if the target URL bypasses that proxy. Since you are bypassing the proxy anyway, you can make it a dummy value "0.0.0.0:80", and make sure your target url is covered by what you specify in the bypass list "*.fpc.wa.gov.au"
I would first test if you can reach your url through a normal browser on the same server X you run your code on (A). I would try then reach the url from another PC. One never used to reach that url but in the same network as server X (B).
If B works but A doesn't I would suspect that for some reason your source server (i.e. that one that serves the url) blocks server X for some reason. Check the security settings of II6 and of NTLM.
If both A and B don't work, there is something wrong more in general with your source server (i.e. it blocks everything or NTML doesn't allow you in).
If A works (B doesn't matter then), the problem has to be somewhere in your code. In that case, I would recommend fiddler. This tool can give you the HTTP requests of both your browser and your code in realtime. You can then compare both. That should give you at least a very strong hint about (if not immediately give you) the solution.

ASP.NET: System.UnauthorizedAccessException - Access to Path Denied

I have an ASP.NET web application which does the following:
Reads an Excel file.
The excel file will have an image URL located in it that points to somewhere on the internet.
The program reads each image URL and store it into a temporary folder in the web server.
The application then resizes (changes the width and height) of the image.
Finally, the application will save that image to another folder.
I am getting the following exception:
System.Net.WebException: An exception
occurred during a WebClient request.
---> System.UnauthorizedAccessException:
Access to the path
'\abcserver\target03\3111\35644\www.testing.com\web\content\images\TempStorage\tempImage.jpg'
is denied. at
System.IO.__Error.WinIOError(Int32
errorCode, String maybeFullPath) at
System.IO.FileStream.Init(String path,
FileMode mode, FileAccess access,
Int32 rights, Boolean useRights,
FileShare share, Int32 bufferSize,
FileOptions options,
SECURITY_ATTRIBUTES secAttrs, String
msgPath, Boolean bFromProxy) at
System.IO.FileStream..ctor(String
path, FileMode mode, FileAccess
access) at
System.Net.WebClient.DownloadFile(Uri
address, String fileName) --- End
of inner exception stack trace ---
at ProcessImage.GetFileFromUrl(String
imageFileUrl, String newFileName)
at
uploadexceldata.UploadExcelData(String
fileName)
foreach (DataRow dr in dt.Rows) // Reading each excel row
{
if (dr[0].ToString() != "")
{
id= "";
path = "";
manuId = "";
id= dr[0].ToString();
path = dr[1].ToString();
fileNameOnly = iProImg.GetFileNameOnly(path);
objDb.openConnection();
strSqlGroupInfo = "select ManufacturerID from manufacturers where id='" + id+ "'";
dTblManu = objDb.BuildDT(strSqlGroupInfo); // To Fill data to Datatable
objDb.closeConnection();
if (dTblManu.Rows.Count > 0)
{
manuId = dTblManu.Rows[0][0].ToString();
}
if (manuId != "")
{
tempUploadPath = "images/TempStorage/";
tempUploadPath = Server.MapPath(tempUploadPath);
if (!Directory.Exists(tempUploadPath))
{
Directory.CreateDirectory(tempUploadPath);
}
tempFilePath = tempUploadPath + "\\tempImage.jpg";
tempFilePath = tempFilePath.Replace("/", "\\");
previewPath = Server.MapPath("images/previews/" + manuId);
thumbNailPath = Server.MapPath("images/thumbnails/" + manuId);
if (!Directory.Exists(previewPath))
{
Directory.CreateDirectory(previewPath);
}
if (!Directory.Exists(thumbNailPath))
{
Directory.CreateDirectory(thumbNailPath);
}
fileNameOnly = "\\preview" + id+ ".jpg";
fileNameOnly = fileNameOnly.Replace("/", "\\");
previewPath = previewPath + fileNameOnly;
tempPartialPathP = "images\\previews\\" + manuId + fileNameOnly;
fileNameOnly = "\\thumbnail" + id+ ".jpg";
thumbNailPath = thumbNailPath + fileNameOnly;
tempPartialPathT = "images\\thumbnails\\" + manuId + fileNameOnly;
try
{
iProImg.GetFileFromUrl(path, tempFilePath);
rowCounter++;
iProImg.ReSizeImage(tempFilePath, previewPath, previewSize);
iProImg.ReSizeImage(previewPath, thumbNailPath, thumbNailSize);
}
catch (Exception ec)
{
errorRowCount++;
iLog.LogErrorToFile("uploadExcel", ec.ToString(), "path : " + path + ",tempFilePath :" + tempFilePath);
}
finally
{
if(File.Exists(tempFilePath))
{
File.Delete(tempFilePath);
}
}
} // If manuid!=""
} //if (dr[0].ToString() != "")
Does anyone have any suggestions on how to fix this exception?
Try setting the access permissions to "Full control" for the .Net user from where you are reading/saving the files.
No answers in the world solved this for me until I stumbled on the answer for myself:
UN-ENCRYPT THE FILE
You can grant full permissions to everyone on your entire hard drive, it still won't allow ASP.NET decrypt files.
If you are certain the file isn't encrypted, then you just need to add the ASPNET account to the file or folder you want to access. But make sure its not encrypted first!
In reply to what was said : "This is a remote server and the folder has full read/write permission granted.Still not working "
Make sure the .Net user / machine account user has full permissions for that Folder.
Also, add < identity /> to your config file
Make sure the ASP.NET account has read/write permission on the folder you're writing to (basic windows security).
How to:
http://www.microsoft.com/windowsxp/using/networking/security/permissions.mspx
(first 4 steps, check the boxes and click OK)
[EDIT]
You need to authenticate yourself with an account known on the remote server. You probably gave rights to the local ASP.NET account on the remote server, which won't work because that's not the user you access the folder with (from the webserver).
[/EDIT]
All of the above, plus you may need to add this tag:
<identity impersonate="true" userName="accountname" password="password" />
Read this KB article and if you are going from browser to iis to a file share, that counts as two hops and now you need to configure Kerberos Delegation. System administrators much smarter than me have tried to configure kerberos delegation and failed. Move your images or you IIS instance so that they are on the same machine.
First, narrow down your problem by temporarily granting Everyone full permission on that particular path. If it works, then you know for a fact it's a simple permission issue and you just need to figure out which acct needs proper permission. Probably the Anonymous User account (double check this setting in IIS Admin) and not the ASP.NET account. (don't forget to pull permission for Everyone)
If you need to, I believe you can use FileMon to see which account is attempting to access a particular file. Could be wrong, I haven't used this tool in a while.
One last thing... is the read-only flag set on the file? :)
I had the exact same problem today. After spending hours trying to track down what was causing the issue I found out that the permissions for the folder that was being written to were incorrect. Essentially, the folder was readonly from the perspective of the user being used to create the file.
Try doing the following for the folder in question:
Right Click on the folder and select properties
Click on the Sharing tab and then click on the Permissions button
Make sure to add whatever user is going to writing to the folder permissions to do so
Back at the properties page, click the Security tab
Make sure to add whatever user is going to write to the folder permissions to do so
Seeing as this question was asked 6 months ago, I'm assuming that you've already solved the issue...but I just thought I'd document my solution just in case it becomes useful to someone else in the future as they try to figure out how to solve this UnauthorizedAccessException.
Check that the image file (jpg) you're writing to the tempStorage has the proper permissions for the webuser account(aspnet or iis_wpg). You can set the TempStorage directory to replace permisson entries on all child objects.
Right Click TempStorage folder and select properties
Select the security tab (ensure the proper read/write/modify permissons are here)
Click the Advanced button
Check the second checkbox - Replace permissions entries on all child objects with entries shown here that apply to child objects.
Now all files that you add to the TempStoreage folder will inherit the permissions allowing you webuser account to read the jpg file.
Instead of granting permissions to ASPNET user, grant permissions to NETWORK SERVICE user. Modify permissions within the folder should be enough, no need to give full permissions (no reason to give more permissions than needed)
for more details read forum : http://forums.asp.net/t/1013434.aspx/1
the error is pretty obvious there Access to the path 'bin\myprojname.pdb\' is denied. the user the web console process is running under (not the user you created in the webconsole, the actual windows user), most likely "Network Service" doesnt have permissions to that folder.
You can either - Right click on that folder, goto permissions and add the "Network Service" user - Right click on that folder, goto permissions and add the "Everyone" user
that should fix that problem.

Resources