Bitcoin

ConnArtist: Lightweight Endpoint Network Logger in PowerShell

In today’s digital landscape, quickly understanding what’s happening behind the scenes on an individual machine can be crucial. Introducing ConnArtist, a streamlined, intuitive PowerShell script designed specifically for monitoring network connections on a single endpoint—ideal for security checks or diagnostic tasks without needing heavyweight tools like Wireshark.

What is ConnArtist?

ConnArtist is a simple yet powerful PowerShell-based network monitoring tool built specifically for single endpoints. Perfect for quick checks by security analysts, sysadmins, or tech support, ConnArtist helps you swiftly identify unexpected or problematic network activity.

With ConnArtist, you can:

  • Log active TCP connections along with the responsible processes.
  • Optionally capture DNS queries made by the endpoint.
  • Filter out local (private) IP traffic for concise logs.
  • Continuously monitor and prevent redundant logging through smart duplicate detection.

How Does ConnArtist Work?

Here’s how it operates:

Initialization

The script prompts two straightforward questions:

  • Whether to filter local (private IP) traffic.
  • Whether to capture DNS queries.

Based on your responses, ConnArtist adjusts its monitoring appropriately.

Active Monitoring

ConnArtist continuously:

  • Logs active TCP connections, including detailed metadata (time, process, remote address, remote host).
  • Optionally logs DNS queries, capturing query names and timestamps.
  • Avoids duplicate entries by maintaining internal tracking.

Clear Logging

Data captured is neatly formatted and stored locally:

  • TCP connections logged to tcp_log.txt.
  • DNS queries stored in dns_log.txt.

Implementing ConnArtist

Step 1: Preparation

  • Save the provided PowerShell script as ConnArtist.ps1.
  • Ensure you have permissions to write logs (C:\Users\Public\).

Step 2: Execution

  • Run PowerShell as Administrator.

  • Execute the script:

    powershell.exe -ExecutionPolicy Bypass -File "C:\Path\To\ConnArtist.ps1"
    
  • Answer prompts regarding local traffic filtering and DNS capture based on your use-case.

Step 3: Continuous Monitoring

  • ConnArtist monitors the network every 5 seconds, providing real-time insights.
  • Press Ctrl+C to stop monitoring at any time.

Example Use Cases

  • Security Checks: Quickly identify unexpected external connections that could indicate malware or unauthorized activity.
  • Diagnostic Tasks: Troubleshoot connectivity issues by pinpointing problematic connections or DNS resolutions.

Customizing ConnArtist

Adjust log locations or intervals as needed:

$tcpLogFile = "C:\Users\Public\tcp_log.txt"
$dnsLogFile = "C:\Users\Public\dns_log.txt"

# Modify monitoring interval as desired
Start-Sleep -Seconds 5

Adjusting Local Network Filtering

For accurate filtering, you might need to customize your local network’s private IP ranges. Modify the following function to match your network’s octets:

function IsPrivateIP($ipAddress) {
    try {
        $ip = [System.Net.IPAddress]::Parse($ipAddress)
        if ($ip.AddressFamily -eq 'InterNetwork') { # IPv4
            return ($ipAddress -like '10.*' -or
                    $ipAddress -like '172.16.*' -or
                    $ipAddress -like '192.168.*') # Modify these octets to your local network range
        } elseif ($ip.AddressFamily -eq 'InterNetworkV6') { # IPv6
            return ($ip.IsIPv6LinkLocal -or $ip.IsIPv6SiteLocal)
        } else {
            return $false
        }
    } catch {
        return $false
    }
}

Why Use ConnArtist?

  • Lightweight: No installations or complex setups required.
  • Clear Insights: Straightforward, easily readable logs.
  • Focused: Designed for pinpoint checks on single endpoints.
  • Real-time Monitoring: Quick detection of unusual activities or connection issues.

ConnArtist simplifies endpoint network visibility, allowing quick identification of potential security concerns or troubleshooting network issues swiftly and effectively.

Happy Monitoring!

#Another        /\_[]_/\
#    fine      |] _||_ [|
#       ___     \/ || \/
#      /___\       ||
#     (|0 0|)      ||
#   __/{\U/}\_ ___/vvv
#  / \  {~}   / _|_P|
#  | /\  ~   /_/   []
#  |_| (____)        
#  \_]/______\  Barberion  
#     _\_||_/_     Production      
#    (_,_||_,_)
#
# Define log file paths for TCP and DNS logs
$tcpLogFile = "C:\Users\Public\tcp_log.txt"
$dnsLogFile = "C:\Users\Public\dns_log.txt"

# Function to check if an IP address is private
function IsPrivateIP($ipAddress) {
    try {
        $ip = [System.Net.IPAddress]::Parse($ipAddress)
        if ($ip.AddressFamily -eq 'InterNetwork') { # IPv4
            return ($ipAddress -like '10.*' -or
                    $ipAddress -like '172.16.*' -or
                    $ipAddress -like '192.168.*')
        } elseif ($ip.AddressFamily -eq 'InterNetworkV6') { # IPv6
            return ($ip.IsIPv6LinkLocal -or $ip.IsIPv6SiteLocal)
        } else {
            return $false
        }
    } catch {
        return $false
    }
}

