mirror of
https://github.com/anotherhadi/github-recon.git
synced 2026-10-05 10:58:25 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98769561c3 | ||
|
|
c76953882c | ||
|
|
94fd83ecce | ||
|
|
2d01c1639f | ||
|
|
66030c1c16 | ||
|
|
bb8f34055d | ||
|
|
26a1cfdd37 |
@@ -98,7 +98,7 @@ nix run github:anotherhadi/github-recon -- [--flags value] target_username_or_em
|
|||||||
|
|
||||||
# then add it to your packages
|
# then add it to your packages
|
||||||
environment.systemPackages = with pkgs; [ # or home.packages
|
environment.systemPackages = with pkgs; [ # or home.packages
|
||||||
github-recon
|
inputs.github-recon.defaultPackage.${pkgs.system}
|
||||||
];
|
];
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type EmailResult struct {
|
|||||||
TargetType github_recon_settings.TargetType
|
TargetType github_recon_settings.TargetType
|
||||||
|
|
||||||
Commits CommitsResult
|
Commits CommitsResult
|
||||||
Spoofing SpoofingResult
|
Spoofing *SpoofingResult
|
||||||
}
|
}
|
||||||
|
|
||||||
func Email(settings github_recon_settings.Settings) EmailResult {
|
func Email(settings github_recon_settings.Settings) EmailResult {
|
||||||
@@ -33,7 +33,7 @@ func Email(settings github_recon_settings.Settings) EmailResult {
|
|||||||
} else {
|
} else {
|
||||||
utils.PrintTitle(settings.Silent, "🎭 Spoofing test")
|
utils.PrintTitle(settings.Silent, "🎭 Spoofing test")
|
||||||
result.Spoofing = Spoofing(settings)
|
result.Spoofing = Spoofing(settings)
|
||||||
if result.Spoofing.AvatarURL != "" {
|
if result.Spoofing != nil && result.Spoofing.AvatarURL != "" {
|
||||||
utils.PrintAvatar(settings, result.Spoofing.AvatarURL)
|
utils.PrintAvatar(settings, result.Spoofing.AvatarURL)
|
||||||
}
|
}
|
||||||
utils.PrintStruct(settings, result.Spoofing, 0)
|
utils.PrintStruct(settings, result.Spoofing, 0)
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ func RandomString(n int) string {
|
|||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Spoofing(s github_recon_settings.Settings) (response SpoofingResult) {
|
func Spoofing(s github_recon_settings.Settings) (response *SpoofingResult) {
|
||||||
|
response = &SpoofingResult{}
|
||||||
name := "gh-recon-spoofing-" + RandomString(8)
|
name := "gh-recon-spoofing-" + RandomString(8)
|
||||||
private := true
|
private := true
|
||||||
autoInit := true
|
autoInit := true
|
||||||
@@ -41,6 +42,13 @@ func Spoofing(s github_recon_settings.Settings) (response SpoofingResult) {
|
|||||||
}
|
}
|
||||||
utils.WaitForRateLimit(s, resp)
|
utils.WaitForRateLimit(s, resp)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_, err = s.Client.Repositories.Delete(s.Ctx, repo.Owner.GetLogin(), name)
|
||||||
|
if err != nil {
|
||||||
|
s.Logger.Error("Error while deleting repo", "err", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
branch := repo.GetDefaultBranch()
|
branch := repo.GetDefaultBranch()
|
||||||
if branch == "" {
|
if branch == "" {
|
||||||
branch = "main"
|
branch = "main"
|
||||||
@@ -57,7 +65,6 @@ func Spoofing(s github_recon_settings.Settings) (response SpoofingResult) {
|
|||||||
ref, resp, err := s.Client.Git.GetRef(s.Ctx, repo.Owner.GetLogin(), name, refName)
|
ref, resp, err := s.Client.Git.GetRef(s.Ctx, repo.Owner.GetLogin(), name, refName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.Logger.Error("Error while getting ref", "err", err)
|
s.Logger.Error("Error while getting ref", "err", err)
|
||||||
s.Logger.Warn("The temp repo was left undeleted", "repo", repo.GetHTMLURL())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
utils.WaitForRateLimit(s, resp)
|
utils.WaitForRateLimit(s, resp)
|
||||||
@@ -65,7 +72,6 @@ func Spoofing(s github_recon_settings.Settings) (response SpoofingResult) {
|
|||||||
parentCommit, resp, err := s.Client.Git.GetCommit(s.Ctx, repo.Owner.GetLogin(), name, ref.GetObject().GetSHA())
|
parentCommit, resp, err := s.Client.Git.GetCommit(s.Ctx, repo.Owner.GetLogin(), name, ref.GetObject().GetSHA())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.Logger.Error("Error while getting parent commit", "err", err)
|
s.Logger.Error("Error while getting parent commit", "err", err)
|
||||||
s.Logger.Warn("The temp repo was left undeleted", "repo", repo.GetHTMLURL())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
utils.WaitForRateLimit(s, resp)
|
utils.WaitForRateLimit(s, resp)
|
||||||
@@ -81,7 +87,6 @@ func Spoofing(s github_recon_settings.Settings) (response SpoofingResult) {
|
|||||||
newCommit, resp, err := s.Client.Git.CreateCommit(s.Ctx, repo.Owner.GetLogin(), name, commit, nil)
|
newCommit, resp, err := s.Client.Git.CreateCommit(s.Ctx, repo.Owner.GetLogin(), name, commit, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.Logger.Error("Error while creating spoofed empty commit", "err", err)
|
s.Logger.Error("Error while creating spoofed empty commit", "err", err)
|
||||||
s.Logger.Warn("The temp repo was left undeleted", "repo", repo.GetHTMLURL())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
utils.WaitForRateLimit(s, resp)
|
utils.WaitForRateLimit(s, resp)
|
||||||
@@ -90,7 +95,6 @@ func Spoofing(s github_recon_settings.Settings) (response SpoofingResult) {
|
|||||||
_, resp, err = s.Client.Git.UpdateRef(s.Ctx, repo.Owner.GetLogin(), name, ref, false)
|
_, resp, err = s.Client.Git.UpdateRef(s.Ctx, repo.Owner.GetLogin(), name, ref, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.Logger.Error("Error while updating ref to spoofed commit", "err", err)
|
s.Logger.Error("Error while updating ref to spoofed commit", "err", err)
|
||||||
s.Logger.Warn("The temp repo was left undeleted", "repo", repo.GetHTMLURL())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
utils.WaitForRateLimit(s, resp)
|
utils.WaitForRateLimit(s, resp)
|
||||||
@@ -98,23 +102,22 @@ func Spoofing(s github_recon_settings.Settings) (response SpoofingResult) {
|
|||||||
commits, _, err := s.Client.Repositories.ListCommits(s.Ctx, repo.Owner.GetLogin(), name, nil)
|
commits, _, err := s.Client.Repositories.ListCommits(s.Ctx, repo.Owner.GetLogin(), name, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.Logger.Error("Error while listing commits", "err", err)
|
s.Logger.Error("Error while listing commits", "err", err)
|
||||||
s.Logger.Warn("The temp repo was left undeleted", "repo", repo.GetHTMLURL())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(commits) > 0 {
|
if len(commits) > 1 {
|
||||||
last := commits[0]
|
last := commits[0]
|
||||||
response.Username = last.GetAuthor().GetLogin()
|
response.Username = last.GetAuthor().GetLogin()
|
||||||
response.Name = last.GetAuthor().GetName()
|
response.Name = last.GetAuthor().GetName()
|
||||||
response.Email = last.GetAuthor().GetEmail()
|
response.Email = last.GetAuthor().GetEmail()
|
||||||
response.Url = last.GetAuthor().GetHTMLURL()
|
response.Url = last.GetAuthor().GetHTMLURL()
|
||||||
response.AvatarURL = last.GetAuthor().GetAvatarURL()
|
response.AvatarURL = last.GetAuthor().GetAvatarURL()
|
||||||
|
} else {
|
||||||
|
s.Logger.Error("Only one commit found, something went wrong.", "commits", commits)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = s.Client.Repositories.Delete(s.Ctx, repo.Owner.GetLogin(), name)
|
if response.Username == "" && response.Name == "" && response.Email == "" {
|
||||||
if err != nil {
|
return nil
|
||||||
s.Logger.Error("Error while deleting repo", "err", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ import (
|
|||||||
type CloseFriendsResult []CloseFriendResult
|
type CloseFriendsResult []CloseFriendResult
|
||||||
|
|
||||||
type CloseFriendResult struct {
|
type CloseFriendResult struct {
|
||||||
|
Name string
|
||||||
Username string
|
Username string
|
||||||
|
Orgs []string
|
||||||
|
Company string
|
||||||
|
Location string
|
||||||
Score int
|
Score int
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,8 +100,12 @@ func CloseFriends(s github_recon_settings.Settings) (results CloseFriendsResult)
|
|||||||
// Add candidate if they matched at least one condition
|
// Add candidate if they matched at least one condition
|
||||||
if score > 0 {
|
if score > 0 {
|
||||||
results = append(results, CloseFriendResult{
|
results = append(results, CloseFriendResult{
|
||||||
|
Name: candidateDetails.GetName(),
|
||||||
Username: candidateLogin,
|
Username: candidateLogin,
|
||||||
|
Orgs: candidateOrgsToNames(candidateOrgs),
|
||||||
Score: score,
|
Score: score,
|
||||||
|
Location: candidateDetails.GetLocation(),
|
||||||
|
Company: candidateDetails.GetCompany(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,6 +138,15 @@ func checkIfUserFollows(s github_recon_settings.Settings, sourceUser, targetUser
|
|||||||
}
|
}
|
||||||
return isFollowing, nil
|
return isFollowing, nil
|
||||||
}
|
}
|
||||||
|
func candidateOrgsToNames(orgs []*github.Organization) []string {
|
||||||
|
var orgNames []string
|
||||||
|
for _, org := range orgs {
|
||||||
|
if org.GetLogin() != "" {
|
||||||
|
orgNames = append(orgNames, org.GetLogin())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return orgNames
|
||||||
|
}
|
||||||
|
|
||||||
func getOrgs(s github_recon_settings.Settings, user string) ([]*github.Organization, error) {
|
func getOrgs(s github_recon_settings.Settings, user string) ([]*github.Organization, error) {
|
||||||
orgs, resp, err := s.Client.Organizations.List(s.Ctx, user, nil)
|
orgs, resp, err := s.Client.Organizations.List(s.Ctx, user, nil)
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ func DeepScan(s github_recon_settings.Settings) (response DeepScanResult) {
|
|||||||
Name: authorName,
|
Name: authorName,
|
||||||
Email: authorEmail,
|
Email: authorEmail,
|
||||||
FoundIn: []string{repoIdentifier},
|
FoundIn: []string{repoIdentifier},
|
||||||
Levenshtein: utils.LevenshteinDistance(s.Target, authorName),
|
Levenshtein: levenshteinDistanceAuthor(s.Target, authorName, authorEmail),
|
||||||
})
|
})
|
||||||
mapAuthorToIndex[trimmedLine] = len(authorOccurrences) - 1
|
mapAuthorToIndex[trimmedLine] = len(authorOccurrences) - 1
|
||||||
}
|
}
|
||||||
@@ -334,13 +334,13 @@ func findEmailsAndOccurrencesInDir(rootPath string, username string) (Emails, er
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !d.IsDir() {
|
if d.Type().IsRegular() {
|
||||||
if strings.Contains(path, ".git/logs/") {
|
if strings.Contains(path, ".git/logs/") {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
content, err := os.ReadFile(path)
|
content, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
currentFileEmails := emailRegex.FindAllString(string(content), -1)
|
currentFileEmails := emailRegex.FindAllString(string(content), -1)
|
||||||
@@ -380,3 +380,10 @@ func findEmailsAndOccurrencesInDir(rootPath string, username string) (Emails, er
|
|||||||
|
|
||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func levenshteinDistanceAuthor(target, name, email string) int {
|
||||||
|
if strings.Contains(email, "@") {
|
||||||
|
email = strings.SplitN(email, "@", 2)[0]
|
||||||
|
}
|
||||||
|
return slices.Min([]int{utils.LevenshteinDistance(target, name), utils.LevenshteinDistance(target, email)})
|
||||||
|
}
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ func GetSettings() (settings Settings) {
|
|||||||
|
|
||||||
// If token is not set via flag, get it from env
|
// If token is not set via flag, get it from env
|
||||||
if settings.Token == "null" || settings.Token == "" {
|
if settings.Token == "null" || settings.Token == "" {
|
||||||
settings.Token = getToken()
|
settings.Token = GetToken()
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.Token == "null" || settings.Token == "" {
|
if settings.Token == "null" || settings.Token == "" {
|
||||||
|
|||||||
+2
-1
@@ -9,7 +9,8 @@ import (
|
|||||||
flag "github.com/spf13/pflag"
|
flag "github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getToken() string {
|
// GetToken retrieves the GitHub token from the environment variable or config file
|
||||||
|
func GetToken() string {
|
||||||
token := os.Getenv("GITHUB_RECON_TOKEN")
|
token := os.Getenv("GITHUB_RECON_TOKEN")
|
||||||
if token != "" {
|
if token != "" {
|
||||||
return token
|
return token
|
||||||
|
|||||||
+3
-1
@@ -57,7 +57,9 @@ func PrintStruct(settings github_recon_settings.Settings, s any, indent int) {
|
|||||||
for i := 0; i < v.NumField(); i++ {
|
for i := 0; i < v.NumField(); i++ {
|
||||||
field := t.Field(i).Name
|
field := t.Field(i).Name
|
||||||
value := v.Field(i)
|
value := v.Field(i)
|
||||||
|
if !value.CanInterface() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if !value.IsValid() || (value.Kind() == reflect.String && value.String() == "") {
|
if !value.IsValid() || (value.Kind() == reflect.String && value.String() == "") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user