mirror of https://github.com/gophish/gophish
implement mark submitted data as false positive, reference #1915
parent
db63ee978d
commit
a79ce72535
|
@ -135,3 +135,18 @@ func (as *Server) CampaignComplete(w http.ResponseWriter, r *http.Request) {
|
|||
JSONResponse(w, models.Response{Success: true, Message: "Campaign completed successfully!"}, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func (as *Server) FalsePositive(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id, _ := strconv.ParseInt(vars["id"], 0, 64)
|
||||
rid, _ := vars["rid"]
|
||||
switch {
|
||||
case r.Method == "GET":
|
||||
err := models.MarkEvent(id, rid)
|
||||
if err != nil {
|
||||
JSONResponse(w, models.Response{Success: false, Message: "Error marking event as false positive"}, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
JSONResponse(w, models.Response{Success: true, Message: "Event marked as false positive!"}, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ func (as *Server) registerRoutes() {
|
|||
router.HandleFunc("/campaigns/{id:[0-9]+}/results", as.CampaignResults)
|
||||
router.HandleFunc("/campaigns/{id:[0-9]+}/summary", as.CampaignSummary)
|
||||
router.HandleFunc("/campaigns/{id:[0-9]+}/complete", as.CampaignComplete)
|
||||
router.HandleFunc("/falsepositive/{id:[0-9]+}/rid/{rid:[a-zA-Z0-9]+}", as.FalsePositive)
|
||||
router.HandleFunc("/groups/", as.Groups)
|
||||
router.HandleFunc("/groups/summary", as.GroupsSummary)
|
||||
router.HandleFunc("/groups/{id:[0-9]+}", as.Group)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
-- +goose Up
|
||||
-- SQL in section 'Up' is executed when this migration is applied
|
||||
ALTER TABLE `events` ADD COLUMN false_positive BOOLEAN DEFAULT 0;
|
||||
|
||||
-- +goose Down
|
||||
-- SQL section 'Down' is executed when this migration is rolled back
|
|
@ -0,0 +1,6 @@
|
|||
-- +goose Up
|
||||
-- SQL in section 'Up' is executed when this migration is applied
|
||||
ALTER TABLE events ADD COLUMN false_positive BOOLEAN DEFAULT 0;
|
||||
|
||||
-- +goose Down
|
||||
-- SQL section 'Down' is executed when this migration is rolled back
|
|
@ -74,12 +74,13 @@ type CampaignStats struct {
|
|||
// Event contains the fields for an event
|
||||
// that occurs during the campaign
|
||||
type Event struct {
|
||||
Id int64 `json:"-"`
|
||||
CampaignId int64 `json:"campaign_id"`
|
||||
Email string `json:"email"`
|
||||
Time time.Time `json:"time"`
|
||||
Message string `json:"message"`
|
||||
Details string `json:"details"`
|
||||
Id int64 `json:"id"`
|
||||
CampaignId int64 `json:"campaign_id"`
|
||||
Email string `json:"email"`
|
||||
Time time.Time `json:"time"`
|
||||
Message string `json:"message"`
|
||||
Details string `json:"details"`
|
||||
FalsePositive bool `json:"false_positive"`
|
||||
}
|
||||
|
||||
// EventDetails is a struct that wraps common attributes we want to store
|
||||
|
@ -154,6 +155,33 @@ func (c *Campaign) UpdateStatus(s string) error {
|
|||
return db.Table("campaigns").Where("id=?", c.Id).Update("status", s).Error
|
||||
}
|
||||
|
||||
// Sets the False Positive-field for the specified eventid to true.
|
||||
// Checks if all Events with the specific email in that campaign where data has been submitted are set to false_positive "true" and if thats the case changes
|
||||
// the status in the "results" table for that recipient back to "Clicked Link" hence it won´t be count in the Submitted statistic until new data is submitted
|
||||
func MarkEvent(eveId int64, rid string) error {
|
||||
var mailcount int64
|
||||
var fpcount int64
|
||||
s := Event{}
|
||||
query := db.Table("events").Where("id=?", eveId).Update("false_positive", true).Error
|
||||
if query != nil {
|
||||
log.Errorf("Problem editing false_positive in database: Table \"events\" on id %d", eveId)
|
||||
}
|
||||
mailquery := db.Table("events").Where("id = ?", eveId)
|
||||
mailquery.Select("id, campaign_id, email, time, message, details, false_positive")
|
||||
err := mailquery.Scan(&s).Error
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
//Counter to check if all Data Submitted is flaged as false/positive
|
||||
db.Table("events").Select("Count(*)").Where("email = ? AND message = ?", s.Email, "Submitted Data").Count(&mailcount)
|
||||
db.Table("events").Select("Count(*)").Where("email = ? AND message = ? AND false_positive = ?", s.Email, "Submitted Data", true).Count(&fpcount)
|
||||
if mailcount == fpcount {
|
||||
return db.Table("results").Where("campaign_id = ? AND r_id = ?", s.CampaignId, rid).Update("status", "Clicked Link").Error
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// AddEvent creates a new campaign event in the database
|
||||
func AddEvent(e *Event, campaignID int64) error {
|
||||
e.CampaignId = campaignID
|
||||
|
|
|
@ -741,4 +741,10 @@ table.dataTable {
|
|||
}
|
||||
#password-strength-container {
|
||||
height: 40px;
|
||||
}
|
||||
.ms-1 {
|
||||
margin-left: 1em;
|
||||
}
|
||||
.mt-1 {
|
||||
margin-top: 1em;
|
||||
}
|
|
@ -42,6 +42,12 @@ var statuses = {
|
|||
icon: "fa-exclamation",
|
||||
point: "ct-point-clicked"
|
||||
},
|
||||
"True/False":{
|
||||
color: "#6c7a89",
|
||||
label: "label-info",
|
||||
icon: "fa-eraser",
|
||||
point: "ct-point-true_false"
|
||||
},
|
||||
//not a status, but is used for the campaign timeline and user timeline
|
||||
"Email Reported": {
|
||||
color: "#45d6ef",
|
||||
|
@ -178,7 +184,7 @@ function completeCampaign() {
|
|||
return new Promise(function (resolve, reject) {
|
||||
api.campaignId.complete(campaign.id)
|
||||
.success(function (msg) {
|
||||
resolve()
|
||||
resolve()
|
||||
})
|
||||
.error(function (data) {
|
||||
reject(data.responseJSON.message)
|
||||
|
@ -236,6 +242,56 @@ function exportAsCSV(scope) {
|
|||
$("#exportButton").html(exportHTML)
|
||||
}
|
||||
|
||||
function false_positive(rid, eventid, cid, repo) {
|
||||
if(repo === 'true'){
|
||||
Swal.fire({
|
||||
title: "Are you sure?",
|
||||
text: "This will flag the submitted data as False Positive and substract it from the count. Please make sure that they are invalid!",
|
||||
type: "question",
|
||||
animation: false,
|
||||
showCancelButton: true,
|
||||
reverseButtons: true,
|
||||
allowOutsideClick: false,
|
||||
showLoaderOnConfirm: true
|
||||
}).then(function (result) {
|
||||
if (result.value){
|
||||
api.eventId.falsepositive(eventid, rid).success((function() {
|
||||
refresh();
|
||||
} ));
|
||||
}
|
||||
})
|
||||
}
|
||||
else{ // will be called if Reported is not marked
|
||||
Swal.fire({
|
||||
title: "Are you sure?",
|
||||
text: "This will flag the submitted data as False Positive and substract it from the count. Please make sure that they are invalid!",
|
||||
type: "question",
|
||||
animation: false,
|
||||
showCancelButton: true,
|
||||
input: 'checkbox',
|
||||
inputValue: 1,
|
||||
inputPlaceholder: 'Mark as reported too',
|
||||
confirmButtonText: "Continue",
|
||||
confirmButtonColor: "#428bca",
|
||||
reverseButtons: true,
|
||||
allowOutsideClick: false,
|
||||
showLoaderOnConfirm: true
|
||||
}).then(function (result) {
|
||||
if (result.value && !result.reported){ // Reports the rid as Reported and the submitted data as false positive
|
||||
report_mail(escapeHtml(rid), cid);
|
||||
api.eventId.falsepositive(eventid, rid).success((function() {
|
||||
refresh();
|
||||
} ));
|
||||
} else if (result.value === 0){ // Marks the Event with the submitted data as false positive
|
||||
api.eventId.falsepositive(eventid, rid).success((function() {
|
||||
refresh();
|
||||
}));
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function replay(event_idx) {
|
||||
request = campaign.timeline[event_idx]
|
||||
details = JSON.parse(request.details)
|
||||
|
@ -400,7 +456,13 @@ function renderTimeline(data) {
|
|||
}
|
||||
if (event.message == "Submitted Data") {
|
||||
results += '<div class="timeline-replay-button"><button onclick="replay(' + i + ')" class="btn btn-success">'
|
||||
results += '<i class="fa fa-refresh"></i> Replay Credentials</button></div>'
|
||||
results += '<i class="fa fa-refresh"></i> Replay Credentials</button>'
|
||||
if(campaign.timeline[i].false_positive === true){
|
||||
results += '<div class="alert alert-warning mt-1" role="alert">Marked as False Positive!</div></div>'
|
||||
}
|
||||
else{
|
||||
results += '<button onclick="false_positive(\'' + record.id + '\',\'' + campaign.timeline[i].id + '\',\'' + campaign.id + '\',\'' + record.reported + '\')" id="false-positive-button" class="btn btn-warning ms-1"><i class="fa fa-ban"></i> False Positive</button></div>'
|
||||
}
|
||||
results += '<div class="timeline-event-details"><i class="fa fa-caret-right"></i> View Details</div>'
|
||||
}
|
||||
if (details.payload) {
|
||||
|
|
|
@ -255,6 +255,12 @@ var api = {
|
|||
return query("/users/" + id, "DELETE", {}, true)
|
||||
}
|
||||
},
|
||||
eventId:{
|
||||
//marks an event as false positiv in the database
|
||||
falsepositive: function (eventid, rid) {
|
||||
return query("/falsepositive/" + eventid + "/rid/" + rid, "GET", {}, true)
|
||||
}
|
||||
},
|
||||
webhooks: {
|
||||
get: function() {
|
||||
return query("/webhooks/", "GET", {}, false)
|
||||
|
|
Loading…
Reference in New Issue