# Ask the user if they want to filter out local traffic
$filterPrivateIPs = (Read-Host "Do you want to filter out local traffic? (yes/no)").Trim().ToLower()
$filterPrivate = $filterPrivateIPs -eq 'yes' -or $filterPrivateIPs -eq 'y'

# Ask the user if they want to capture DNS requests
$dnsCaptureInput = (Read-Host "Do you want to capture DNS requests? (yes/no)").Trim().ToLower()
$captureDNS = $dnsCaptureInput -eq 'yes' -or $dnsCaptureInput -eq 'y'

# Output the monitoring message at the top
Write-Host "Monitoring network connections. Press Ctrl+C to stop."
Add-Content -Path $tcpLogFile -Value "Monitoring TCP connections. Press Ctrl+C to stop."
Add-Content -Path $dnsLogFile -Value "Monitoring DNS connections. Press Ctrl+C to stop."

# Define the headers
$tcpHeader = "{0,-20} {1,-20} {2,-25} {3}" -f "Date/Time", "Process", "Remote Address", "Remote Host"
$dnsHeader = "{0,-20} {1,-30}" -f "Date/Time", "DNS Query"

Write-Host $tcpHeader
Write-Host ("-" * 90)
Add-Content -Path $tcpLogFile -Value $tcpHeader
Add-Content -Path $tcpLogFile -Value ("-" * 90)

if ($captureDNS) {
    $dnsLogName = "Microsoft-Windows-DNS-Client/Operational"
    if (-not (Get-WinEvent -ListLog $dnsLogName).IsEnabled) {
        Write-Host "Enabling DNS client operational log..."
        try {
            wevtutil sl $dnsLogName /e:true
        } catch {
            Write-Host "Failed to enable DNS client operational log. You may need to run PowerShell as Administrator."
            $captureDNS = $false
        }
    }
    if ($captureDNS) {
        # Initialize the last DNS check time
        $lastDNSCheckTime = Get-Date
        # Output the DNS header
        Write-Host $dnsHeader
        Write-Host ("-" * 50)
        Add-Content -Path $dnsLogFile -Value $dnsHeader
        Add-Content -Path $dnsLogFile -Value ("-" * 50)
    }
}

# To prevent duplication, maintain hashsets of logged connections and DNS queries
$loggedConnections = @{}
$loggedDNSQueries = @{}

while ($true) {
    # Get current network connections
    $currentConnections = Get-NetTCPConnection -State Established

    if ($filterPrivate) {
        $currentConnections = $currentConnections | Where-Object {
            $_.RemoteAddress -ne '127.0.0.1' -and
            $_.RemoteAddress -ne '::1'
        }
    }

    foreach ($conn in $currentConnections) {
        $connectionKey = "$($conn.OwningProcess)|$($conn.RemoteAddress):$($conn.RemotePort)"
        if (-not $loggedConnections.ContainsKey($connectionKey)) {
            if (-not $filterPrivate -or (-not (IsPrivateIP $conn.RemoteAddress))) {
                $dateTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
                $process = Get-Process -Id $conn.OwningProcess -ErrorAction SilentlyContinue
                $processName = if ($process) { $process.ProcessName } else { 'N/A' }
                $remoteHost = $conn.RemoteAddress
                try {
                    $dnsEntry = [System.Net.Dns]::GetHostEntry($conn.RemoteAddress)
                    $remoteHost = $dnsEntry.HostName
                } catch {
                    # Could not resolve host
                }
                $remoteAddressPort = "$($conn.RemoteAddress):$($conn.RemotePort)"
                $logEntry = "TCP {0,-20} {1,-20} {2,-25} {3}" -f $dateTime, $processName, $remoteAddressPort, $remoteHost
                Add-Content -Path $tcpLogFile -Value $logEntry
                Write-Host $logEntry
                # Add the connection to the loggedConnections hashset to prevent future duplicates
                $loggedConnections[$connectionKey] = $true
            }
        }
    }

    if ($captureDNS) {
        try {
            # Get new DNS query events
            $dnsEvents = Get-WinEvent -FilterHashtable @{
                LogName = 'Microsoft-Windows-DNS-Client/Operational';
                Id = 3008;
                StartTime = $lastDNSCheckTime
            } -ErrorAction SilentlyContinue
            
            if ($dnsEvents) {
                foreach ($event in $dnsEvents) {
                    $dateTime = $event.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss')
                    $queryName = $event.Properties[0].Value
                    if (-not $loggedDNSQueries.ContainsKey($queryName)) {
                        $dnsEntry = "DNS {0,-20} {1,-30}" -f $dateTime, $queryName
                        Add-Content -Path $dnsLogFile -Value $dnsEntry
                        Write-Host $dnsEntry
                        # Add the DNS query to the loggedDNSQueries hashset to prevent future duplicates
                        $loggedDNSQueries[$queryName] = $true
                    }
                }
                # Update the last DNS check time
                $lastDNSCheckTime = Get-Date
            }
        } catch {
            # Suppress any errors related to DNS event fetching
        }
    }

    Start-Sleep -Seconds 5
}

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button