Skip to content

Commit

Permalink
Merge pull request #32 from punk-security/add-cross-platform-SMB
Browse files Browse the repository at this point in the history
Add cross platform smb
  • Loading branch information
SimonGurney authored Feb 22, 2022
2 parents c2d7336 + 90f699f commit 4e25d48
Show file tree
Hide file tree
Showing 16 changed files with 480 additions and 176 deletions.
9 changes: 8 additions & 1 deletion .github/workflows/build_preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ jobs:
- name: Restore dependencies
run: dotnet restore
- name: Build windows x64
run: dotnet publish -c Release --self-contained -r win-x64 -o packages\windows\x64 -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
run: dotnet publish -c Release --self-contained -r win-x64 -o packages\windows\x64 -p:PublishSingleFile=true -p:PublishTrimmed=true -p:InvariantGlobalization=true -p:DebugType=None -p:DebugSymbols=false
- name: Build linux x64
run: dotnet publish -c Release --self-contained -r linux-x64 -o packages\linux\x64 -p:PublishSingleFile=true -p:PublishTrimmed=true -p:InvariantGlobalization=true -p:DebugType=None -p:DebugSymbols=false
- name: Install signing tool
run: dotnet tool install --global AzureSignTool
- name: Digitally sign executable
Expand All @@ -36,3 +38,8 @@ jobs:
with:
name: windows-x64
path: packages\windows/x64\*
- name: Upload linux x64
uses: actions/upload-artifact@v2
with:
name: linux-x64
path: packages\linux/x64\*
17 changes: 15 additions & 2 deletions .github/workflows/build_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ jobs:
- name: Restore dependencies
run: dotnet restore
- name: Build windows x64
run: dotnet publish -c Release --self-contained -r win-x64 -o packages\windows\x64 -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
run: dotnet publish -c Release --self-contained -r win-x64 -o packages\windows\x64 -p:PublishSingleFile=true -p:PublishTrimmed=true -p:InvariantGlobalization=true -p:DebugType=None -p:DebugSymbols=false
- name: Build linux x64
run: dotnet publish -c Release --self-contained -r linux-x64 -o packages\linux\x64 -p:PublishSingleFile=true -p:PublishTrimmed=true -p:InvariantGlobalization=true -p:DebugType=None -p:DebugSymbols=false
- name: version
run: echo ::set-output name=version::$(echo $GITHUB_REF | cut -d / -f 3)
shell: bash
Expand All @@ -41,7 +43,7 @@ jobs:
tag_name: ${{ github.ref }}
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Create archive
- name: Create Windows archive
run: Compress-Archive -DestinationPath .\win_x64.zip -Path .\packages\windows\x64
- name: Upload Win x64 binary
uses: actions/upload-release-asset@v1
Expand All @@ -52,3 +54,14 @@ jobs:
asset_path: .\win_x64.zip
asset_name: smbeagle_${{ steps.version.outputs.version }}_win_x64.zip
asset_content_type: application/zip
- name: Create Linux archive
run: Compress-Archive -DestinationPath .\linux_x64.zip -Path .\packages\linux\x64
- name: Upload Linux x64 binary
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: .\linux_x64.zip
asset_name: smbeagle_${{ steps.version.outputs.version }}_linux_x64.zip
asset_content_type: application/zip
46 changes: 46 additions & 0 deletions FileDiscovery/CrossPlatformPermissionHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using SMBLibrary.Client;
using SMBLibrary;
using System;

