36b3af2e3d
PR Check / Code Quality: Format (push) Failing after 1s
PR Check / Code Quality: Lint (darwin) (push) Failing after 0s
PR Check / Code Quality: Lint (freebsd) (push) Failing after 1s
PR Check / Code Quality: Lint (windows) (push) Failing after 1s
PR Check / Code Quality: Lint (linux) (push) Failing after 1s
PR Check / Security: Vulnerability Scan (push) Failing after 0s
Update Documentation / update-docs (push) Failing after 2s
PR Check / Code Quality: Vendor (push) Failing after 1s
PR Check / Code Quality: Coverage (push) Failing after 0s
PR Check / Tests: Unit (macos-latest) (push) Has been cancelled
PR Check / Tests: Unit (ubuntu-24.04) (push) Has been cancelled
PR Check / Tests: Unit (ubuntu-24.04-arm) (push) Has been cancelled
PR Check / Tests: Unit (windows-latest) (push) Has been cancelled
77 lines
1.7 KiB
Go
77 lines
1.7 KiB
Go
package source
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/pranshuparmar/witr/pkg/model"
|
|
)
|
|
|
|
func detectSSH(ancestry []model.Process) *model.Source {
|
|
if len(ancestry) < 2 {
|
|
return nil
|
|
}
|
|
|
|
// Look for sshd in the ancestry chain (excluding the target itself)
|
|
hasSSHD := false
|
|
for i := 0; i < len(ancestry)-1; i++ {
|
|
base := filepath.Base(ancestry[i].Command)
|
|
if base == "sshd" || base == "sshd.exe" || strings.HasPrefix(base, "sshd:") {
|
|
hasSSHD = true
|
|
break
|
|
}
|
|
}
|
|
if !hasSSHD {
|
|
return nil
|
|
}
|
|
|
|
// Extract SSH connection details from environment variables.
|
|
// Check all processes in the chain (target first, then ancestors) because
|
|
// su/sudo create clean login shells that don't inherit SSH_* vars.
|
|
target := ancestry[len(ancestry)-1]
|
|
var remoteIP, tty string
|
|
|
|
for i := len(ancestry) - 1; i >= 0 && remoteIP == ""; i-- {
|
|
for _, entry := range ancestry[i].Env {
|
|
key, val, ok := strings.Cut(entry, "=")
|
|
if !ok {
|
|
continue
|
|
}
|
|
switch key {
|
|
case "SSH_CLIENT":
|
|
if fields := strings.Fields(val); len(fields) >= 1 {
|
|
remoteIP = fields[0]
|
|
}
|
|
case "SSH_CONNECTION":
|
|
if remoteIP == "" {
|
|
if fields := strings.Fields(val); len(fields) >= 1 {
|
|
remoteIP = fields[0]
|
|
}
|
|
}
|
|
case "SSH_TTY":
|
|
if tty == "" {
|
|
tty = val
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
desc := "SSH session"
|
|
if remoteIP != "" {
|
|
if tty != "" {
|
|
desc = fmt.Sprintf("SSH session from %s (%s@%s)", remoteIP, target.User, strings.TrimPrefix(tty, "/dev/"))
|
|
} else if target.User != "" {
|
|
desc = fmt.Sprintf("SSH session from %s (%s)", remoteIP, target.User)
|
|
} else {
|
|
desc = fmt.Sprintf("SSH session from %s", remoteIP)
|
|
}
|
|
}
|
|
|
|
return &model.Source{
|
|
Type: model.SourceSSH,
|
|
Name: "sshd",
|
|
Description: desc,
|
|
}
|
|
}
|