Add SSH artifacts collection (Get-SSHArtifacts.ps1)

Collect SSH forensic data: known hosts with counts, SSH config,
keys, authorized_keys, PuTTY sessions, and server logs.

Update TODO.md with completed scripts.
This commit is contained in:
2026-02-03 21:48:51 +01:00
parent 22c13d4633
commit dcebc0f4fa
2 changed files with 234 additions and 0 deletions

18
TODO.md
View File

@@ -10,6 +10,9 @@
- [x] Network Connection History
- [x] Hotspot Connections
- [x] Recent Documents (RecentDocs)
- [x] System Information (Get-Info.ps1)
- [x] User Accounts (Get-Users.ps1)
- [x] SSH sessions and known hosts
### User Activity Artifacts
- [ ] UserAssist - Programs run by user through Windows Explorer
@@ -48,6 +51,21 @@
- [ ] VPN connections
- [ ] Remote Desktop connections
### Developer & Security Artifacts
- [x] SSH sessions and known hosts
- [ ] Git repositories and commit history
- [ ] WSL (Windows Subsystem for Linux) artifacts
- [ ] PowerShell history (ConsoleHost_history.txt)
- [ ] Terminal/Command Prompt history
- [ ] Docker containers and images
- [ ] Virtual machines (VirtualBox, VMware, Hyper-V)
- [ ] IDE recent projects (VS Code, Visual Studio, JetBrains)
- [ ] Package manager caches (npm, pip, cargo, nuget)
- [ ] Environment variables and PATH modifications
- [ ] Installed development tools and SDKs
- [ ] Code signing certificates
- [ ] API keys and tokens in config files
## Other Operating Systems
### Linux

View File

