From fa58485712a52204fa363e161ec13d106472c6db Mon Sep 17 00:00:00 2001 From: Hadi <112569860+anotherhadi@users.noreply.github.com> Date: Sat, 11 Apr 2026 21:29:59 +0200 Subject: [PATCH] init ghunt Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com> --- back/internal/registry/registry.go | 2 + back/internal/tools/ghunt/tool.go | 123 +++++++++++++++++++++++++++++ flake.lock | 12 +-- flake.nix | 4 +- 4 files changed, 134 insertions(+), 7 deletions(-) create mode 100644 back/internal/tools/ghunt/tool.go diff --git a/back/internal/registry/registry.go b/back/internal/registry/registry.go index 27cf3ca..d105539 100644 --- a/back/internal/registry/registry.go +++ b/back/internal/registry/registry.go @@ -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, diff --git a/back/internal/tools/ghunt/tool.go b/back/internal/tools/ghunt/tool.go new file mode 100644 index 0000000..a9d1725 --- /dev/null +++ b/back/internal/tools/ghunt/tool.go @@ -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 +} diff --git a/flake.lock b/flake.lock index 17e2472..ac0cd74 100644 --- a/flake.lock +++ b/flake.lock @@ -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": { diff --git a/flake.nix b/flake.nix index 3130d47..c604f29 100644 --- a/flake.nix +++ b/flake.nix @@ -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;