mirror of https://github.com/gophish/gophish
Added support for reporting campaign emails as attachments
parent
b888c37346
commit
920f61d2ee
|
@ -14,12 +14,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/gophish/gophish/logger"
|
log "github.com/gophish/gophish/logger"
|
||||||
|
"github.com/jordan-wright/email"
|
||||||
|
|
||||||
"github.com/gophish/gophish/models"
|
"github.com/gophish/gophish/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pattern for GoPhish emails e.g ?rid=AbC123
|
// Pattern for GoPhish emails e.g ?rid=AbC123
|
||||||
var goPhishRegex = regexp.MustCompile("(\\?rid=[A-Za-z0-9]{7})")
|
var goPhishRegex = regexp.MustCompile("(\\?rid=(3D)?([A-Za-z0-9]{7}))") // We include the optional quoted-printable 3D at the front, just in case decoding fails
|
||||||
|
|
||||||
// Monitor is a worker that monitors IMAP servers for reported campaign emails
|
// Monitor is a worker that monitors IMAP servers for reported campaign emails
|
||||||
type Monitor struct {
|
type Monitor struct {
|
||||||
|
@ -147,30 +148,34 @@ func checkForNewEmails(im models.IMAP) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body := string(append(m.Email.Text, m.Email.HTML...)) // Not sure if we need to check the Text as well as the HTML. Perhaps sometimes Text only emails won't have an HTML component?
|
rids, err := checkRIDs(m.Email) // Search email Text, HTML, and each attachment for rid parameters
|
||||||
rid := goPhishRegex.FindString(body)
|
if err != nil {
|
||||||
|
log.Errorf("Error searching email for rids from user '%s': %s", m.Email.From, err.Error())
|
||||||
if rid != "" {
|
} else {
|
||||||
rid = rid[5:]
|
if len(rids) < 1 {
|
||||||
log.Infof("User '%s' reported email with rid %s", m.Email.From, rid)
|
// In the future this should be an alert in Gophish
|
||||||
result, err := models.GetResult(rid)
|
log.Infof("User '%s' reported email with subject '%s'. This is not a GoPhish campaign; you should investigate it.\n", m.Email.From, m.Email.Subject)
|
||||||
if err != nil {
|
}
|
||||||
log.Error("Error reporting GoPhish email with rid ", rid, ": ", err.Error())
|
for rid := range rids {
|
||||||
reportingFailed = append(reportingFailed, m.SeqNum)
|
log.Infof("User '%s' reported email with rid %s", m.Email.From, rid)
|
||||||
} else {
|
result, err := models.GetResult(rid)
|
||||||
err = result.HandleEmailReport(models.EventDetails{})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Error updating GoPhish email with rid ", rid, ": ", err.Error())
|
log.Error("Error reporting GoPhish email with rid ", rid, ": ", err.Error())
|
||||||
|
reportingFailed = append(reportingFailed, m.SeqNum)
|
||||||
} else {
|
} else {
|
||||||
if im.DeleteReportedCampaignEmail == true {
|
err = result.HandleEmailReport(models.EventDetails{})
|
||||||
campaignEmails = append(campaignEmails, m.SeqNum)
|
if err != nil {
|
||||||
|
log.Error("Error updating GoPhish email with rid ", rid, ": ", err.Error())
|
||||||
|
} else {
|
||||||
|
if im.DeleteReportedCampaignEmail == true {
|
||||||
|
campaignEmails = append(campaignEmails, m.SeqNum)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// In the future this should be an alert in Gophish
|
|
||||||
log.Debugf("User '%s' reported email with subject '%s'. This is not a GoPhish campaign; you should investigate it.\n", m.Email.From, m.Email.Subject)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if any emails were unable to be reported, so we can mark them as unread
|
// Check if any emails were unable to be reported, so we can mark them as unread
|
||||||
if len(reportingFailed) > 0 {
|
if len(reportingFailed) > 0 {
|
||||||
log.Debugf("Marking %d emails as unread as failed to report\n", len(reportingFailed))
|
log.Debugf("Marking %d emails as unread as failed to report\n", len(reportingFailed))
|
||||||
|
@ -192,3 +197,35 @@ func checkForNewEmails(im models.IMAP) {
|
||||||
log.Debug("No new emails for ", im.Username)
|
log.Debug("No new emails for ", im.Username)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns a slice of gophish rid paramters found in the email HTML, Text, and attachments
|
||||||
|
func checkRIDs(em *email.Email) (map[string]int, error) {
|
||||||
|
|
||||||
|
rids := make(map[string]int)
|
||||||
|
|
||||||
|
// Check Text and HTML
|
||||||
|
for _, r := range goPhishRegex.FindAllStringSubmatch(string(em.Text)+string(em.HTML), -1) {
|
||||||
|
newrid := r[len(r)-1]
|
||||||
|
if _, ok := rids[newrid]; ok {
|
||||||
|
rids[newrid]++
|
||||||
|
} else {
|
||||||
|
rids[newrid] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Next check each attachment
|
||||||
|
for _, a := range em.Attachments {
|
||||||
|
if a.Header.Get("Content-Type") == "message/rfc822" {
|
||||||
|
for _, r := range goPhishRegex.FindAllStringSubmatch(string(a.Content), -1) {
|
||||||
|
newrid := r[len(r)-1]
|
||||||
|
if _, ok := rids[newrid]; ok {
|
||||||
|
rids[newrid]++
|
||||||
|
} else {
|
||||||
|
rids[newrid] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rids, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue