prod@blog:~$

Auditing SMB Shares Across Your Windows Domain for Security Risks


Creating SMB shares on a file server is one thing, but unfortunately, every Windows client or server has the ability to create local shares. These shares can appear anywhere across your domain, often created by users or applications without IT's knowledge, potentially exposing sensitive data to unauthorized access.

If you need to audit these shares and confirm there are no security concerns, then you'll need PowerShell to do a comprehensive assessment of your domain. Manual checking simply isn't feasible when you have hundreds or thousands of computers.

Understanding Share Permissions vs ACL

When it comes to shares, there are two permission layers:

  1. Share permissions - Applied at the share level
  2. Security permissions (ACL) - Applied at the NTFS folder level

Share permissions apply before security permissions, meaning if you set "Read" on the share permission and "Write" on the ACL, users will only be able to obtain read access because the share has restricted it.

This is why it's recommended to set your share permissions to "Everyone Full Control" or, if you wish to be a little bit more secure, "Authenticated Users Full Control". The difference is that "Everyone" includes unauthenticated users, while "Authenticated Users" only includes people authenticated by your domain controller, making it a little bit more secure against unauthorized and unmanaged devices.

The Security Risk

What is particularly concerning is when on the ACL of a share (or anywhere in Windows), someone blindly applies "Everyone Full Control". This causes several problems because it means any user - authenticated or not - can technically delete, modify, or access files from that folder without proper authorization, especially if that folder is shared via an unsecured share.

The Solution: PowerShell Audit Scripts

I've developed two PowerShell scripts to address this security concern. The first targets individual servers for testing, and the second scans your entire domain.

Script 1: Individual Server Audit

The first script targets a server individually with the -ServerName parameter. This is to make sure the script works and does what it should do - giving you a report on all the shares listed on that server, and then another report where it detects "Everyone" having Full Control on the ACL.

Key Components Explained

Administrative Share Exclusions

I've built in automatic exclusion of administrative shares that are part of Windows by default:

# Define exclusions for administrative shares
$exclusions = @('C$', 'D$', 'E$', 'ADMIN$', 'IPC$', 'print$', 'NETLOGON', 'SYSVOL')

# Add any custom exclusions here
$customExclusions = @()
$exclusions += $customExclusions

This ensures I'm not reporting on built-in administrative shares that are meant to be there. The $customExclusions array allows you to add your own shares to skip, such as backup software shares or monitoring tool shares.

Remote Connection Management

The script establishes a CIM session for remote connectivity:

try {
    # Test connectivity to the server first
    if (-not (Test-Connection -ComputerName $ServerName -Count 1 -Quiet)) {
        throw "Cannot connect to server $ServerName"
    }
    
    # Get all SMB shares from the remote server
    $shares = Get-SmbShare -CimSession $ServerName -ErrorAction Stop
}
catch {
    Write-Host "✗ ERROR: $_" -ForegroundColor Red
}

This approach uses CIM sessions which are more firewall-friendly than traditional PowerShell remoting and work over standard Windows management ports.

Permission Analysis Logic

The core permission checking logic examines each ACL entry:

# Get ACL for the share path
$acl = Get-Acl -Path $uncPath -ErrorAction Stop

# Process each access rule
foreach ($accessRule in $acl.Access) {
    $identityName = $accessRule.IdentityReference.Value
    
    # Create detailed share data object for reporting
    $shareData = [PSCustomObject]@{
        ServerName = $ServerName
        ShareName = $share.Name
        SharePath = $share.Path
        UNCPath = $uncPath
        Description = $share.Description
        Identity = $identityName
        Rights = $accessRule.FileSystemRights
        AccessControlType = $accessRule.AccessControlType
        IsInherited = $accessRule.IsInherited
        InheritanceFlags = $accessRule.InheritanceFlags
        PropagationFlags = $accessRule.PropagationFlags
    }
}

This captures comprehensive permission details including inheritance flags, which help identify whether permissions were set explicitly or inherited from parent folders.

Dangerous Permission Detection

The script looks for multiple variations of "Everyone" groups and different representations of Full Control:

# Check for Everyone with Full Control
if ($identityName -match "Everyone|BUILTIN\\Users|NT AUTHORITY\\Authenticated Users") {
    # Check multiple representations of Full Control
    if ($accessRule.FileSystemRights -eq "FullControl" -or 
        $accessRule.FileSystemRights -eq "-1" -or
        $accessRule.FileSystemRights -eq "268435456" -or
        $accessRule.FileSystemRights -match "FullControl") {
        
        Write-Host "⚠ WARNING: Full Control detected!" -ForegroundColor Red
        
        # Create detailed risk entry
        $everyoneData = [PSCustomObject]@{
            ServerName = $ServerName
            ShareName = $share.Name
            SharePath = $share.Path
            UNCPath = $uncPath
            Identity = $identityName
            Rights = $accessRule.FileSystemRights
            RiskLevel = "HIGH"
            DiscoveredTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
        }
    }
}

The multiple checks for Full Control are necessary because Windows can represent these permissions in different numeric formats depending on how they were set.

Sample Output - Normal Server

Here's what you'd see when scanning a normal server with five shares:

Console Output:

========================================
SMB Share Permission Audit
Target Server: FILESERVER01
Started: 2024-01-15 10:23:45
========================================

Testing connection to FILESERVER01...
Retrieving SMB shares from FILESERVER01...
Found 8 total shares

  Skipping administrative share: ADMIN$
  Skipping administrative share: C$
  Skipping administrative share: IPC$

Processing share: Finance
  Path: E:\Shares\Finance
  Total ACL entries: 4
  Unique identities: 3

Processing share: HR_Documents  
  Path: E:\Shares\HR
  Total ACL entries: 3
  Unique identities: 2

Processing share: Public
  Path: E:\Shares\Public
  Total ACL entries: 5
  Unique identities: 4

Processing share: Marketing
  Path: E:\Shares\Marketing
  Total ACL entries: 6
  Unique identities: 4

Processing share: IT_Tools
  Path: E:\Shares\IT
  Total ACL entries: 2
  Unique identities: 2

========================================
Generating Reports...
========================================

✓ All shares report saved to: AllShares_FILESERVER01_20240115_102345.csv
  Total permission entries: 20

✓ No shares found with Everyone Full Control (Good!)

========================================
Audit Summary
========================================
Server: FILESERVER01
Total shares scanned: 8
Non-admin shares: 5
Risky shares found: 0
Completed: 2024-01-15 10:24:12

Sample Output - Server with Security Risk

Now, here's what happens when one of those shares has "Everyone Full Control" on the ACL:

Console Output:

Processing share: Public
  Path: E:\Shares\Public
  Found: Everyone
    Rights: FullControl
    ⚠ WARNING: Full Control detected!
  Found: BUILTIN\Users
    Rights: FullControl
    ⚠ WARNING: Full Control detected!
  Total ACL entries: 5
  Unique identities: 4

========================================
Generating Reports...
========================================

✓ All shares report saved to: AllShares_FILESERVER01_20240115_102345.csv
  Total permission entries: 22

⚠ SECURITY ALERT: Found 2 shares with Everyone Full Control!
  Report saved to: EveryoneFullControl_FILESERVER01_20240115_102345.csv
  
  Affected shares:
    - Public (Everyone)
    - Public (BUILTIN\Users)

If you don't get the additional "EveryoneFullControl" exception file, you have no shares that assign Everyone Full Control - which is the desired state.

Script 2: Domain-Wide Audit

The second script connects to your domain and looks up all computers, which you can filter with "Workstations" or "Servers", and will try to query the shares remotely. I've built a timeout parameter into this to avoid excessively long-running scripts.

Advanced Features Explained

Active Directory Computer Discovery

The script uses LDAP filters to efficiently query Active Directory:

if ($ComputerType -eq "Servers") {
    # Get all servers (Windows Server OS)
    $computers = Get-ADComputer -Filter {
        OperatingSystem -like "*Server*" -and 
        Enabled -eq $true
    } -Properties Name, OperatingSystem, DNSHostName | 
    Select-Object Name, OperatingSystem, DNSHostName
}
else {
    # Get all workstations (non-Server OS)
    $computers = Get-ADComputer -Filter {
        OperatingSystem -notlike "*Server*" -and 
        Enabled -eq $true
    } -Properties Name, OperatingSystem, DNSHostName | 
    Select-Object Name, OperatingSystem, DNSHostName
}

The filter for Enabled -eq $true ensures I'm not wasting time trying to connect to disabled computer accounts.

Robust Timeout Mechanism

The timeout mechanism using PowerShell jobs prevents the script from hanging:

# Create a job to get SMB shares with timeout
$job = Start-Job -ScriptBlock {
    param($compName)
    try {
        $session = New-CimSession -ComputerName $compName -ErrorAction Stop
        $shares = Get-SmbShare -CimSession $session -ErrorAction Stop
        Remove-CimSession $session -ErrorAction SilentlyContinue
        return $shares
    }
    catch {
        return $null
    }
} -ArgumentList $computerName

# Wait for job with timeout
Write-Host "Attempting to retrieve SMB shares (timeout: $TimeoutSeconds seconds)..." -NoNewline
$completed = Wait-Job -Job $job -Timeout $TimeoutSeconds

if ($completed) {
    $shares = Receive-Job -Job $job
    Remove-Job -Job $job -Force
    # Process shares
}
else {
    # Timeout occurred - kill the job and move on
    Stop-Job -Job $job -ErrorAction SilentlyContinue
    Remove-Job -Job $job -Force -ErrorAction SilentlyContinue
    Write-Host " Timeout!" -ForegroundColor Red
}

This ensures the script never hangs indefinitely on an unresponsive computer. The job runs in the background and is forcefully terminated if it doesn't complete within the timeout period.

Connectivity Testing with Flexibility

I've included optional ping testing that can be bypassed:

# Test connectivity (unless skipped)
if (-not $SkipPing) {
    Write-Host "Testing connectivity..." -NoNewline
    if (Test-Connection -ComputerName $computerName -Count 1 -Quiet) {
        Write-Host " Ping successful" -ForegroundColor Green
        $isReachable = $true
    }
    else {
        Write-Host " Ping failed" -ForegroundColor Yellow
        # Try anyway since ping might be blocked
        $isReachable = $true
    }
}

