ThreatHunting/Find-DataExfiltration.ps1

function Find-DataExfiltration {
    <#
    .SYNOPSIS
        Detects potential data exfiltration activities
    .DESCRIPTION
        Identifies indicators of data exfiltration including large file transfers,
        uploads to cloud services, compression activities, and staging behaviors
    .PARAMETER CheckLargeTransfers
        Check for large network transfers
    .PARAMETER CheckCloudUploads
        Check for uploads to cloud services
    .PARAMETER CheckCompression
        Check for file compression activities
    .PARAMETER CheckStaging
        Check for data staging activities
    .PARAMETER ThresholdMB
        Threshold for large file transfers in MB (default: 100)
    .EXAMPLE
        Find-DataExfiltration -CheckLargeTransfers -CheckCloudUploads
        Find-DataExfiltration -CheckLargeTransfers -CheckCompression -CheckStaging -ThresholdMB 50
    .OUTPUTS
        PSCustomObject with data exfiltration indicators
    #>

    
    [CmdletBinding()]
    param(
        [Parameter()]
        [switch]$CheckLargeTransfers,
        
        [Parameter()]
        [switch]$CheckCloudUploads,
        
        [Parameter()]
        [switch]$CheckCompression,
        
        [Parameter()]
        [switch]$CheckStaging,
        
        [Parameter()]
        [int]$ThresholdMB = 100
    )
    
    begin {
        Write-Host "=== DATA EXFILTRATION DETECTION ===" -ForegroundColor Cyan
        Write-Host "Start Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Yellow
        Write-Host "Transfer Threshold: $ThresholdMB MB" -ForegroundColor Yellow
        
        if (-not ($CheckLargeTransfers -or $CheckCloudUploads -or $CheckCompression -or $CheckStaging)) {
            $CheckLargeTransfers = $true
            $CheckCloudUploads = $true
            Write-Host "No specific check selected - enabling default checks" -ForegroundColor Yellow
        }
        
        $results = [PSCustomObject]@{
            ScanDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
            ComputerName = $env:COMPUTERNAME
            ThresholdMB = $ThresholdMB
            Indicators = @{
                LargeTransfers = @()
                CloudUploads = @()
                Compression = @()
                Staging = @()
            }
            Summary = @{
                TotalIndicators = 0
                CriticalFindings = 0
                HighFindings = 0
                MediumFindings = 0
                TotalDataMB = 0
            }
            Recommendations = @()
        }
        
        # Track file paths already counted toward TotalDataMB (Compression and Staging
        # scan overlapping locations such as $env:TEMP)
        $countedDataPaths = @{}

        # Known cloud services and upload endpoints
        $cloudServices = @(
            'dropbox.com',
            'drive.google.com',
            'onedrive.live.com',
            'box.com',
            'mega.nz',
            'wetransfer.com',
            'sendspace.com',
            'mediafire.com',
            'filebin.net',
            'pastebin.com',
            'transfer.sh',
            's3.amazonaws.com',
            'blob.core.windows.net'
        )
    }
    
    process {
        try {
            # 1. Check for Large Network Transfers
            if ($CheckLargeTransfers) {
                Write-Host "`n[1/4] Checking network transfers..." -ForegroundColor Cyan
                
                try {
                    # Check active connections with high data transfer
                    $connections = Get-NetTCPConnection -State Established -ErrorAction SilentlyContinue |
                        Where-Object { $null -ne $_ -and $_.RemoteAddress -notmatch '^(127\.|::1|0\.0\.0\.0)' }
                    
                    foreach ($conn in $connections | Select-Object -First 10) {
                        $process = Get-Process -Id $conn.OwningProcess -ErrorAction SilentlyContinue
                        
                        if ($process) {
                            # Skip browsers and common legitimate processes
                            if ($process.Name -match 'chrome|firefox|edge|teams|zoom|onedrive') {
                                continue
                            }
                            
                            $indicator = [PSCustomObject]@{
                                Type = 'NetworkTransfer'
                                Process = $process.Name
                                ProcessId = $conn.OwningProcess
                                RemoteAddress = $conn.RemoteAddress
                                RemotePort = $conn.RemotePort
                                LocalPort = $conn.LocalPort
                                Severity = 'Medium'
                                Description = "Active connection from $($process.Name) to $($conn.RemoteAddress)"
                                Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
                            }
                            
                            $results.Indicators.LargeTransfers += $indicator
                            $results.Summary.MediumFindings++
                            
                            Write-Host " [!] Active: $($process.Name) -> $($conn.RemoteAddress):$($conn.RemotePort)" -ForegroundColor Yellow
                        }
                    }
                    
                    if ($results.Indicators.LargeTransfers.Count -eq 0) {
                        Write-Host " No suspicious large transfers detected" -ForegroundColor Green
                    }
                }
                catch {
                    Write-Warning "Error checking network transfers: $_"
                }
            }
            
            # 2. Check for Cloud Service Uploads
            if ($CheckCloudUploads) {
                Write-Host "`n[2/4] Checking cloud service uploads..." -ForegroundColor Cyan
                
                try {
                    # Check active connections to known cloud services
                    $connections = Get-NetTCPConnection -State Established -ErrorAction SilentlyContinue
                    
                    $foundCount = 0
                    
                    foreach ($conn in $connections) {
                        # Try to resolve hostname
                        try {
                            $hostname = [System.Net.Dns]::GetHostEntry($conn.RemoteAddress).HostName
                        }
                        catch {
                            $hostname = $conn.RemoteAddress
                        }
                        
                        foreach ($cloudService in $cloudServices) {
                            if ($hostname -like "*$cloudService*") {
                                $process = Get-Process -Id $conn.OwningProcess -ErrorAction SilentlyContinue
                                
                                if (-not $process) {
                                    break
                                }
                                
                                # Skip if it's a browser (expected behavior)
                                if ($process.Name -match 'chrome|firefox|edge|msedge') {
                                    continue
                                }
                                
                                $indicator = [PSCustomObject]@{
                                    Type = 'CloudUpload'
                                    Process = $process.Name
                                    ProcessId = $conn.OwningProcess
                                    CloudService = $cloudService
                                    RemoteAddress = $conn.RemoteAddress
                                    Hostname = $hostname
                                    Severity = 'High'
                                    Description = "Connection to $cloudService from $($process.Name)"
                                    Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
                                }
                                
                                $results.Indicators.CloudUploads += $indicator
                                $results.Summary.HighFindings++
                                $foundCount++
                                
                                Write-Host " [!] Cloud: $cloudService via $($process.Name)" -ForegroundColor Red
                                break
                            }
                        }
                    }
                    
                    if ($foundCount -eq 0) {
                        Write-Host " No suspicious cloud uploads detected" -ForegroundColor Green
                    }
                }
                catch {
                    Write-Warning "Error checking cloud uploads: $_"
                }
            }
            
            # 3. Check for File Compression Activities
            if ($CheckCompression) {
                Write-Host "`n[3/4] Checking compression activities..." -ForegroundColor Cyan
                
                try {
                    # Check for running compression tools
                    $compressionTools = @('7z', 'winrar', 'zip', 'rar', 'tar', 'gzip')
                    $processes = Get-Process | Select-Object Name, Id, Path, StartTime
                    
                    $foundCount = 0
                    
                    foreach ($process in $processes) {
                        foreach ($tool in $compressionTools) {
                            if ($process.Name -like "*$tool*") {
                                $indicator = [PSCustomObject]@{
                                    Type = 'Compression'
                                    Process = $process.Name
                                    ProcessId = $process.Id
                                    Path = $process.Path
                                    StartTime = if ($process.StartTime) { $process.StartTime.ToString("yyyy-MM-dd HH:mm:ss") } else { "Unknown" }
                                    Severity = 'Medium'
                                    Description = "Compression tool running: $($process.Name)"
                                    Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
                                }
                                
                                $results.Indicators.Compression += $indicator
                                $results.Summary.MediumFindings++
                                $foundCount++
                                
                                Write-Host " [!] Compression: $($process.Name) (PID: $($process.Id))" -ForegroundColor Yellow
                                break
                            }
                        }
                    }
                    
                    # Check recent archive files in common locations
                    $tempPaths = @($env:TEMP, $env:USERPROFILE, "$env:USERPROFILE\Downloads", "$env:USERPROFILE\Desktop")
                    $archiveExtensions = @('*.zip', '*.rar', '*.7z', '*.tar', '*.gz')
                    
                    foreach ($path in $tempPaths) {
                        if (Test-Path $path) {
                            foreach ($ext in $archiveExtensions) {
                                $recentArchives = Get-ChildItem -Path $path -Filter $ext -File -ErrorAction SilentlyContinue |
                                    Where-Object { $_.LastWriteTime -gt (Get-Date).AddHours(-24) } |
                                    Where-Object { $_.Length -gt ($ThresholdMB * 1MB) }
                                
                                foreach ($archive in $recentArchives) {
                                    $sizeMB = [math]::Round($archive.Length / 1MB, 2)
                                    
                                    $indicator = [PSCustomObject]@{
                                        Type = 'Compression'
                                        Process = 'N/A'
                                        ProcessId = 'N/A'
                                        Path = $archive.FullName
                                        SizeMB = $sizeMB
                                        LastModified = $archive.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss")
                                        Severity = if ($sizeMB -gt 500) { 'High' } else { 'Medium' }
                                        Description = "Large archive file: $($archive.Name) ($sizeMB MB)"
                                        Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
                                    }
                                    
                                    $results.Indicators.Compression += $indicator
                                    if (-not $countedDataPaths.ContainsKey($archive.FullName)) {
                                        $countedDataPaths[$archive.FullName] = $true
                                        $results.Summary.TotalDataMB += $sizeMB
                                    }
                                    
                                    if ($sizeMB -gt 500) {
                                        $results.Summary.HighFindings++
                                    } else {
                                        $results.Summary.MediumFindings++
                                    }
                                    
                                    $foundCount++
                                    
                                    Write-Host " [!] Archive: $($archive.Name) ($sizeMB MB)" -ForegroundColor Yellow
                                }
                            }
                        }
                    }
                    
                    if ($foundCount -eq 0) {
                        Write-Host " No suspicious compression activities detected" -ForegroundColor Green
                    }
                }
                catch {
                    Write-Warning "Error checking compression: $_"
                }
            }
            
            # 4. Check for Data Staging
            if ($CheckStaging) {
                Write-Host "`n[4/4] Checking data staging..." -ForegroundColor Cyan
                
                try {
                    # Check for large files in staging locations
                    $stagingPaths = @(
                        "$env:TEMP",
                        "$env:USERPROFILE\AppData\Local\Temp",
                        "C:\Users\Public",
                        "C:\ProgramData"
                    )
                    
                    $foundCount = 0
                    
                    foreach ($path in $stagingPaths) {
                        if (Test-Path $path) {
                            # Find large files created recently
                            $recentFiles = Get-ChildItem -Path $path -File -Recurse -ErrorAction SilentlyContinue -Depth 2 |
                                Where-Object { 
                                    $_.Length -gt ($ThresholdMB * 1MB) -and 
                                    $_.CreationTime -gt (Get-Date).AddHours(-24) 
                                } |
                                Sort-Object Length -Descending |
                                Select-Object -First 5
                            
                            foreach ($file in $recentFiles) {
                                $sizeMB = [math]::Round($file.Length / 1MB, 2)
                                
                                $indicator = [PSCustomObject]@{
                                    Type = 'Staging'
                                    Process = 'N/A'
                                    ProcessId = 'N/A'
                                    Path = $file.FullName
                                    FileName = $file.Name
                                    SizeMB = $sizeMB
                                    Created = $file.CreationTime.ToString("yyyy-MM-dd HH:mm:ss")
                                    Severity = if ($sizeMB -gt 500) { 'High' } else { 'Medium' }
                                    Description = "Large file in staging location: $($file.Name) ($sizeMB MB)"
                                    Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
                                }
                                
                                $results.Indicators.Staging += $indicator
                                if (-not $countedDataPaths.ContainsKey($file.FullName)) {
                                    $countedDataPaths[$file.FullName] = $true
                                    $results.Summary.TotalDataMB += $sizeMB
                                }
                                
                                if ($sizeMB -gt 500) {
                                    $results.Summary.HighFindings++
                                } else {
                                    $results.Summary.MediumFindings++
                                }
                                
                                $foundCount++
                                
                                Write-Host " [!] Staged: $($file.Name) ($sizeMB MB) in $path" -ForegroundColor Yellow
                            }
                        }
                    }
                    
                    if ($foundCount -eq 0) {
                        Write-Host " No suspicious data staging detected" -ForegroundColor Green
                    }
                }
                catch {
                    Write-Warning "Error checking staging: $_"
                }
            }
            
            # Calculate summary
            $results.Summary.TotalIndicators = 
                $results.Indicators.LargeTransfers.Count +
                $results.Indicators.CloudUploads.Count +
                $results.Indicators.Compression.Count +
                $results.Indicators.Staging.Count
            
            # Generate recommendations
            if ($results.Summary.TotalIndicators -gt 0) {
                if ($results.Summary.HighFindings -gt 0) {
                    $results.Recommendations += "HIGH: Investigate high-severity exfiltration indicators immediately"
                }
                
                $results.Recommendations += "Review and investigate flagged processes and files"
                $results.Recommendations += "Check network logs for data transfer volumes"
                $results.Recommendations += "Implement DLP (Data Loss Prevention) solution"
                $results.Recommendations += "Monitor cloud service access"
                $results.Recommendations += "Enable file access auditing on sensitive data"
                
                if ($results.Indicators.CloudUploads.Count -gt 0) {
                    $results.Recommendations += "Consider blocking unauthorized cloud services"
                }
                
                if ($results.Summary.TotalDataMB -gt 1000) {
                    $results.Recommendations += "CRITICAL: Large volume of data detected ($([math]::Round($results.Summary.TotalDataMB/1024, 2)) GB)"
                }
            }
            
        }
        catch {
            Write-Error "Error during data exfiltration detection: $_"
            throw
        }
    }
    
    end {
        Write-Host "`n=== SCAN COMPLETE ===" -ForegroundColor $(
            if ($results.Summary.HighFindings -gt 0) { 'Red' }
            elseif ($results.Summary.TotalIndicators -gt 0) { 'Yellow' }
            else { 'Green' }
        )
        
        Write-Host "`nDetection Summary:" -ForegroundColor Cyan
        Write-Host " Total Indicators: $($results.Summary.TotalIndicators)" -ForegroundColor White
        Write-Host " Critical: $($results.Summary.CriticalFindings)" -ForegroundColor Red
        Write-Host " High: $($results.Summary.HighFindings)" -ForegroundColor Yellow
        Write-Host " Medium: $($results.Summary.MediumFindings)" -ForegroundColor Yellow
        Write-Host " Total Data Volume: $([math]::Round($results.Summary.TotalDataMB, 2)) MB" -ForegroundColor White
        
        if ($results.Summary.TotalIndicators -gt 0) {
            Write-Host "`nIndicator Breakdown:" -ForegroundColor Cyan
            if ($results.Indicators.LargeTransfers.Count -gt 0) {
                Write-Host " Large Transfers: $($results.Indicators.LargeTransfers.Count)" -ForegroundColor White
            }
            if ($results.Indicators.CloudUploads.Count -gt 0) {
                Write-Host " Cloud Uploads: $($results.Indicators.CloudUploads.Count)" -ForegroundColor White
            }
            if ($results.Indicators.Compression.Count -gt 0) {
                Write-Host " Compression: $($results.Indicators.Compression.Count)" -ForegroundColor White
            }
            if ($results.Indicators.Staging.Count -gt 0) {
                Write-Host " Staging: $($results.Indicators.Staging.Count)" -ForegroundColor White
            }
        }
        else {
            Write-Host "`nNo data exfiltration indicators detected" -ForegroundColor Green
        }
        
        if ($results.Recommendations.Count -gt 0) {
            Write-Host "`nRecommendations:" -ForegroundColor Cyan
            $results.Recommendations | Select-Object -Unique | ForEach-Object {
                Write-Host " ! $_" -ForegroundColor Yellow
            }
        }
        
        return $results
    }
}