Does Path.Combine ever make network calls in .net? - c#

Someone I know is claiming that it does and I am decompiling System.IO and looking in the Path class and I can't see it making networking calls. The only suspect is in NormalizePath, where it calls to PathHelper which has calls into Win32Native.GetFullPathName. I don't know what that does.
They are also claiming that System.Uri makes networking calls when created, which I find very incredible. I just can't believe that it would do that given how unbelievably slow that would be and how intrinsic these methods are.
Can anyone enlighten me?
Edit:
It turns out that Path.Combine(p) doesn't ever call the network but Path.GetFullName(p) can. In the scenario where you have a UNC path with a short filename ("\\server\abcdef~1.txt" for example) it will actually call out to the network and try to expand the path, which blows my mind frankly.

No, the Path.Combine method simply performs the required string manipulation to generate a legal path string, given the path separator. It explicitly does not check to see if you've given it a valid path, or a valid file name, or whatever.
The reference source code for .NET 4 is available, if you're curious, and you can see that the work is done entirely in managed code, no native method calls, and is basically:
return path1 + (path1.EndsWidth("\") ? "" : "\") + path2;
(A lot more robust and flexible, of course, but that's the idea.)
Similarly, the constructors for the Uri class do mostly string parsing (though orders of magnitude more complex than the Path stuff) but still, no network calls that I can see.
You could also check this yourself by running a packet capture utility such as Wireshark while executing such commands in a C# app.

Related

Safe code execution on server side API with Roslyn

To give my users more flexibility and to let them write their own expressions, I want to allow them to write very simple C# statements in a text field that are executed on server side to do some custom calculations.
I am archiving this with Roslyn.
A good example to start for me can be found here.
I let users inject code inside an evaluation function, like this:
string codeToCompile = #"
using System;
using System.Collections.Generic;
namespace Evaluator
{
public class Evaluator
{
public string Eval()
{
" + {POTENTIALLY_DANGEROUS_CODE_GOES_HERE} + #"
}
}
}";
You can see that the injected code is always inside an Eval-Function and should return a string in the end.
The user can decide how this string is calculated.
I am now thinking of security, because I do not have any control of the injected code.
Actually my users should only be able to:
Use mathematical expressions
Primitive variables
if statements
So an example injected code could look like this:
int a = 5;
int b = 10;
if(a < b)
{
return "a is smaller";
}
else
{
return "a is bigger or equal";
}
You can see in the sample code above, that the namespace is limited to "System" and "System.Collections.Generic", so a lot of stuff wont be possible anymore (like reading something from the file system of the server and outputting this information as a string)
I also replace all occurences of loops, so expressions like while, for, foreach etc... are removed from the string.
But I am still pretty unsure if this solution is secure.
What could a potential attacker still do now? (Especially with the options of the two provided namespaces)
Is there any best-practice what I could do in this case, to prevent attacks?
Depending on your needs, this is very hard to get right. Very hard. "If you have to ask how to do it you might be over your head" hard. Some fun things to consider:
Just because you limit the namespaces at the top of the file doesn't mean somebody can't explicitly qualify to something in their code snippet to a different namespace. So what's important is you have to walk the entire code to see if there's uses of any other types. I can't tell if your explicit list of things you're allowing implicitly disallows all method calls or object creation.
Be careful with assuming anything in System is safe. Consider System.Activator, which lets you call CreateInstance and pass in the string name of another type to create it. That type alone lets you bypass any other checks you might do. And that was just the first one that jumped out when I pulled up the docs in the System namespace alphabetically!
...and of course don't just block System.Activator specifically. Any time you update which framework people are writing code against, there might be new types that are problematic.
Also consider your types of potential security attacks: even if you can't write files, can you still leak information from your server (like the username or machine name) that might allow the user to break into your system some other way. Or they just write an infinite loop which consumes server resources. You mentioned that you'll remove loops, but don't forget things like goto, or just writing some sort of recursive function that does a stack overflow.
I'm not going to say "just do X and it's safe", because I don't even trust myself to write that. But:
Use your OS to help you isolate: run this in a separate process with less or no permissions, etc. If you can do a separate VM/container, great. The more you can isolate here the better.
If you're going to do code inspection, don't reject patterns that you know are bad; instead write code that only accepts patterns that you know are "safe". And that might result in a lot of work to opt in silly things, but the alternative requires you to enumerate all that is bad.
Maybe you do not need C# code? There are multiple options to integrate a script language. They will be interpreted and slower but that is usually not an issue.
I can recommend https://github.com/sebastienros/jint for JavaScript for example. (I'm not affiliated with the project) It has good interoparability with the hosting C# code. It also has built-in safety guards for "resource" attacks like endless loops or excessive memory consumption.
Small word of caution: Be careful what kind of .net interoparability you allow or you might open up a security risk even with interpreted code.

Path traversal warning when using Path.Combine

I am currently using NewtonJSON to load some UI data from a JSON file. However, there is an warning says I have path traversal.
Here is the situation:
Any idea to remove this security vulnerability?
The path traversal exploit is possible when a path provided by a user or other untrusted source is combined, without checking, with a parent path. The problem is that there are "path traversal" components of paths that enable navigation out of the parent folder.
For example, if you were to combine the following two paths, an absolute path and a relative one:
Base/absolute path: C:\WebData
Relative/user path: ..\windows\system32\
Then this would yield:
C:\windows\system32\
As you can imagine, letting someone read or write this directory, which is not the intended WebData directory, could be a huge problem, as it could lead to someone learning information about your system or placing exploits that compromise the system, giving control of it to malicious actors.
You can read more about this exploit.
To deal with this vulnerability properly, you need to ensure that the relative path combined with the parent path is safe. Here are some ways to ensure this:
The relative path comes from a known trusted source, such as a vetted, internal list.
The relative path has previously been checked and was stored/maintained in a way that ensures it can be distinguished from untrusted paths, and could not be modified by a user or untrusted agent in the meantime. For example, keeping the path in a string is a bad idea. Instead, you would do something like create a TrustedPath class that code could only gain an instance of by, in fact, running code that checked that the path is safe.
The resulting path is checked after combination to ensure it is in the correct location.
You could do the last item like so (all of the below):
(As good practice to avoid unnecessary exceptions), use Path. GetInvalidFileNameChars() to check the (untrusted) relative path for invalid characters.
Perform Path.Combine() as you have done.
Ensure the resulting path is still within the original, parent path. This can be done by simply ensuring the resulting path starts with the parent path, but there may be issues with that. So consider an answer like this or other code that ensures the resulting path is truly a descendant of the desired folder.
Once you have done all this, if the "path traversal" warning is still showing, you can use the menu options in your code quality/security checking tool to annotate this instance of path traversal as safe. You may also want to put a comment with notes explaining why you marked it as safe, which could conceivably include a link to this SO question or one of its answers.
Note 1
Be careful about reusing a relative path that you have proven combines okay with a specific absolute path. Consider the following:
Base/absolute path: C:\WebData\FormElements\SuperForm\windows\
Relative/user path: ..\windows\
These two paths would combine safely, however this has not proven that the relative path is always safe to use with any absolute path.
Note 2
Be wary how you go about this. Assuming that relative path traversal always starts with ..\ is a mistake. The following is a valid relative path: folder\..\..\wheeeWeGotOut.
Note 3
Another answer proposes that safety can be guaranteed by simply removing invalid characters, and disallowing paths that contain .. or :. This is problematic for multiple reasons:
Files in many non-Windows file systems such as HFS or linux can legitimately have these characters. For example, a:filename and another..filename are perfectly fine (I just tested them). Restricting those characters limits what users can do.
Trying to improve the filtering to allow legitimate use-cases through is not a good idea. How do you know that you've written this code correctly and didn't miss an edge-case?
But most of all: what if there is an accidental symlink inside of the user's allowed path that points to a file elsewhere in the filesystem? What if the user is able to write a file that can function as a symlink, or has another exploit to cause such a file to be written or copied? The path exploit may not stand alone. It is often a combination of small exploits that leads to large exploits (each next one intersecting with or escalating the previous one). The only safe technique to ensure a file or directory is in the proper location is to, after all other filtering and passes and combining have been done, to check that the result is still within the expected location or is a direct descendant (paying attention to symlinks).
Regarding hard links—that is another matter. Good luck with that one. Don't make hard links. It's very hard to tell that a hard-link even exists, because it's a low-level modification. Read up on it if you're interested.
A secure way of using Path.Combine can be the next:
public string PathCombine(string path1, string path2)
{
if (path2.Contains("..")) return null;
if (path2.Contains(":")) return null;
string result = Path.Combine(path1, path2);
return (result.Equals(path2) ? null : result);
}
Note that this is only an example, not allowed strings check can be improved.
As additional information you can take a look here.
If you want to get more information about how this problem can be exploited I recommend you to read the OWASP documentation.
The fact of check if the result is like the second parameter is due to the behavior of the CombineInternal function that you can check here:
private static string CombineInternal(string first, string second)
{
if (string.IsNullOrEmpty(first))
return second;
if (string.IsNullOrEmpty(second))
return first;
if (IsPathRooted(second.AsSpan()))
return second;
return JoinInternal(first.AsSpan(), second.AsSpan());
}
As you can see, if the second variable IsPathRooted, the result is going to be it, and this is a common way to explode this without the need of use '..' characters, think on this example:
Your web is on c:\wwwroot\web1\public\index.html
if you pass as second parameter c:\wwwroot\web1\private\secret.conf you are going to be able to access this file.

Path strings too long [duplicate]

How can I use (to avoid PathTooLongException):
System.IO.FileInfo
with paths bigger than 260 chars?
Are there similar classes/methods that return the same result of FileInfo class?
From what I know it is not easily possible. While it is possible to use workaround for streams as phoenix mentioned, it is not possible for file names handling. Internally every class that works with file names perform checks for long file names.
You can instantiate FileInfo and fill private memebers using reflection (however this is not recommended) and get FileInfo pointing to file with long path. But when you try to use this object you will still receive PathTooLongException exceptions, because for example, Path class (used heavily by FileInfo) checks for long path on every method call.
So, there is only one right way to get problem free long path support - implement your own set of classes that will mimic FileInfo behavior. It is not very complex (only security maybe), but time-consuming.
Update: Here even two ready solutions for this problem: AlpfaFS and Zeta Long Paths
Here at work we deal with long paths quite frequently, and we therefore had to basically roll our own System.IO to do it. Well not really, but we rewrote File, Directory, FileInfo, DirectoryInfo and Path just to name a few. The basic premise is that it's all possible from a Win32 API perspective, so all you really need to do at the end of the day is invoke the Unicode versions of the Win32 API functions, and then you're good. It's alot of work, and can be a pain in the ass at times, but there's really no better way to do it.
There's a great library on Microsoft TechNet for overcoming the long filenames problem, it's called
Delimon.Win32.I​O Library (V4.0) and it has its own versions of key methods from System.IO
For example, you would replace:
System.IO.Directory.GetFiles
with
Delimon.Win32.IO.Directory.GetFiles
which will let you handle long files and folders.
From the website:
Delimon.Win32.IO replaces basic file functions of System.IO and
supports File & Folder names up to up to 32,767 Characters.
This Library is written on .NET Framework 4.0 and can be used either
on x86 & x64 systems. The File & Folder limitations of the standard
System.IO namespace can work with files that have 260 characters in a
filename and 240 characters in a folder name (MAX_PATH is usually
configured as 260 characters). Typically you run into the
System.IO.PathTooLongException Error with the Standard .NET Library.
I only needed to use the FullName property but was also receiving the PathTooLongException.
Using reflection to extract the FullPath value was enough to solve my problem:
private static string GetFullPath(FileInfo src)
{
return (string)src.GetType()
.GetField("FullPath", BindingFlags.Instance|BindingFlags.NonPublic)
.GetValue(src);
}

C# correct Syntax for Networkconnection with adminshare

I have following, simple, problem because I don't have the luxury to actually debug properly right now. This question might even seem dumb to most but I am still unexperienced when it comes to coding.
I am supposed to write a simple console application that connects to a few different clients (and one server) and replaces some files on the C Drive with Adminrights(If I understood it right that's what the C$ is for?). But because something had gone wrong in the past there are actually a few occurences where the filepath differs from the standard, so I have to check with Dictionary.Exists(path) first, to not make it any longer, what is the correct Syntax to properly connect to said folder?
I was thinking about:
Directory.Exists(#"192.168.xxx.xxx\C$\Program Files\...")
I also tried to test it via localhost, but that didn't seem to work because either I am doing it wrong or it is just not intended to work with it?
Well, figured it out now thanks to a tip from Alex K.. Didn't know that this kind of format was called UNC and did some research about it (a bunch of different sites), could easily test it on my own computer like that:
bool test = Directory.Exists(#"\\192.168.10.102\C$\Program Files")
Also works with the domainname "localhost" instead of "192.168.10.102". Both resulted in true.

represent Memory Stream as a physical file

I've ran into a bit of a stupid problem today:
In my project I have to use a library (that I can't replace), he problem is that I'm using MemoryStream instead of frequently saving to the HDD (because there are many files, and they are small in size, so it's perfect for MemoryStream). The problem is that the library API is built around filesystem access - and one of the functions accepts only direct path to file.
How can I still send a string (path) to the method, which makes a new FileStream without actually touch the hard-drive?
For example "\MEMORY\myfile.bin"?
Well - that's thought.
Basically, you have three possible solutions:
You can use a reflector to modify the library given.
You can inspect the appropriate method, and then, by using some reflection magic you might be able to modify the object at runtime (very un-recommended)
You can play around with system calls and API - and by going into low-level ring0 assembly modify kernal.dll to referrer I/O queries from your path to the memory. (maybe that's possible without ring0 access - I am not sure).
Obviously, the most recommended is to use a reflector to modify the library given. otherwise, I can't see a solution for you.
In respond to the first comment, you can:
use RAMDrive (a program which allocates small chunks of the system memory and show it as partition)
If the file must exist on the disk (and only disk paths are accepted), then the main option is a virtual filesystem which lets you expose custom data as a filesystem. There exist several options, such as now-dead Dokan, our Solid File System OS Edition and Callback File System (see description of our Virtual Storage product line) and maybe Pismo File Mount would work (never looked at it closely).
It all depends on how the library is constructed.
If it's a 100% managed library that uses a FileStream, you are probably stuck.
If it takes the provided filename and call a native WIN32 CreateFile function, it's possible to give it something else than a file such as a named pipe.
To test quickly if it's possible, pass #"\\.\pipe\random_name" to the method: if it responds by saying explicitely that it can't open pipes and filenames begining with \\.\, well, sorry. ON the other hand, if it says it can't find the file, you have a chance to make it work.
You can then create a NamedPipeServerStream and use the same name for your library method call prepended with \\.\pipe\.
You can't "represent" it as a file, but you could "convert" it to a file using a StreamWriter class.

Categories