|
Home > Archive > IIS Server Security > October 2004 > Restrict FileSystemObject to it's virtual dir
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Restrict FileSystemObject to it's virtual dir
|
|
|
| Hi everybody,
i've to configure on a single win2003 machine a lot dinamic web site.
I'd like to protect each site from interference of other sites scripts that
uses, for example, filesystemobject method.
In other words, i dont want asp script using FSO of a site can access,
modify or delete files on other sites.
Is there a way to restrict FSO to it's virtual directory?
tnx to everyone

| |
| Tom Kaminski [MVP] 2004-08-06, 7:50 am |
| "Dallo" <dallo.s@libero.it> wrote in message
news:cevhq9$pg6$1@carabinieri.cs.interbusiness.it...
> Hi everybody,
> i've to configure on a single win2003 machine a lot dinamic web site.
> I'd like to protect each site from interference of other sites scripts
that
> uses, for example, filesystemobject method.
> In other words, i dont want asp script using FSO of a site can access,
> modify or delete files on other sites.
> Is there a way to restrict FSO to it's virtual directory?
Make sure each site uses a different IUSR account.
--
Tom Kaminski IIS MVP
http://www.microsoft.com/windowsser...ty/centers/iis/
http://mvp.support.microsoft.com/
http://www.iisfaq.com/
http://www.iistoolshed.com/ - tools, scripts, and utilities for running IIS
http://www.tryiis.com
| |
| Adam Hammouda 2004-08-18, 5:57 pm |
| A long while back, I wrote this piece of code you may find useful;
It was supposed to provide a custom "FileSystemObject" implementation which
would not allow users to break out of their root directory in a web hosting
environment.
It's been so long I can't really recall how I did things exactly, but if I
had to guess:
-Disable native FileSystemObject support [through the registry, I think?]
-Then register the .NET assembly with IIS through the command line ["regasm
/tlb /codebase [assemblypath]" maybe ?]
I had imported the ASPTypeLibrary and Scripting dll's, which must be
referenced when compiling the project.
I also believe the entire FileSystemObject API is implemented below in the
encapsulating classes.
your users would then instantiate the "FileSystemObject" with a:
Server.CreateObject("Custom.FileSystemObject") instead of
....("Scripting.FileSystemObject")
If you find it helpful, do with it what you please 
using System;
using System.Collections;
using System.IO;
using System.Runtime.InteropServices;
using ASPTypeLibrary; // COM Interoped ASP Classes.
using Scripting; // COM Interoped Scripting Classes.
namespace Custom {
/**
* FileSystemObject - File Implementation.
*/
public sealed class File : Scripting.File {
internal FileSystemObject fso;
internal Scripting.File file;
public File(FileSystemObject fso, Scripting.File file) {
this.fso = fso;
this.file = file;
}
public FileAttribute Attributes {
get {
return file.Attributes;
} set {
file.Attributes = value;
}
}
public DateTime DateCreated {
get {
return file.DateCreated;
}
}
public DateTime DateLastAccessed {
get {
return file.DateLastAccessed;
}
}
public DateTime DateLastModified {
get {
return file.DateLastModified;
}
}
public Drive Drive {
get {
throw new NotSupportedException();
}
}
public string Name {
get {
return file.Name;
} set {
file.Name = value;
}
}
public Scripting.Folder ParentFolder {
get {
return new Folder(fso, file.ParentFolder);
}
}
public string Path {
get {
return file.Path;
}
}
public string ShortName {
get {
return file.ShortName;
}
}
public string ShortPath {
get {
return file.ShortPath;
}
}
public object Size {
get {
return file.Size;
}
}
public string Type {
get {
return file.Type;
}
}
/* Added for backwards compatibility. */
public void Copy(string destination) {
fso.CopyFile(Path, destination);
}
public void Copy(string destination, bool overwrite) {
fso.CopyFile(Path, destination, overwrite);
}
/* Added for backwards compatibility. */
public void Delete() {
fso.DeleteFile(Path);
}
public void Delete(bool force) {
fso.DeleteFile(Path, force);
}
public void Move(string destination) {
fso.MoveFile(Path, destination);
}
/* Added for backwards compatibility. */
public TextStream OpenAsTextStream() {
return fso.OpenTextFile(Path);
}
/* Added for backwards compatibility. */
public TextStream OpenAsTextStream(short mode) {
return fso.OpenTextFile(Path, mode);
}
/* Added for backwards compatibility. */
public TextStream OpenAsTextStream(short mode, short format) {
return fso.OpenTextFile(Path, mode, false, format);
}
public TextStream OpenAsTextStream(IOMode mode, Tristate format) {
return fso.OpenTextFile(Path, mode, false, format);
}
}
/**
* FileSystemObject - Files Implementation.
*/
public sealed class Files : Scripting.Files {
internal FileSystemObject fso;
internal Scripting.Files files;
public Files(FileSystemObject fso, Scripting.Files files) {
this.fso = fso;
this.files = files;
}
public int Count {
get {
return files.Count;
}
}
public IEnumerator GetEnumerator() {
return files.GetEnumerator();
}
public Scripting.File this[object id] {
get {
return new File(fso, files[id]);
}
}
}
/**
* FileSystemObject - Folder Implementation.
*/
public sealed class Folder : Scripting.Folder {
internal FileSystemObject fso;
internal Scripting.Folder dir;
public Folder(FileSystemObject fso, Scripting.Folder dir) {
this.fso = fso;
this.dir = dir;
}
public FileAttribute Attributes {
get {
return dir.Attributes;
} set {
dir.Attributes = value;
}
}
public DateTime DateCreated {
get {
return dir.DateCreated;
}
}
public DateTime DateLastAccessed {
get {
return dir.DateLastAccessed;
}
}
public DateTime DateLastModified {
get {
return dir.DateLastModified;
}
}
public Drive Drive {
get {
throw new NotSupportedException();
}
}
public Scripting.Files Files {
get {
return new Files(fso, dir.Files);
}
}
public bool IsRootFolder {
get {
return dir.IsRootFolder;
}
}
public string Name {
get {
return dir.Name;
} set {
dir.Name = value;
}
}
public Scripting.Folder ParentFolder {
get {
Folder folder = null;
try {
DirectoryInfo parent = new DirectoryInfo(Path);
parent = new
DirectoryInfo(fso.GetDirectoryPath(parent.Parent.FullName, true));
folder = new Folder(fso, dir.ParentFolder);
} catch {
folder = null;
}
return folder;
}
}
public string Path {
get {
return dir.Path;
}
}
public string ShortName {
get {
return dir.ShortName;
}
}
public string ShortPath {
get {
return dir.ShortPath;
}
}
public object Size {
get {
return dir.Size;
}
}
public Scripting.Folders SubFolders {
get {
return new Folders(fso, dir.SubFolders);
}
}
public string Type {
get {
return dir.Type;
}
}
/* Added for backwards compatibility. */
public void Copy(string destination) {
fso.CopyFolder(Path, destination);
}
public void Copy(string destination, bool overwrite) {
fso.CopyFolder(Path, destination, overwrite);
}
/* Added for backwards compatibility. */
public void Delete() {
fso.DeleteFolder(Path);
}
public void Delete(bool force) {
fso.DeleteFolder(Path, force);
}
public void Move(string destination) {
fso.MoveFolder(Path, destination);
}
/* Added for backwards compatibility. */
public TextStream CreateTextFile(string filename) {
return fso.CreateTextFile(System.IO.Path.Combine(Path, filename));
}
/* Added for backwards compatibility. */
public TextStream CreateTextFile(string filename, bool overwrite) {
return fso.CreateTextFile(System.IO.Path.Combine(Path, filename),
overwrite);
}
public TextStream CreateTextFile(string filename, bool overwrite, bool
unicode) {
//FileInfo file = new FileInfo(fso.GetFilePath(filename));
//return dir.CreateTextFile(file.FullName, overwrite, unicode);
return fso.CreateTextFile(System.IO.Path.Combine(Path, filename),
overwrite, unicode);
}
}
/**
* FileSystemObject - Folders Implementation.
*/
public sealed class Folders : Scripting.Folders {
internal FileSystemObject fso;
internal Scripting.Folders folders;
public Folders(FileSystemObject fso, Scripting.Folders folders) {
this.fso = fso;
this.folders = folders;
}
public Scripting.Folder Add(string filename) {
throw new NotSupportedException();
}
public int Count {
get {
return folders.Count;
}
}
public IEnumerator GetEnumerator() {
return folders.GetEnumerator();
}
public Scripting.Folder this[object id] {
get {
return new Folder(fso, folders[id]);
}
}
}
/**
* FileSystemObject - FileSystemObject Implementation.
*/
public sealed class FileSystemObject : Scripting.FileSystemObject {
private Scripting.FileSystemObject FSO;
private ScriptingContext Context;
private Request Request;
private Server Server;
private DirectoryInfo RootDirectory;
public FileSystemObject() : base() {
Request = null;
Context = null;
Server = null;
RootDirectory = null;
// Initialize internal Scripting.FileSystemObject.
FSO = new Scripting.FileSystemObject();
}
/**
* Entrypoint function called by IIS with the current ScriptingContext.
*/
public void onStartPage(ScriptingContext Context) {
try {
this.Context = Context;
if(Context == null) {
throw new ArgumentNullException("Context");
}
this.Request = Context.Request; //
(RequestClass)Marshal.CreateWrapperOfType(Request, typeof(RequestClass));
if(Request == null) {
throw new ArgumentNullException("Request");
}
this.Server = Context.Server;
if(Server == null) {
throw new ArgumentNullException("Server");
}
string path = String.Empty;
IStringList list = (IStringList)Request.ServerVariables["URL"];
if(list != null && list.Count == 1) {
path = list[1].ToString(); // Reminder: VB/ASP Arrays are not
zero-based.
} else {
throw new ArgumentNullException("List");
}
if(path == null || path.Length == 0) {
throw new ArgumentNullException("Path");
}
while(path.StartsWith("/")) {
path = path.Substring(1, path.Length - 1);
}
if(path.IndexOf("/") <= 0) {
throw new Exception();
}
path = "/" + path.Substring(0, path.IndexOf("/")) + "/";
RootDirectory = new DirectoryInfo(Server.MapPath(path));
if(RootDirectory == null || !(RootDirectory.Exists)) {
throw new ArgumentNullException("RootDirectory");
}
} catch {
throw new Exception("Unable to initialize Custom.FileSystemObject");
}
}
public Drives Drives {
get {
throw new NotSupportedException();
}
}
public string BuildPath(string path1, string path2) {
return FSO.BuildPath(path1, path2);
}
/* Added for backwards compatibility. */
public void CopyFile(string source, string destination) {
CopyFile(source, destination, true);
}
public void CopyFile(string source, string destination, bool overwrite)
{
CheckInitialized();
FileInfo srcFile = new FileInfo(GetFilePath(source, true));
srcFile.CopyTo(destination, overwrite);
}
/* Added for backwards compatibility. */
public void CopyFolder(string source, string destination) {
CopyFolder(source, destination, true);
}
public void CopyFolder(string source, string destination, bool
overwrite) {
CheckInitialized();
DirectoryInfo srcDir = new DirectoryInfo(GetDirectoryPath(source,
true));
InternalDirectoryCopy(srcDir, GetDirectoryPath(destination),
overwrite);
}
public Scripting.Folder CreateFolder(string filename) {
CheckInitialized();
DirectoryInfo dir = new DirectoryInfo(GetDirectoryPath(filename)
);
return new Folder(this, FSO.CreateFolder(dir.FullName));
}
/* Added for backwards compatibility. */
public TextStream CreateTextFile(string filename) {
return CreateTextFile(filename, false);
}
/* Added for backwards compatibility. */
public TextStream CreateTextFile(string filename, bool overwrite) {
return CreateTextFile(filename, overwrite, false);
}
public TextStream CreateTextFile(string filename, bool overwrite, bool
unicode) {
CheckInitialized();
FileInfo file = new FileInfo(GetFilePath(filename));
return FSO.CreateTextFile(file.FullName, overwrite, unicode);
}
/* Added for backwards compatibility. */
public void DeleteFile(string filename) {
DeleteFile(filename, true);
}
public void DeleteFile(string filename, bool force) {
CheckInitialized();
FileInfo file = new FileInfo(GetFilePath(filename, true));
file.Delete();
}
/* Added for backwards compatibility. */
public void DeleteFolder(string filename) {
DeleteFolder(filename, true);
}
public void DeleteFolder(string filename, bool force) {
CheckInitialized();
DirectoryInfo dir = new DirectoryInfo(GetDirectoryPath(filename,
true));
dir.Delete(true);
}
public bool DriveExists(string path) {
throw new NotSupportedException();
}
public bool FileExists(string filename) {
CheckInitialized();
FileInfo file = new FileInfo(GetFilePath(filename));
return file.Exists;
}
public bool FolderExists(string filename) {
CheckInitialized();
DirectoryInfo dir = new DirectoryInfo(GetDirectoryPath(filename)
);
return dir.Exists;
}
public string GetAbsolutePathName(string path) {
return FSO.GetAbsolutePathName(path);
}
public string GetBaseName(string path) {
return FSO.GetBaseName(path);
}
public Drive GetDrive(string path) {
throw new NotSupportedException();
}
public string GetDriveName(string path) {
throw new NotSupportedException();
}
public string GetExtensionName(string path) {
return FSO.GetExtensionName(path);
}
public Scripting.File GetFile(string filename) {
CheckInitialized();
FileInfo file = new FileInfo(GetFilePath(filename, true));
return new File(this, FSO.GetFile(file.FullName));
}
public string GetFileVersion(string path) {
return FSO.GetFileVersion(path);
}
public string GetFileName(string path) {
return FSO.GetFileName(path);
}
public Scripting.Folder GetFolder(string filename) {
CheckInitialized();
DirectoryInfo dir = new DirectoryInfo(GetDirectoryPath(filename,
true));
return new Folder(this, FSO.GetFolder(dir.FullName));
}
public string GetParentFolderName(string path) {
return FSO.GetParentFolderName(path);
}
public Scripting.Folder GetSpecialFolder(SpecialFolderConst
specialFolder) {
throw new NotSupportedException();
}
public TextStream GetStandardStream(StandardStreamTypes streamType, bool
unicode) {
throw new NotSupportedException();
}
public string GetTempName() {
return FSO.GetTempName();
}
public void MoveFile(string source, string destination) {
CheckInitialized();
FileInfo srcFile = new FileInfo(GetFilePath(source, true));
srcFile.MoveTo(GetFilePath(destination));
}
public void MoveFolder(string source, string destination) {
CheckInitialized();
DirectoryInfo srcDir = new DirectoryInfo(GetDirectoryPath(source,
true));
srcDir.MoveTo(GetDirectoryPath(destination));
}
/* Added for backwards compatibility. */
public TextStream OpenTextFile(string filename) {
return OpenTextFile(filename, 1);
}
/* Added for backwards compatibility. */
public TextStream OpenTextFile(string filename, short mode) {
return OpenTextFile(filename, mode, false);
}
/* Added for backwards compatibility. */
public TextStream OpenTextFile(string filename, short mode, bool create)
{
return OpenTextFile(filename, mode, create, 0);
}
/* Added for backwards compatibility. */
public TextStream OpenTextFile(string filename, short smode, bool
create, short sformat) {
IOMode mode = IOMode.ForReading;
Tristate format = Tristate.TristateFalse;
if(smode == 1) {
mode = IOMode.ForReading;
} else if(smode == 2) {
mode = IOMode.ForWriting;
} else if(smode == 8) {
mode = IOMode.ForAppending;
}
if(sformat == -2) {
format = Tristate.TristateUseDefault;
} else if(sformat == -1) {
format = Tristate.TristateTrue;
} else if(sformat == 0) {
format = Tristate.TristateFalse;
}
return OpenTextFile(filename, mode, create, format);
}
public TextStream OpenTextFile(string filename, IOMode mode, bool
create, Tristate format) {
CheckInitialized();
FileInfo file = new FileInfo(GetFilePath(filename));
return FSO.OpenTextFile(file.FullName, mode, create, format);
}
// Internal Operations.
internal string GetFilePath(string relpath) {
return GetFilePath(relpath, false);
}
internal string GetFilePath(string relpath, bool checkExists) {
CheckInitialized();
string path = null;
try {
FileInfo file = (Path.IsPathRooted(relpath)) ? new FileInfo(relpath)
: new FileInfo(Path.Combine(RootDirectory.FullName, relpath));
if(file == null || (checkExists && !(file.Exists))) {
throw new ArgumentNullException("File");
}
if(!(file.Directory.FullName.StartsWith(RootDirectory.FullName))) {
throw new Exception("Error: Hacking attempt");
}
path = file.FullName;
} catch {
throw new Exception("Custom.FileSystemObject Path Error");
}
return path;
}
internal string GetDirectoryPath(string relpath) {
return GetDirectoryPath(relpath, false);
}
internal string GetDirectoryPath(string relpath, bool checkExists) {
CheckInitialized();
string path = null;
try {
DirectoryInfo dir = (Path.IsPathRooted(relpath)) ? new
DirectoryInfo(relpath) : new
DirectoryInfo(Path.Combine(RootDirectory.FullName, relpath));
if(dir == null || (checkExists && !(dir.Exists))) {
throw new ArgumentNullException("Dir");
}
if(!(dir.FullName.StartsWith(RootDirectory.FullName))) {
throw new Exception("Error: Hacking attempt");
}
path = dir.FullName;
} catch {
throw new Exception("Custom.FileSystemObject Path Error");
}
return path;
}
// Private Helper Operations.
private void CheckInitialized() {
if(!((FSO != null && Request != null && Context != null && Server !=
null && RootDirectory != null && RootDirectory.Exists))) {
throw new Exception("Custom.FileSystemObject not initialized.");
}
}
private void InternalDirectoryCopy(DirectoryInfo source, string
destination, bool overwrite) {
if(source == null) {
return;
}
foreach(FileSystemInfo fso in source.GetFileSystemInfos()) {
string destName = Path.Combine(source.FullName, fso.Name);
if(fso is FileInfo) {
System.IO.File.Copy(fso.FullName, destName, overwrite);
} else if(fso is DirectoryInfo) {
Directory.CreateDirectory(destName);
InternalDirectoryCopy((DirectoryInfo)fso
, destName, overwrite);
}
}
}
}
}
| |
| FKeller 2004-10-25, 8:47 pm |
| Hello Dallo
I wonder if you got it to work with the desired security?
I did see that there is a very ingenious ASP-script going around. Even on
big providers you can go with it to all drives, even C:\WINNT and \SYSTEM32
and read, change, delete or upload whatever you want. So as I did see even
big providers have not the needed security and are in danger. How did you
implement the security that users cannot go out of there root? Hackers event
use file upload possibilities in websites to upload the tool and use it then.
Thanks for help,
Fritz Keller
"Dallo" wrote:
> Hi everybody,
> i've to configure on a single win2003 machine a lot dinamic web site.
> I'd like to protect each site from interference of other sites scripts that
> uses, for example, filesystemobject method.
> In other words, i dont want asp script using FSO of a site can access,
> modify or delete files on other sites.
> Is there a way to restrict FSO to it's virtual directory?
>
>
> tnx to everyone
> 
>
>
>
| |
| FKeller 2004-10-25, 8:47 pm |
| Hello Dallo
I wonder if you got it to work with the desired security?
I did see that there is a very ingenious ASP-script going around. Even on
big providers you can go with it to all drives, even C:\WINNT and \SYSTEM32
and read, change, delete or upload whatever you want. So as I did see even
big providers have not the needed security and are in danger. How did you
implement the security that users cannot go out of there root? Hackers event
use file upload possibilities in websites to upload the tool and use it then.
Thanks for help,
Fritz Keller
"Dallo" wrote:
> Hi everybody,
> i've to configure on a single win2003 machine a lot dinamic web site.
> I'd like to protect each site from interference of other sites scripts that
> uses, for example, filesystemobject method.
> In other words, i dont want asp script using FSO of a site can access,
> modify or delete files on other sites.
> Is there a way to restrict FSO to it's virtual directory?
>
>
> tnx to everyone
> 
>
>
>
| |
| David Wang [Msft] 2004-10-28, 2:47 am |
| Scripting.FileSystemObject does not support any such policy. Web Servers
implement such "rooted" policies, but it only applies to the Web Server and
not scripts run by the Web Server (same reasoning).
You will have to rely on NTFS ACLs to prevent mingling between apps.
In general, "app isolation" is done through NTFS ACLs (i.e. if directory1 is
ACLd only to user1 and directory2 is ACLd only to user2, an app running as
user2 can only access directory2 but not directory1).
You can do this on IIS6 in a couple of ways:
1. Creating an Application Pool for each application, with a unique AppPool
Identity and Anonymous User/Authentication. This effectively binds code run
by that AppPool to the configured AppPool/Anonymous identity(s).
2. Use unique AnonymousUser identity for every application for isolation.
This has a weakness in that if the script code can call "RevertToSelf", it
can gain access to the process identity, which by default already have
access to everything (you're relying on impersonation as isolation).
If you allow users to upload and run arbitrary code on the server, then you
must use Application Pools with unique AppPool Identity to isolate users
from each other. The users must execute code in separate processes or else
they'd share something in common.
--
//David
IIS
This posting is provided "AS IS" with no warranties, and confers no rights.
//
"FKeller" <Fritz Keller@discussions.microsoft.com> wrote in message
news:A96D650B-CB7F-4D7D-A2B8-AC33BA528364@microsoft.com...
Hello Dallo
I wonder if you got it to work with the desired security?
I did see that there is a very ingenious ASP-script going around. Even on
big providers you can go with it to all drives, even C:\WINNT and \SYSTEM32
and read, change, delete or upload whatever you want. So as I did see even
big providers have not the needed security and are in danger. How did you
implement the security that users cannot go out of there root? Hackers event
use file upload possibilities in websites to upload the tool and use it
then.
Thanks for help,
Fritz Keller
"Dallo" wrote:
> Hi everybody,
> i've to configure on a single win2003 machine a lot dinamic web site.
> I'd like to protect each site from interference of other sites scripts
that
> uses, for example, filesystemobject method.
> In other words, i dont want asp script using FSO of a site can access,
> modify or delete files on other sites.
> Is there a way to restrict FSO to it's virtual directory?
>
>
> tnx to everyone
> 
>
>
>
|
|
|
|
|