@@ -0,0 +1,216 @@
# Get-SSHArtifacts.ps1
# Collects SSH session artifacts, known hosts, and configuration
param(
[switch]$ShowKeys
)
Write-Host "=== SSH Artifacts ===" -ForegroundColor Cyan
# Check common SSH directory locations
$sshPaths = @(
"$env:USERPROFILE\.ssh",
"$env:PROGRAMDATA\ssh"
)
$foundArtifacts = $false
foreach ($sshPath in $sshPaths) {
if (Test-Path $sshPath) {
$foundArtifacts = $true
Write-Host "`n--- SSH Directory: $sshPath ---" -ForegroundColor Yellow
# Known hosts
$knownHostsPath = Join-Path $sshPath "known_hosts"
if (Test-Path $knownHostsPath) {
Write-Host "`nKnown Hosts:" -ForegroundColor Green
try {
$knownHosts = Get-Content $knownHostsPath -ErrorAction SilentlyContinue
$hostCounts = @{}
foreach ($line in $knownHosts) {
if ($line -and -not $line.StartsWith("#")) {
# Extract hostname/IP (first field before space or comma)
$parts = $line -split '\s+', 2
if ($parts[0]) {
# Handle hashed hosts and comma-separated hosts
$hostname = $parts[0] -split ',' | Select-Object -First 1
if ($hostCounts.ContainsKey($hostname)) {
$hostCounts[$hostname]++
} else {
$hostCounts[$hostname] = 1
}
}
}
}
if ($hostCounts.Count -gt 0) {
$count = 0
foreach ($hostname in ($hostCounts.Keys | Sort-Object)) {
$count++
$appearances = $hostCounts[$hostname]
$plural = if ($appearances -eq 1) { "entry" } else { "entries" }
Write-Host " $count. $hostname ($appearances $plural)" -ForegroundColor Cyan
}
} else {
Write-Host " No hosts found" -ForegroundColor Gray
}
} catch {
Write-Host " Error reading known_hosts: $_" -ForegroundColor Red
}
}
# SSH Config
$configPath = Join-Path $sshPath "config"
if (Test-Path $configPath) {
Write-Host "`nSSH Config:" -ForegroundColor Green
try {
$config = Get-Content $configPath -ErrorAction SilentlyContinue
$currentHost = $null
foreach ($line in $config) {
$trimmed = $line.Trim()
if ($trimmed -match '^Host\s+(.+)') {
$currentHost = $matches[1]
Write-Host " Host: $currentHost" -ForegroundColor Yellow
} elseif ($currentHost -and $trimmed -match '^HostName\s+(.+)') {
Write-Host " Hostname: $($matches[1])" -ForegroundColor Cyan
} elseif ($currentHost -and $trimmed -match '^User\s+(.+)') {
Write-Host " User: $($matches[1])" -ForegroundColor Cyan
} elseif ($currentHost -and $trimmed -match '^Port\s+(.+)') {
Write-Host " Port: $($matches[1])" -ForegroundColor Cyan
} elseif ($currentHost -and $trimmed -match '^IdentityFile\s+(.+)') {
Write-Host " IdentityFile: $($matches[1])" -ForegroundColor Cyan
}
}
} catch {
Write-Host " Error reading config: $_" -ForegroundColor Red
}
}
# SSH Keys
Write-Host "`nSSH Keys:" -ForegroundColor Green
$keyFiles = Get-ChildItem -Path $sshPath -Filter "id_*" -ErrorAction SilentlyContinue
if ($keyFiles) {
foreach ($keyFile in $keyFiles) {
$isPrivate = $keyFile.Name -notmatch '\.pub$'
$keyType = if ($isPrivate) { "Private" } else { "Public" }
Write-Host " [$keyType] $($keyFile.Name)" -ForegroundColor $(if ($isPrivate) { "Red" } else { "Green" })
Write-Host " Path: $($keyFile.FullName)" -ForegroundColor Gray
Write-Host " Modified: $($keyFile.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Gray
# Show public key content if requested
if ($ShowKeys -and -not $isPrivate) {
try {
$content = Get-Content $keyFile.FullName -ErrorAction SilentlyContinue
if ($content) {
Write-Host " Content: $content" -ForegroundColor Cyan
}
} catch {
Write-Host " Error reading key: $_" -ForegroundColor Red
}
}
}
} else {
Write-Host " No SSH keys found" -ForegroundColor Gray
}
# Authorized keys
$authorizedKeysPath = Join-Path $sshPath "authorized_keys"
if (Test-Path $authorizedKeysPath) {
Write-Host "`nAuthorized Keys:" -ForegroundColor Green
try {
$authKeys = Get-Content $authorizedKeysPath -ErrorAction SilentlyContinue
$count = 0
foreach ($line in $authKeys) {
if ($line -and -not $line.StartsWith("#")) {
$count++
# Extract key type and comment
if ($line -match '^(ssh-\S+)\s+\S+\s*(.*)$') {
$keyType = $matches[1]
$comment = $matches[2]
Write-Host " $count. $keyType $(if ($comment) { "($comment)" })" -ForegroundColor Cyan
}
}
}
if ($count -eq 0) {
Write-Host " No authorized keys found" -ForegroundColor Gray
}
} catch {
Write-Host " Error reading authorized_keys: $_" -ForegroundColor Red
}
}
# List all other files in .ssh directory
Write-Host "`nOther Files:" -ForegroundColor Green
$otherFiles = Get-ChildItem -Path $sshPath -File -ErrorAction SilentlyContinue |
Where-Object { $_.Name -notin @('known_hosts', 'config', 'authorized_keys') -and $_.Name -notmatch '^id_' }
if ($otherFiles) {
foreach ($file in $otherFiles) {
Write-Host " $($file.Name) - Modified: $($file.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Cyan
}
} else {
Write-Host " No other files" -ForegroundColor Gray
}
}
}
# Check for PuTTY sessions (Windows alternative to OpenSSH)
Write-Host "`n--- PuTTY Sessions ---" -ForegroundColor Yellow
try {
$puttyPath = "HKCU:\Software\SimonTatham\PuTTY\Sessions"
if (Test-Path $puttyPath) {
$sessions = Get-ChildItem -Path $puttyPath -ErrorAction SilentlyContinue
if ($sessions) {
foreach ($session in $sessions) {
$sessionName = [System.Web.HttpUtility]::UrlDecode($session.PSChildName)
$props = Get-ItemProperty -Path $session.PSPath -ErrorAction SilentlyContinue
Write-Host "`nSession: $sessionName" -ForegroundColor Green
if ($props.HostName) { Write-Host " Hostname: $($props.HostName)" -ForegroundColor Cyan }
if ($props.UserName) { Write-Host " Username: $($props.UserName)" -ForegroundColor Cyan }
if ($props.PortNumber) { Write-Host " Port: $($props.PortNumber)" -ForegroundColor Cyan }
if ($props.Protocol) { Write-Host " Protocol: $($props.Protocol)" -ForegroundColor Cyan }
}
} else {
Write-Host "No PuTTY sessions found" -ForegroundColor Gray
}
} else {
Write-Host "PuTTY not installed or no sessions configured" -ForegroundColor Gray
}
} catch {
Write-Host "Error reading PuTTY registry: $_" -ForegroundColor Red
}
# Check for Windows OpenSSH Server logs
Write-Host "`n--- OpenSSH Server Logs ---" -ForegroundColor Yellow
$sshServerLog = "$env:ProgramData\ssh\logs\sshd.log"
if (Test-Path $sshServerLog) {
Write-Host "Server log found: $sshServerLog" -ForegroundColor Green
try {
$recentLogs = Get-Content $sshServerLog -Tail 20 -ErrorAction SilentlyContinue
Write-Host "`nRecent log entries (last 20 lines):" -ForegroundColor Cyan
$recentLogs | ForEach-Object {
Write-Host " $_" -ForegroundColor Gray
}
} catch {
Write-Host "Error reading log: $_" -ForegroundColor Red
}
} else {
Write-Host "No OpenSSH server logs found" -ForegroundColor Gray
}
if (-not $foundArtifacts) {
Write-Host "`nNo SSH artifacts found" -ForegroundColor Gray
Write-Host "SSH might not be configured on this system" -ForegroundColor Gray
}
Write-Host "`nNote: Use -ShowKeys to display public key contents" -ForegroundColor Cyan
Write-Host "Private keys are never displayed for security reasons" -ForegroundColor Cyan