init ghunt

Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
This commit is contained in:
Hadi
2026-04-11 21:29:59 +02:00
parent a0fceb36df
commit fa58485712
4 changed files with 134 additions and 7 deletions

View File

@@ -3,6 +3,7 @@ package registry
import (
"github.com/anotherhadi/iknowyou/internal/tools"
breachdirectory "github.com/anotherhadi/iknowyou/internal/tools/breachdirectory"
ghunt "github.com/anotherhadi/iknowyou/internal/tools/ghunt"
crtsh "github.com/anotherhadi/iknowyou/internal/tools/crtsh"
digtool "github.com/anotherhadi/iknowyou/internal/tools/dig"
githubrecon "github.com/anotherhadi/iknowyou/internal/tools/github-recon"
@@ -25,6 +26,7 @@ var Factories = []func() tools.ToolRunner{
gravatarrecon.New,
whoisfreaks.New,
maigret.New,
ghunt.New,
leakcheck.New,
crtsh.New,
breachdirectory.New,

View File

@@ -0,0 +1,123 @@
package ghunt
import (
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"github.com/anotherhadi/iknowyou/internal/tools"
)
var ansiRe = regexp.MustCompile(`\x1b[\x5b-\x5f][0-9;]*[A-Za-z]|\x1b[^[\x5b-\x5f]`)
const (
name = "ghunt"
description = "Google account OSINT via GHunt. Extracts profile info, linked services, and activity from a Google email address."
link = "https://github.com/mxrch/GHunt"
icon = "google"
)
type Config struct {
Creds string `yaml:"creds" iky:"desc=GHunt credentials (content of ~/.malfrats/ghunt/creds.m). To obtain: (1) install GHunt and run 'ghunt login' on your machine, (2) copy the full content of ~/.malfrats/ghunt/creds.m, (3) paste it here.;required=true"`
}
type Runner struct {
cfg Config
}
func New() tools.ToolRunner {
cfg := Config{}
tools.ApplyDefaults(&cfg)
return &Runner{cfg: cfg}
}
func (r *Runner) Name() string { return name }
func (r *Runner) Description() string { return description }
func (r *Runner) Link() string { return link }
func (r *Runner) Icon() string { return icon }
func (r *Runner) InputTypes() []tools.InputType {
return []tools.InputType{
tools.InputTypeEmail,
}
}
func (r *Runner) ConfigPtr() interface{} { return &r.cfg }
func (r *Runner) ConfigFields() []tools.ConfigField {
return tools.ReflectConfigFields(r.cfg)
}
func (r *Runner) Available() (bool, string) {
if _, err := exec.LookPath("ghunt"); err != nil {
return false, "ghunt binary not found in PATH"
}
return true, ""
}
func (r *Runner) Dependencies() []string { return []string{"ghunt"} }
func (r *Runner) writeCreds() error {
home, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("cannot determine home directory: %w", err)
}
dir := filepath.Join(home, ".malfrats", "ghunt")
if err := os.MkdirAll(dir, 0700); err != nil {
return fmt.Errorf("cannot create ghunt dir: %w", err)
}
return os.WriteFile(filepath.Join(dir, "creds.m"), []byte(r.cfg.Creds), 0600)
}
func (r *Runner) Run(ctx context.Context, target string, _ tools.InputType, out chan<- tools.Event) error {
defer close(out)
if err := r.writeCreds(); err != nil {
out <- tools.Event{Tool: name, Type: tools.EventTypeError, Payload: err.Error()}
out <- tools.Event{Tool: name, Type: tools.EventTypeDone}
return nil
}
cmd := exec.CommandContext(ctx, "ghunt", "email", target)
output, err := tools.RunWithPTY(ctx, cmd)
output = strings.ReplaceAll(output, "\r\n", "\n")
output = strings.ReplaceAll(output, "\r", "\n")
lines := strings.Split(output, "\n")
parsed := make([]string, len(lines))
for i, l := range lines {
parsed[i] = ansiRe.ReplaceAllString(l, "")
}
start := 0
for i, l := range parsed {
if strings.Contains(l, "[+] Authenticated !") {
start = i + 1
break
}
}
end := len(lines)
for i := start; i < len(parsed); i++ {
if strings.Contains(parsed[i], "Traceback (most recent call last)") {
end = i
break
}
}
output = strings.TrimSpace(strings.Join(lines[start:end], "\n"))
if err != nil && ctx.Err() != nil {
out <- tools.Event{Tool: name, Type: tools.EventTypeError, Payload: "scan cancelled"}
} else if output != "" {
out <- tools.Event{Tool: name, Type: tools.EventTypeOutput, Payload: output}
out <- tools.Event{Tool: name, Type: tools.EventTypeCount, Payload: 1}
}
out <- tools.Event{Tool: name, Type: tools.EventTypeDone}
return nil
}

12
flake.lock generated
View File

@@ -59,11 +59,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1775036866,
"narHash": "sha256-ZojAnPuCdy657PbTq5V0Y+AHKhZAIwSIT2cb8UgAz/U=",
"lastModified": 1775710090,
"narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "6201e203d09599479a3b3450ed24fa81537ebc4e",
"rev": "4c1018dae018162ec878d42fec712642d214fdfa",
"type": "github"
},
"original": {
@@ -95,11 +95,11 @@
]
},
"locked": {
"lastModified": 1774035694,
"narHash": "sha256-PtORnAJ/SKeOwrPAjZ0LR00Pu8aDIzXO8H8v9CoM7zk=",
"lastModified": 1775935554,
"narHash": "sha256-7StMiQf3HSBruAxZ2/ZYJhhNEp1KbglGVijQBrurqiM=",
"owner": "anotherhadi",
"repo": "nur-osint",
"rev": "813351d47721d411441bb6221faf2c6163846946",
"rev": "460e377522a43d3d968be20bec2cf40a72013904",
"type": "github"
},
"original": {

View File

@@ -35,7 +35,9 @@
dnsutils
maigret
nur-osint.packages.${system}.user-scanner
nur-osint.packages.${system}.gravatar-recon
nur-osint.packages.${system}.github-recon
nur-osint.packages.${system}.ghunt
];
ikyPkg = pkgs.symlinkJoin {
@@ -50,7 +52,7 @@
'';
};
in {
nixosModules.default = import ./nix/module.nix { inherit self; };
nixosModules.default = import ./nix/module.nix {inherit self;};
packages.${system} = {
backend = backendPkg;