Skip to content

Commit bc6d5c0

Browse files
Improve extensibility
Move all regexes to config file. No more special processing. Store collected data as values not keys.
1 parent 4009a22 commit bc6d5c0

File tree

3 files changed

+72
-138
lines changed

3 files changed

+72
-138
lines changed

config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type Regex struct {
1919
Regex string
2020
compiled *regexp.Regexp
2121
Prefix string
22+
Match string
2223
}
2324

2425
type Config struct {

config.json

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,46 @@
66
"github_token": "github_api_token",
77
"save": true,
88
"buckets": [
9-
"awskeys",
10-
"emails",
11-
"creds",
12-
"privkeys",
139
"keywords",
1410
"regexes",
1511
"pastes"
1612
],
1713
"regexes": [
18-
{"regex": "\\$[0-9]\\$[a-zA-Z0-9]\\$[a-zA-Z0-9./=]+", "prefix": "pwhash"},
19-
{"regex": "[a-zA-Z0-9]+::[a-zA-Z0-9]{10}:[a-z0-9]{32}:[a-z0-9-]+", "prefix": "pwhash"},
20-
{"regex": "[a-zA-Z0-9-_]+:[0-9]+:[a-z0-9]{32}:[a-z0-9]{32}", "prefix": "pwhash"},
21-
{"regex": "CVE-[0-9]{4}-[0-9]{4,5}", "prefix": "exploit"}
14+
{
15+
"regex": "(?m)^([a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]+):([^ ~/$| ].*$)",
16+
"prefix": "creds",
17+
"match": "all"
18+
},
19+
{
20+
"regex": "[a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}",
21+
"prefix": "email",
22+
"match": "all"
23+
},
24+
{
25+
"regex": "(?s)BEGIN (RSA|DSA|) PRIVATE KEY.*END (RSA|DSA|) PRIVATE KEY",
26+
"prefix": "privkey",
27+
"match": "all"
28+
},
29+
{
30+
"regex": "\\$[0-9]\\$[a-zA-Z0-9]+\\$[a-zA-Z0-9./=]+",
31+
"prefix": "pwhash",
32+
"match": "all"
33+
},
34+
{
35+
"regex": "[a-zA-Z0-9]+::[a-zA-Z0-9]{10}:[a-z0-9]{32}:[a-z0-9-]+",
36+
"prefix": "pwhash",
37+
"match": "all"
38+
},
39+
{
40+
"regex": "[a-zA-Z0-9-_]+:[0-9]+:[a-z0-9]{32}:[a-z0-9]{32}",
41+
"prefix": "pwhash",
42+
"match": "all"
43+
},
44+
{
45+
"regex": "CVE-[0-9]{4}-[0-9]{4,5}",
46+
"prefix": "exploit",
47+
"match": "one"
48+
}
2249
],
2350
"keywords": [
2451
{"keyword": "`password`", "prefix": "sqlpass"},

process.go

Lines changed: 36 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -2,153 +2,64 @@ package main
22

33
import (
44
"fmt"
5-
"regexp"
65
"strings"
76
)
87

9-
var reCreds = regexp.MustCompile("(?m)^([a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]+):([^ ~/$| ].*$)")
10-
var reEmail = regexp.MustCompile("[a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]+")
11-
var rePrivKey = regexp.MustCompile("(?s)BEGIN (RSA|DSA|) PRIVATE KEY.*END (RSA|DSA|) PRIVATE KEY")
12-
var reAwsKey = regexp.MustCompile("(?is)(AKIA[A-Z0-9]{16})[\"',: =]+([A-Za-z0-9+/]{40})")
13-
var reBase64 = regexp.MustCompile("^([a-zA-Z0-9+/]+)$")
14-
15-
// Find AWS access keys and secrets
16-
func processAWSKeys(contents, key string) bool {
17-
// Base64 content yields false positives. Skip documents that are only Base64
18-
if b64 := reBase64.FindString(contents); b64 != "" {
19-
return false
20-
}
21-
22-
awsKeys := reAwsKey.FindAllStringSubmatch(contents, -1)
23-
24-
// No keys found.
25-
if awsKeys == nil {
26-
return false
27-
}
28-
29-
for _, awsKey := range awsKeys {
30-
conf.ds.Write("awskeys", strings.Join(awsKey[1:], ":"), []byte(key))
31-
}
32-
33-
return true
34-
}
35-
36-
// Look for email addresses and save them to a file.
37-
func processEmails(contents, key string) bool {
38-
emails := reEmail.FindAllString(contents, -1)
39-
40-
// No emails found.
41-
if emails == nil {
42-
return false
43-
}
44-
45-
for _, email := range emails {
46-
email = cleanEmail(email)
47-
48-
if email == "" {
49-
continue
50-
}
51-
52-
conf.ds.Write("emails", email, []byte(key))
53-
}
54-
55-
return true
56-
}
57-
58-
// Look for credentials in the format of email:password and save them to a file.
59-
func processCredentials(contents, key string) bool {
60-
creds := reCreds.FindAllString(contents, -1)
61-
62-
// No creds found.
63-
if creds == nil {
64-
return false
65-
}
66-
67-
for _, cred := range creds {
68-
if cred == "" {
69-
continue
70-
}
71-
72-
conf.ds.Write("creds", cred, []byte(key))
73-
}
74-
75-
return true
76-
}
77-
78-
// Look for private keys.
79-
func processPrivKey(contents, key string) bool {
80-
privKeys := rePrivKey.FindAllString(contents, -1)
81-
82-
// No keys found.
83-
if privKeys == nil {
84-
return false
85-
}
86-
87-
for _, privKey := range privKeys {
88-
conf.ds.Write("privkeys", privKey, []byte(key))
89-
}
90-
91-
return true
92-
}
93-
94-
func savePaste(key, value string) {
8+
func savePaste(key, content string) {
959
if conf.Save == false {
9610
return
9711
}
9812

99-
if len(value) > conf.MaxSize {
13+
if len(content) > conf.MaxSize {
10014
return
10115
}
10216

103-
conf.ds.Write("pastes", key, []byte(value))
17+
conf.ds.Write("pastes", key, []byte(content))
10418
}
10519

106-
func processContent(key, content string) {
107-
conf.ds = getStoreConn()
108-
defer conf.ds.Close()
109-
110-
// Find and save specific data.
111-
switch {
112-
case processCredentials(content, key):
113-
savePaste(key, content)
114-
case processEmails(content, key):
115-
savePaste(key, content)
116-
case processPrivKey(content, key):
117-
savePaste(key, content)
118-
case processAWSKeys(content, key):
119-
savePaste(key, content)
120-
default:
121-
}
122-
123-
// Save pastes that match any of our regular expressions. Use these to find
124-
// interesting data that will eventually be processed with a more specific
125-
// method.
20+
func processRegexes(key, content string) {
12621
save := false
12722
for i, _ := range conf.Regexes {
12823
r := conf.Regexes[i]
129-
rKey := fmt.Sprintf("%s-%s", r.Prefix, key)
130-
match := r.compiled.FindString(content)
13124

132-
if match != "" {
133-
save = true
134-
conf.ds.Write("regexes", rKey, nil)
25+
switch r.Match {
26+
case "all":
27+
items := r.compiled.FindAllString(content, -1)
28+
29+
if items != nil {
30+
save = true
31+
}
32+
33+
for k := range items {
34+
rKey := fmt.Sprintf("%s-%s-%d", r.Prefix, key, k)
35+
conf.ds.Write("regexes", rKey, []byte(items[k]))
36+
}
37+
case "one":
38+
match := r.compiled.FindString(content)
39+
rKey := fmt.Sprintf("%s-%s", r.Prefix, key)
40+
41+
if match != "" {
42+
save = true
43+
conf.ds.Write("regexes", rKey, []byte(match))
44+
}
45+
default:
13546
}
13647
}
13748

13849
if save {
13950
savePaste(key, content)
14051
}
52+
}
14153

142-
// Save pastes that match any of our keywords. Use these to find interesting
143-
// data that will eventually be processed with a more specific method.
144-
save = false
54+
func processKeywords(key, content string) {
55+
save := false
14556
for i, _ := range conf.Keywords {
14657
kwd := conf.Keywords[i]
14758
kwdKey := fmt.Sprintf("%s-%s", kwd.Prefix, key)
14859

14960
if strings.Contains(strings.ToLower(content), strings.ToLower(kwd.Keyword)) {
15061
save = true
151-
conf.ds.Write("keywords", kwdKey, nil)
62+
conf.ds.Write("keywords", kwdKey, []byte(key))
15263
}
15364
}
15465

@@ -157,16 +68,11 @@ func processContent(key, content string) {
15768
}
15869
}
15970

160-
// Remove common false positives in email addresses.
161-
func cleanEmail(email string) string {
162-
email = strings.ToLower(email)
163-
164-
switch {
165-
case strings.HasSuffix(email, "2x.png"):
166-
return ""
167-
case strings.HasSuffix(email, ".so"):
168-
return ""
169-
default:
170-
return email
171-
}
71+
72+
func processContent(key, content string) {
73+
conf.ds = getStoreConn()
74+
defer conf.ds.Close()
75+
76+
processRegexes(key, content)
77+
processKeywords(key, content)
17278
}

0 commit comments

Comments
 (0)