namespace SMBeagle.FileDiscovery
{
class CrossPlatformPermissionHelper
{
private static bool CheckAccessMask(ISMBFileStore fileStore, string filePath, AccessMask accessMask)
{
if (fileStore is SMB1FileStore)
{
filePath = @"\\" + filePath;
}
object handle;
NTStatus result = fileStore.CreateFile(out handle, out _, filePath, accessMask, FileAttributes.Normal, ShareAccess.None, CreateDisposition.FILE_OPEN, CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, null);
if (result == NTStatus.STATUS_SUCCESS)
fileStore.CloseFile(handle);
return result == NTStatus.STATUS_SUCCESS;
}
public static ACL ResolvePermissions(File file)
{
ACL acl = new();
if (file.ParentDirectory.Share == null)
{
Console.WriteLine("ERROR: File does not have a parent share");
Environment.Exit(1);
}
NTStatus status;
//TODO: optimise storing filestore somewhere
ISMBFileStore fileStore = file.ParentDirectory.Share.Host.Client.TreeConnect(file.ParentDirectory.Share.Name, out status);

if (status != NTStatus.STATUS_SUCCESS)
{
Console.WriteLine("ERROR: Could not connect to share");
}
string filePath = file.FullName;
acl.Readable = CheckAccessMask(fileStore, filePath, AccessMask.GENERIC_READ | AccessMask.SYNCHRONIZE);
acl.Writeable = CheckAccessMask(fileStore, filePath, AccessMask.GENERIC_WRITE | AccessMask.SYNCHRONIZE);
acl.Deletable = CheckAccessMask(fileStore, filePath, AccessMask.DELETE | AccessMask.SYNCHRONIZE);
fileStore.Disconnect();
return acl;
}
}

}
150 changes: 130 additions & 20 deletions FileDiscovery/Directory.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
using System;
using SMBeagle.ShareDiscovery;
using SMBLibrary;
using SMBLibrary.Client;
using System;
using System.Collections.Generic;
using System.IO;