This is important because many organizations block ICMP (ping) traffic, but SMB might still work.

Nested Timeout for ACL Retrieval

Even ACL retrieval has its own timeout to prevent hanging on slow network shares:

# Create a job for ACL retrieval with timeout
$aclJob = Start-Job -ScriptBlock {
    param($path)
    try {
        return Get-Acl -Path $path -ErrorAction Stop
    }
    catch {
        return $null
    }
} -ArgumentList $uncPath

$aclCompleted = Wait-Job -Job $aclJob -Timeout $TimeoutSeconds

if ($aclCompleted) {
    $acl = Receive-Job -Job $aclJob
    Remove-Job -Job $aclJob -Force
    # Process ACL entries
}

Progress Tracking

For large domains, I've added progress indicators:

# Progress indicator
if ($processedComputers % 10 -eq 0) {
    $percentComplete = [math]::Round(($processedComputers / $computers.Count) * 100, 1)
    Write-Host "`nProgress: $percentComplete% complete ($processedComputers/$($computers.Count))" -ForegroundColor Magenta
}

This gives you feedback every 10 computers so you know the script is still running.

Comprehensive Error Tracking

The script tracks unreachable computers with detailed status:

$unreachableComputers += [PSCustomObject]@{
    ComputerName = $computerName
    OperatingSystem = $computer.OperatingSystem
    Status = "Connection timeout ($TimeoutSeconds seconds)"
    Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
}

This helps identify patterns - maybe all Windows 10 machines are failing, or all computers in a specific subnet.

Memory Management

The cleanup section ensures no orphaned jobs remain:

finally {
    # Clean up any remaining jobs
    Get-Job | Where-Object {$_.State -eq 'Running'} | Stop-Job -ErrorAction SilentlyContinue
    Get-Job | Remove-Job -Force -ErrorAction SilentlyContinue
    
    # Clean up CIM sessions
    Get-CimSession | Where-Object {$_.ComputerName -eq $ServerName} | Remove-CimSession -ErrorAction SilentlyContinue
}

This prevents memory leaks during long-running scans of large domains.

Important Considerations

If you're going to run the domain-wide script, it must be able to connect to the computer to retrieve the data. This requires:

  • SMB service to be running and accessible (TCP port 445)
  • Appropriate firewall rules allowing WMI/CIM traffic
  • Administrative credentials on target computers
  • PowerShell remoting capabilities or WinRM configured

However, if SMB is not available to that server, there's no risk because users won't be able to access the shares to start with - so a failure to connect is actually a good indicator that the shares aren't exposed.

Running the Scripts

For individual server testing:

# Basic usage
.\Audit-SmbSharePermissions.ps1 -ServerName "FILESERVER01"

# If you need to test from a specific domain controller
.\Audit-SmbSharePermissions.ps1 -ServerName "DC01.domain.local"

For domain-wide scanning:

# Scan all servers with default 5-second timeout
.\Audit-SmbSharePermissions-AD.ps1 -ComputerType "Servers"

# Scan workstations with extended timeout
.\Audit-SmbSharePermissions-AD.ps1 -ComputerType "Workstations" -TimeoutSeconds 10

# Skip ping tests for environments that block ICMP
.\Audit-SmbSharePermissions-AD.ps1 -ComputerType "Servers" -SkipPing

# Combine parameters for challenging networks
.\Audit-SmbSharePermissions-AD.ps1 -ComputerType "Servers" -TimeoutSeconds 15 -SkipPing

Understanding the Output Files

The scripts generate timestamped CSV files that can be opened in Excel for analysis:

AllShares_[Type]_[Timestamp].csv contains:

  • ComputerName, OperatingSystem
  • ShareName, SharePath, UNCPath
  • Every single ACL entry with full permission details
  • Inheritance and propagation flags
  • Scan timestamp

EveryoneFullControl_[Type]_[Timestamp].csv contains:

  • Only the dangerous permission entries
  • Risk level assessment
  • When it was discovered
  • Complete context for remediation

UnreachableComputers_[Type]_[Timestamp].csv contains:

  • Failed connection attempts
  • Reason for failure (timeout, ping failed, etc.)
  • Operating system information
  • Timestamps for pattern analysis

Conclusion

Regular auditing of SMB shares across your domain is essential for maintaining security. These scripts provide a systematic approach to identifying potentially dangerous permission configurations before they can be exploited. The ability to scan individual servers for testing, then scale up to domain-wide audits, gives you the flexibility to validate your approach before running it across your entire infrastructure.

By identifying shares with "Everyone Full Control" permissions, you can proactively address security risks that might otherwise go unnoticed until it's too late. Remember, the absence of an "EveryoneFullControl" CSV file is a good thing - it means your shares are configured more securely.

The time invested in running these audits regularly will pay dividends in preventing data breaches and maintaining compliance with security policies. I recommend scheduling these scans monthly or quarterly, depending on your environment's rate of change. Consider integrating these scripts into your security monitoring dashboard or SIEM system for continuous oversight of share security across your domain.