namespace SMBeagle.FileDiscovery
{
class Directory
{
public Share Share { get; set; }
public string Path { get; set; }
public string UNCPath
{
get
{
// Windows enum needs UNC Paths as Path but Cross-platform doesnt.
if (Path.StartsWith(@"\\"))
return Path;
else
return $"{Share.uncPath}{Path}";
}
}
//todo: replace Base and Type with direct copy from parent then drop the ref
#nullable enable
public Directory? Parent { get; set; } = null;
Expand Down Expand Up @@ -50,15 +65,16 @@ public List<Directory> RecursiveChildDirectories

public List<File> Files { get; private set; } = new List<File>();
public List<Directory> ChildDirectories { get; private set; } = new List<Directory>();
public Directory(string path)
public Directory(string path, Share share)
{
Share = share;
Path = path;
}
public void FindFiles(string pattern = "*.*", List<string> extensionsToIgnore = null)
public void FindFilesWindows(List<string> extensionsToIgnore = null)
{
try
{
FileInfo[] files = new DirectoryInfo(Path).GetFiles(pattern);
FileInfo[] files = new DirectoryInfo(Path).GetFiles("*.*");
foreach (FileInfo file in files)
{
if (extensionsToIgnore.Contains(file.Extension.ToLower()))
Expand All @@ -77,45 +93,139 @@ public void FindFiles(string pattern = "*.*", List<string> extensionsToIgnore =
}
catch { }
}

public void FindFilesCrossPlatform(List<string> extensionsToIgnore = null)
{
try
{
NTStatus status;
ISMBFileStore fileStore = Share.Host.Client.TreeConnect(Share.Name, out status);
if (status == NTStatus.STATUS_SUCCESS)
{
object directoryHandle;
FileStatus fileStatus;
status = fileStore.CreateFile(out directoryHandle, out fileStatus, Path, AccessMask.GENERIC_READ, SMBLibrary.FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);
if (status == NTStatus.STATUS_SUCCESS)
{
List<QueryDirectoryFileInformation> fileList;
//TODO: can we filter on just files
fileStore.QueryDirectory(out fileList, directoryHandle, "*", FileInformationClass.FileDirectoryInformation);
foreach (QueryDirectoryFileInformation f in fileList)
{
if (f.FileInformationClass == FileInformationClass.FileDirectoryInformation)
{
FileDirectoryInformation d = (FileDirectoryInformation)f;
if (d.FileAttributes != SMBLibrary.FileAttributes.Directory)
{
string extension = d.FileName.Substring(d.FileName.LastIndexOf('.') + 1);
string path;
if (Path == "")
path = d.FileName;
else
path = $"{Path}\\{d.FileName}";
if (extensionsToIgnore.Contains(extension.ToLower()))
continue;
Files.Add(
new File(
parentDirectory: this,
name: d.FileName,
fullName: path,
extension: extension,
creationTime: d.CreationTime,
lastWriteTime: d.LastWriteTime
)
);
}
}
}
fileStore.CloseFile(directoryHandle);
}
fileStore.Disconnect();
}
}
catch
{
//TODO: Implement better error handling here, one explosion should not wipe out the whole enumeration
}
}
public void Clear()
{
Files.Clear();
ChildDirectories.Clear();
}

private void FindDirectories()
private void FindDirectoriesWindows()
{
try
{
DirectoryInfo[] subDirs = new DirectoryInfo(Path).GetDirectories();
DirectoryInfo[] subDirs = new DirectoryInfo(UNCPath).GetDirectories();
foreach (DirectoryInfo di in subDirs)
ChildDirectories.Add(new Directory(path: di.FullName) { Parent = this});
ChildDirectories.Add(new Directory(path: di.FullName, share: Share) { Parent = this});
}
catch { }
}
public void FindDirectoriesRecursively()
private void FindDirectoriesCrossPlatform()
{
FindDirectories();
foreach (Directory dir in ChildDirectories)
try
{
NTStatus status;
ISMBFileStore fileStore = Share.Host.Client.TreeConnect(Share.Name, out status);
if (status == NTStatus.STATUS_SUCCESS)
{
object directoryHandle;
FileStatus fileStatus;
status = fileStore.CreateFile(out directoryHandle, out fileStatus, Path, AccessMask.GENERIC_READ, SMBLibrary.FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);
if (status == NTStatus.STATUS_SUCCESS)
{
List<QueryDirectoryFileInformation> fileList;
//TODO: can we filter on just files
fileStore.QueryDirectory(out fileList, directoryHandle, "*", FileInformationClass.FileDirectoryInformation);
foreach (QueryDirectoryFileInformation f in fileList)
{
if (f.FileInformationClass == FileInformationClass.FileDirectoryInformation)
{
FileDirectoryInformation d = (FileDirectoryInformation) f;
if (d.FileAttributes == SMBLibrary.FileAttributes.Directory && d.FileName != "." && d.FileName != "..")
{
string path = "";
if (Path != "")
path += $"{Path}\\";
path += d.FileName;
ChildDirectories.Add(new Directory(path: path, share: Share) { Parent = this });
}
}
}
fileStore.CloseFile(directoryHandle);
}
fileStore.Disconnect();
}
}
catch
{
dir.FindDirectoriesRecursively();
//TODO: Implement better error handling here, one explosion should not wipe out the whole enumeration
}
}

public void FindFilesRecursively(string pattern = "*.*", List<string> extensionsToIgnore = null)
public void FindDirectoriesRecursively(bool crossPlatform)
{
FindFiles(pattern, extensionsToIgnore);
foreach (Directory dir in RecursiveChildDirectories)
if (crossPlatform)
FindDirectoriesCrossPlatform();
else
FindDirectoriesWindows();
foreach (Directory dir in ChildDirectories)
{
dir.FindFilesRecursively(pattern, extensionsToIgnore);
dir.FindDirectoriesRecursively(crossPlatform);
}
}

public void EnumerateFullTree()
public void FindFilesRecursively(bool crossPlatform, List<string> extensionsToIgnore = null)
{
FindDirectoriesRecursively();
FindFilesRecursively();
if (crossPlatform)
FindFilesCrossPlatform(extensionsToIgnore);
else
FindFilesWindows(extensionsToIgnore);
foreach (Directory dir in RecursiveChildDirectories)
{
dir.FindFilesRecursively(crossPlatform, extensionsToIgnore);
}
}

}
Expand Down
Loading

0 comments on commit 4e25d48

Please sign in to comment.