Inserted web templates, readme, license. Updated logo and favicon
This commit is contained in:
@@ -7,7 +7,6 @@ import (
|
||||
"encoding/json"
|
||||
"github.com/jinzhu/gorm"
|
||||
"math/rand"
|
||||
"time"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
@@ -104,7 +103,7 @@ func (tapit *Tapit) register(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// checks if secret code is correct
|
||||
if userJson.SecretCode != tapit.globalSettings.secretRegistrationCode {
|
||||
if userJson.SecretCode != tapit.globalSettings.SecretRegistrationCode {
|
||||
messageOutput := NotificationJson{
|
||||
Text: "Your secret code is incorrect. Please try again.",
|
||||
ResultType: "failure",
|
||||
@@ -280,7 +279,6 @@ func (tapit *Tapit) deleteCookie() http.Cookie {
|
||||
|
||||
func generateToken() string {
|
||||
var tokenResult strings.Builder
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
var r int
|
||||
tokenCharset := "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
for i:=0; i<16; i++ {
|
||||
@@ -291,7 +289,7 @@ func generateToken() string {
|
||||
}
|
||||
|
||||
func (tapit *Tapit) hashPassword(password string) (string, error) {
|
||||
bytes, err := bcrypt.GenerateFromPassword([]byte(password), tapit.globalSettings.bcryptCost)
|
||||
bytes, err := bcrypt.GenerateFromPassword([]byte(password), tapit.globalSettings.BcryptCost)
|
||||
return string(bytes), err
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ type Job struct {
|
||||
gorm.Model
|
||||
CampaignId uint
|
||||
CurrentStatus string // enum Failed, Queued, Sent, Delivered, Not Started
|
||||
WebStatus string // enum Not Visited, xx visits
|
||||
TimeSent time.Time
|
||||
ProviderTag string
|
||||
AccSID string
|
||||
@@ -63,14 +64,21 @@ type Job struct {
|
||||
ToNum string
|
||||
ResultStr string
|
||||
MessageSid string
|
||||
WebRoute string
|
||||
FullUrl string
|
||||
Visits []Visit
|
||||
}
|
||||
|
||||
type JobJson struct {
|
||||
Id uint `json:"id"`
|
||||
CurrentStatus string `json:"currentStatus"`
|
||||
WebStatus string `json:"webStatus"`
|
||||
TimeSent time.Time `json:"timeSent"`
|
||||
FromNum string `json:"fromNum"`
|
||||
ToNum string `json:"toNum"`
|
||||
WebRoute string `json:"webRoute"`
|
||||
FullUrl string `json:"fullUrl"`
|
||||
Visits []VisitJson `json:"visitJson"`
|
||||
}
|
||||
|
||||
type TwilioMessageJson struct {
|
||||
@@ -187,14 +195,24 @@ func (tapit *Tapit) createCampaign(w http.ResponseWriter, r *http.Request) {
|
||||
newCampaign.WebTemplateId = newCampaignJson.WebTemplateId
|
||||
newCampaign.ProviderTag = newCampaignJson.ProviderTag
|
||||
|
||||
// save campaign first
|
||||
tapit.db.NewRecord(&newCampaign)
|
||||
tapit.db.Create(&newCampaign)
|
||||
if newCampaign.ID == 0 {
|
||||
notifyPopup(w, r, "failure", "Failed to create campaign", nil)
|
||||
return
|
||||
}
|
||||
// update records
|
||||
for _, record := range newRecords {
|
||||
var newJob Job
|
||||
newJob.CurrentStatus = "Not Started"
|
||||
newJob.WebStatus = "Not Visited"
|
||||
newJob.ProviderTag = newCampaign.ProviderTag
|
||||
newJob.AccSID = newAccSID
|
||||
newJob.AuthToken = newAuthToken
|
||||
newJob.FromNum = newCampaign.FromNumber
|
||||
newJob.WebRoute = tapit.generateWebTemplateRoute()
|
||||
newJob.FullUrl = tapit.globalSettings.WebTemplatePrefix + newJob.WebRoute
|
||||
|
||||
// interpreting records
|
||||
var newBodyText string
|
||||
@@ -204,20 +222,17 @@ func (tapit *Tapit) createCampaign(w http.ResponseWriter, r *http.Request) {
|
||||
newBodyText = strings.Replace(newBodyText, "{lastName}", record.LastName, -1)
|
||||
newBodyText = strings.Replace(newBodyText, "{alias}", record.Alias, -1)
|
||||
newBodyText = strings.Replace(newBodyText, "{phoneNumber}", record.PhoneNumber, -1)
|
||||
newBodyText = strings.Replace(newBodyText, "{url}", newJob.FullUrl, -1)
|
||||
|
||||
newJob.BodyText = newBodyText
|
||||
|
||||
// saving it
|
||||
newCampaign.Jobs = append(newCampaign.Jobs, newJob)
|
||||
|
||||
// update campaign
|
||||
tapit.db.Save(&newCampaign)
|
||||
}
|
||||
|
||||
// update database
|
||||
tapit.db.NewRecord(&newCampaign)
|
||||
tapit.db.Create(&newCampaign)
|
||||
if newCampaign.ID == 0 {
|
||||
notifyPopup(w, r, "failure", "Failed to create campaign", nil)
|
||||
return
|
||||
}
|
||||
newCampaignJson.Id = newCampaign.ID
|
||||
newCampaignJson.CreateDate = newCampaign.CreatedAt
|
||||
newCampaignJson.Size = newCampaign.Size
|
||||
@@ -301,7 +316,11 @@ func campaignToJson(campaign Campaign) CampaignJson {
|
||||
// iterating jobs
|
||||
for _, job := range campaign.Jobs {
|
||||
var currJson JobJson
|
||||
currJson.Id = job.ID
|
||||
currJson.CurrentStatus = job.CurrentStatus
|
||||
currJson.WebStatus = job.WebStatus
|
||||
currJson.WebRoute = job.WebRoute
|
||||
currJson.FullUrl = job.FullUrl
|
||||
currJson.TimeSent = job.TimeSent
|
||||
currJson.FromNum = job.FromNum
|
||||
currJson.ToNum = job.ToNum
|
||||
@@ -425,7 +444,7 @@ func (tapit *Tapit) workerCampaign(campaign Campaign) {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
jobChan = make(chan JobComms, 1)
|
||||
for i:=0; i<tapit.globalSettings.threadsPerCampaign; i++ {
|
||||
for i:=0; i<tapit.globalSettings.ThreadsPerCampaign; i++ {
|
||||
wg.Add(1)
|
||||
go tapit.workerJob(jobChan, &wg)
|
||||
}
|
||||
@@ -436,7 +455,7 @@ func (tapit *Tapit) workerCampaign(campaign Campaign) {
|
||||
if campaignComms.Campaign.ID == campaign.ID {
|
||||
if campaignComms.Action == "stop" {
|
||||
// kill all
|
||||
for i:=0; i<tapit.globalSettings.threadsPerCampaign; i++ {
|
||||
for i:=0; i<tapit.globalSettings.ThreadsPerCampaign; i++ {
|
||||
var stopComms JobComms
|
||||
stopComms.Action = "stop"
|
||||
jobChan <- stopComms
|
||||
@@ -468,7 +487,7 @@ func (tapit *Tapit) workerCampaign(campaign Campaign) {
|
||||
}
|
||||
}
|
||||
}
|
||||
for i:=0; i<tapit.globalSettings.threadsPerCampaign; i++ {
|
||||
for i:=0; i<tapit.globalSettings.ThreadsPerCampaign; i++ {
|
||||
var stopComms JobComms
|
||||
stopComms.Action = "stop"
|
||||
jobChan <- stopComms
|
||||
@@ -512,6 +531,7 @@ func (tapit *Tapit) workerJob(jobChan chan JobComms, wg *sync.WaitGroup) {
|
||||
} else if twilioResult.Status == "delivered" {
|
||||
currentJob.Job.MessageSid = twilioResult.Sid
|
||||
currentJob.Job.CurrentStatus = "Delivered"
|
||||
currentJob.Job.TimeSent = time.Now()
|
||||
} else {
|
||||
currentJob.Job.CurrentStatus = "Failed"
|
||||
}
|
||||
|
||||
114
tapit-backend/global-settings.go
Normal file
114
tapit-backend/global-settings.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
"strings"
|
||||
"net/http"
|
||||
"io/ioutil"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// GlobalSettings contains basic common settings across the app
|
||||
type GlobalSettings struct {
|
||||
gorm.Model
|
||||
SecretRegistrationCode string
|
||||
ThreadsPerCampaign int
|
||||
BcryptCost int
|
||||
MaxRequestRetries int
|
||||
WaitBeforeRetry int
|
||||
WebTemplatePrefix string
|
||||
WebTemplateRoute string
|
||||
}
|
||||
|
||||
type GlobalSettingsJson struct {
|
||||
SecretRegistrationCode string `json:"secretRegistrationCode"`
|
||||
ThreadsPerCampaign int `json:"threadsPerCampaign"`
|
||||
BcryptCost int `json:"bcryptCost"`
|
||||
MaxRequestRetries int `json:"maxRequestRetries"`
|
||||
WaitBeforeRetry int `json:"waitBeforeRetry"`
|
||||
WebTemplatePrefix string `json:"webTemplatePrefix"`
|
||||
WebTemplateRoute string `json:"webTemplateRoute"`
|
||||
}
|
||||
|
||||
|
||||
func (tapit *Tapit) handleGlobalSettings(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "PUT" {
|
||||
tapit.updateGlobalSettings(w, r)
|
||||
} else if strings.ToUpper(r.Method) == "GET" {
|
||||
tapit.getGlobalSettings(w,r)
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) updateGlobalSettings(w http.ResponseWriter, r *http.Request) {
|
||||
requestBody, err:= ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
var globalSettingsJson GlobalSettingsJson
|
||||
var globalSettings GlobalSettings
|
||||
err = tapit.db.Last(&globalSettings).Error
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(requestBody, &globalSettingsJson)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
if globalSettingsJson.SecretRegistrationCode != "" && globalSettingsJson.ThreadsPerCampaign != 0 && globalSettingsJson.BcryptCost != 0 && globalSettingsJson.WebTemplatePrefix != "" && globalSettingsJson.WebTemplateRoute != "" {
|
||||
globalSettings.SecretRegistrationCode = globalSettingsJson.SecretRegistrationCode
|
||||
globalSettings.ThreadsPerCampaign = globalSettingsJson.ThreadsPerCampaign
|
||||
globalSettings.BcryptCost = globalSettingsJson.BcryptCost
|
||||
globalSettings.MaxRequestRetries = globalSettingsJson.MaxRequestRetries
|
||||
globalSettings.WaitBeforeRetry = globalSettingsJson.WaitBeforeRetry
|
||||
globalSettings.WebTemplatePrefix = globalSettingsJson.WebTemplatePrefix
|
||||
globalSettings.WebTemplateRoute = globalSettingsJson.WebTemplateRoute
|
||||
err = tapit.db.Save(&globalSettings).Error
|
||||
|
||||
if err != nil {
|
||||
notifyPopup(w, r, "failure", "Failed to update global settings", nil)
|
||||
return
|
||||
} else {
|
||||
tapit.globalSettings = globalSettings
|
||||
notifyPopup(w, r, "success", "Successfully updated global settings", globalSettingsJson)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
notifyPopup(w, r, "failure", "Failed to update global settings", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) getGlobalSettings(w http.ResponseWriter, r *http.Request) {
|
||||
var globalSettingsJson GlobalSettingsJson
|
||||
var globalSettings GlobalSettings
|
||||
err := tapit.db.Last(&globalSettings).Error
|
||||
|
||||
if err == nil {
|
||||
globalSettingsJson.SecretRegistrationCode = globalSettings.SecretRegistrationCode
|
||||
globalSettingsJson.ThreadsPerCampaign = globalSettings.ThreadsPerCampaign
|
||||
globalSettingsJson.BcryptCost = globalSettings.BcryptCost
|
||||
globalSettingsJson.MaxRequestRetries = globalSettings.MaxRequestRetries
|
||||
globalSettingsJson.WaitBeforeRetry = globalSettings.WaitBeforeRetry
|
||||
globalSettingsJson.WebTemplatePrefix = globalSettings.WebTemplatePrefix
|
||||
globalSettingsJson.WebTemplateRoute = globalSettings.WebTemplateRoute
|
||||
|
||||
jsonResults, err := json.Marshal(globalSettingsJson)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(jsonResults)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -8,23 +8,18 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
"path/filepath"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
// Tapit is the general struct with shared objects
|
||||
type Tapit struct {
|
||||
db *gorm.DB
|
||||
globalSettings GlobalSettings
|
||||
campaignChan chan CampaignComms
|
||||
}
|
||||
|
||||
type GlobalSettings struct {
|
||||
secretRegistrationCode string
|
||||
threadsPerCampaign int
|
||||
bcryptCost int
|
||||
maxRequestRetries int
|
||||
waitBeforeRetry int
|
||||
}
|
||||
|
||||
func generateFileHandler(path string) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
r.Header.Add("Cache-Control", "private, max-age=604800") // 7 days
|
||||
@@ -66,23 +61,43 @@ func main() {
|
||||
defer db.Close()
|
||||
|
||||
// DB Migrations
|
||||
db.AutoMigrate(&GlobalSettings{})
|
||||
db.AutoMigrate(&Session{})
|
||||
db.AutoMigrate(&User{})
|
||||
db.AutoMigrate(&TextTemplate{})
|
||||
db.AutoMigrate(&WebTemplate{})
|
||||
db.AutoMigrate(&TwilioProvider{})
|
||||
db.AutoMigrate(&Phonebook{})
|
||||
db.AutoMigrate(&PhoneRecord{})
|
||||
db.AutoMigrate(&Campaign{})
|
||||
db.AutoMigrate(&Job{})
|
||||
db.AutoMigrate(&Visit{})
|
||||
|
||||
// Setting up Tapit app
|
||||
var tapit Tapit
|
||||
tapit.db = db
|
||||
tapit.globalSettings.secretRegistrationCode = "Super-Secret-Code"
|
||||
tapit.globalSettings.threadsPerCampaign = 2
|
||||
tapit.globalSettings.bcryptCost = 12
|
||||
tapit.globalSettings.maxRequestRetries = 5
|
||||
tapit.globalSettings.waitBeforeRetry = 1000
|
||||
|
||||
var globalSettings GlobalSettings
|
||||
|
||||
// handle global settings
|
||||
err = tapit.db.Last(&globalSettings).Error
|
||||
if err != nil {
|
||||
globalSettings.SecretRegistrationCode = "Super-Secret-Code"
|
||||
globalSettings.ThreadsPerCampaign = 2
|
||||
globalSettings.BcryptCost = 12
|
||||
globalSettings.MaxRequestRetries = 5
|
||||
globalSettings.WaitBeforeRetry = 1000
|
||||
globalSettings.WebTemplatePrefix = "https://www.attacker.com/"
|
||||
globalSettings.WebTemplateRoute = "/"
|
||||
|
||||
tapit.db.NewRecord(&globalSettings)
|
||||
tapit.db.Create(&globalSettings)
|
||||
}
|
||||
|
||||
tapit.globalSettings = globalSettings
|
||||
|
||||
// Seeding random
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
// Clear running campaigns & starting background jobs
|
||||
tapit.clearRunningCampaigns()
|
||||
@@ -114,6 +129,10 @@ func main() {
|
||||
"/text-template",
|
||||
"/text-template/new",
|
||||
"/text-template/{id}/edit",
|
||||
"/web-template",
|
||||
"/web-template/new",
|
||||
"/web-template/{id}/edit",
|
||||
"/global-settings",
|
||||
"/provider",
|
||||
}
|
||||
indexPath := dir + "/static/index.html"
|
||||
@@ -127,6 +146,8 @@ func main() {
|
||||
|
||||
r.Handle("/api/text-template",tapit.authenticationHandler(tapit.handleTextTemplate))
|
||||
r.Handle("/api/text-template/{id}",tapit.authenticationHandler(tapit.handleSpecificTextTemplate))
|
||||
r.Handle("/api/web-template",tapit.authenticationHandler(tapit.handleWebTemplate))
|
||||
r.Handle("/api/web-template/{id}",tapit.authenticationHandler(tapit.handleSpecificWebTemplate))
|
||||
r.Handle("/api/provider/twilio",tapit.authenticationHandler(tapit.handleTwilioProvider))
|
||||
r.Handle("/api/phonebook",tapit.authenticationHandler(tapit.handlePhonebook))
|
||||
r.Handle("/api/phonebook/{id}",tapit.authenticationHandler(tapit.handleSpecificPhonebook))
|
||||
@@ -135,9 +156,21 @@ func main() {
|
||||
r.Handle("/api/campaign/{id}",tapit.authenticationHandler(tapit.handleSpecificCampaign))
|
||||
r.Handle("/api/campaign/{id}/start",tapit.authenticationHandler(tapit.handleStartCampaign))
|
||||
r.Handle("/api/campaign/{id}/pause",tapit.authenticationHandler(tapit.handleStopCampaign))
|
||||
r.Handle("/api/globalsettings",tapit.authenticationHandler(tapit.handleGlobalSettings))
|
||||
r.Handle("/api/jobs/{id}/visits",tapit.authenticationHandler(tapit.handleDownloadView))
|
||||
|
||||
// Starting management web server
|
||||
r.Handle("/", r)
|
||||
log.Println("Starting management web server on port 8000...")
|
||||
go http.ListenAndServe(":8000", r)
|
||||
|
||||
// Handle WebTemplate Routes
|
||||
webTemplateRouter := mux.NewRouter()
|
||||
webTemplateRouter.HandleFunc("/{route}", tapit.webTemplateRouteHandler)
|
||||
|
||||
// Starting victim route web server
|
||||
webTemplateRouter.Handle("/", webTemplateRouter)
|
||||
log.Println("Starting victim routes on port 8001...")
|
||||
http.ListenAndServe(":8001", webTemplateRouter)
|
||||
|
||||
// Starting web server
|
||||
http.Handle("/", r)
|
||||
log.Println("Starting web server...")
|
||||
http.ListenAndServe(":8000", nil)
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -11,12 +11,14 @@ import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// TextTemplate is the persistent object within Postgres
|
||||
type TextTemplate struct {
|
||||
gorm.Model
|
||||
Name string
|
||||
TemplateStr string
|
||||
}
|
||||
|
||||
// TextTemplateJson is the temporary object for JSON data passing
|
||||
type TextTemplateJson struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
@@ -238,3 +240,4 @@ func textTemplateToJson(textTemplate TextTemplate) TextTemplateJson {
|
||||
result.CreateDate = textTemplate.CreatedAt
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
@@ -128,12 +128,12 @@ func (tapit *Tapit) twilioSend(accSid string, accToken string, bodyText string,
|
||||
|
||||
// sending request
|
||||
res, err := client.Do(newRequest1)
|
||||
retriesLeft := tapit.globalSettings.maxRequestRetries
|
||||
retriesLeft := tapit.globalSettings.MaxRequestRetries
|
||||
for err != nil && retriesLeft > 0 {
|
||||
log.Println("Error in sending request")
|
||||
res, err = client.Do(newRequest1)
|
||||
retriesLeft -= 1
|
||||
time.Sleep(time.Duration(tapit.globalSettings.waitBeforeRetry) * time.Millisecond)
|
||||
time.Sleep(time.Duration(tapit.globalSettings.WaitBeforeRetry) * time.Millisecond)
|
||||
}
|
||||
|
||||
// exit gracefully if can't
|
||||
@@ -160,12 +160,12 @@ func (tapit *Tapit) twilioCheck(accSid string, accToken string, messageSid strin
|
||||
|
||||
// sending request
|
||||
res, err := client.Do(newRequest1)
|
||||
retriesLeft := tapit.globalSettings.maxRequestRetries
|
||||
retriesLeft := tapit.globalSettings.MaxRequestRetries
|
||||
for err != nil && retriesLeft > 0 {
|
||||
log.Println("Error in sending request")
|
||||
res, err = client.Do(newRequest1)
|
||||
retriesLeft -= 1
|
||||
time.Sleep(time.Duration(tapit.globalSettings.waitBeforeRetry) * time.Millisecond)
|
||||
time.Sleep(time.Duration(tapit.globalSettings.WaitBeforeRetry) * time.Millisecond)
|
||||
}
|
||||
|
||||
// exit gracefully if can't
|
||||
@@ -207,6 +207,7 @@ func (tapit *Tapit) workerTwilioChecker() {
|
||||
} else if twilioResult.Status == "delivered" {
|
||||
job.MessageSid = twilioResult.Sid
|
||||
job.CurrentStatus = "Delivered"
|
||||
job.TimeSent = time.Now()
|
||||
}
|
||||
tapit.db.Save(&job)
|
||||
}
|
||||
|
||||
468
tapit-backend/web-template.go
Normal file
468
tapit-backend/web-template.go
Normal file
@@ -0,0 +1,468 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/gorilla/mux"
|
||||
"time"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"strings"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"encoding/csv"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
// WebTemplate is the persistent object within Postgres
|
||||
type WebTemplate struct {
|
||||
gorm.Model
|
||||
Name string
|
||||
TemplateType string // enum redirect, harvester
|
||||
RedirectAgent string
|
||||
RedirectNegAgent string
|
||||
RedirectPlaceholderHtml string
|
||||
RedirectUrl string
|
||||
HarvesterBeforeHtml string
|
||||
HarvesterAfterHtml string
|
||||
}
|
||||
|
||||
// WebTemplateJson is the temporary object for JSON data passing
|
||||
type WebTemplateJson struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
TemplateType string `json:"templateType"`
|
||||
RedirectAgent string `json:"redirectAgent"`
|
||||
RedirectNegAgent string `json:"redirectNegAgent"`
|
||||
RedirectPlaceholderHtml string `json:"redirectPlaceholderHtml"`
|
||||
RedirectUrl string `json:"redirectUrl"`
|
||||
HarvesterBeforeHtml string `json:"harvesterBeforeHtml"`
|
||||
HarvesterAfterHtml string `json:"harvesterAfterHtml"`
|
||||
CreateDate time.Time `json:"createDate"`
|
||||
}
|
||||
|
||||
type Visit struct {
|
||||
gorm.Model
|
||||
JobId uint
|
||||
SourceIp string
|
||||
UserAgent string
|
||||
Method string
|
||||
BodyContent string
|
||||
RawRequest string
|
||||
}
|
||||
|
||||
type VisitJson struct {
|
||||
Id uint `json:"id"`
|
||||
JobId uint `json:"jobId"`
|
||||
SourceIP string `json:"sourceIp"`
|
||||
UserAgent string `json:"userAgent"`
|
||||
Method string `json:"method"`
|
||||
BodyContent string `json:"bodyContent"`
|
||||
RawRequest string `json:"rawRequest"`
|
||||
CreateDate time.Time `json:"createDate"`
|
||||
}
|
||||
|
||||
func (tapit *Tapit) handleWebTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "GET" {
|
||||
tapit.getWebTemplates(w, r)
|
||||
} else if strings.ToUpper(r.Method) == "POST" {
|
||||
tapit.createWebTemplate(w, r)
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) getWebTemplates(w http.ResponseWriter, r *http.Request) {
|
||||
webTemplates := []WebTemplate{}
|
||||
tapit.db.Find(&webTemplates)
|
||||
jsonResults, err := json.Marshal(webTemplatesToJson(webTemplates))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(jsonResults)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func webTemplatesToJson(webTemplates []WebTemplate) []WebTemplateJson {
|
||||
webTemplateJson := make([]WebTemplateJson, 0)
|
||||
for _, webTemplate := range webTemplates {
|
||||
var currentWebTemplateJson WebTemplateJson
|
||||
currentWebTemplateJson.Id = int(webTemplate.ID)
|
||||
currentWebTemplateJson.Name = webTemplate.Name
|
||||
currentWebTemplateJson.TemplateType = webTemplate.TemplateType
|
||||
currentWebTemplateJson.RedirectAgent = webTemplate.RedirectAgent
|
||||
currentWebTemplateJson.RedirectNegAgent = webTemplate.RedirectNegAgent
|
||||
currentWebTemplateJson.RedirectPlaceholderHtml = webTemplate.RedirectPlaceholderHtml
|
||||
currentWebTemplateJson.RedirectUrl = webTemplate.RedirectUrl
|
||||
currentWebTemplateJson.HarvesterBeforeHtml = webTemplate.HarvesterBeforeHtml
|
||||
currentWebTemplateJson.HarvesterAfterHtml = webTemplate.HarvesterAfterHtml
|
||||
currentWebTemplateJson.CreateDate = webTemplate.CreatedAt
|
||||
|
||||
webTemplateJson = append(webTemplateJson, currentWebTemplateJson)
|
||||
}
|
||||
return webTemplateJson
|
||||
}
|
||||
|
||||
func (tapit *Tapit) createWebTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
// start doing work
|
||||
requestBody, err:= ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
newWebTemplateJson := WebTemplateJson{}
|
||||
err = json.Unmarshal(requestBody, &newWebTemplateJson)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
if newWebTemplateJson.Name != "" && newWebTemplateJson.TemplateType != "" {
|
||||
// check that not both user agents are filled
|
||||
if newWebTemplateJson.RedirectAgent != "" && newWebTemplateJson.RedirectNegAgent != "" {
|
||||
notifyPopup(w, r, "failure", "Please fill in only either positive or negative redirect user agent.", nil)
|
||||
return
|
||||
}
|
||||
newWebTemplate := jsonToWebTemplate(newWebTemplateJson)
|
||||
tapit.db.NewRecord(&newWebTemplate)
|
||||
tapit.db.Create(&newWebTemplate)
|
||||
if newWebTemplate.ID == 0 {
|
||||
notifyPopup(w, r, "failure", "Failed to create text template", nil)
|
||||
return
|
||||
}
|
||||
newWebTemplateJson.Id = int(newWebTemplate.ID)
|
||||
newWebTemplateJson.CreateDate = newWebTemplate.CreatedAt
|
||||
|
||||
notifyPopup(w, r, "success", "Successfully added new text template", newWebTemplateJson)
|
||||
return
|
||||
} else {
|
||||
notifyPopup(w, r, "failure", "Please fill in all details", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func jsonToWebTemplate(currentWebTemplateJson WebTemplateJson) WebTemplate {
|
||||
var webTemplate WebTemplate
|
||||
|
||||
webTemplate.Name = currentWebTemplateJson.Name
|
||||
webTemplate.TemplateType = currentWebTemplateJson.TemplateType
|
||||
webTemplate.RedirectAgent = currentWebTemplateJson.RedirectAgent
|
||||
webTemplate.RedirectNegAgent = currentWebTemplateJson.RedirectNegAgent
|
||||
webTemplate.RedirectPlaceholderHtml = currentWebTemplateJson.RedirectPlaceholderHtml
|
||||
webTemplate.RedirectUrl = currentWebTemplateJson.RedirectUrl
|
||||
webTemplate.HarvesterBeforeHtml = currentWebTemplateJson.HarvesterBeforeHtml
|
||||
webTemplate.HarvesterAfterHtml = currentWebTemplateJson.HarvesterAfterHtml
|
||||
|
||||
return webTemplate
|
||||
}
|
||||
|
||||
func (tapit *Tapit) handleSpecificWebTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "PUT" {
|
||||
tapit.updateWebTemplate(w, r)
|
||||
} else if strings.ToUpper(r.Method) == "DELETE" {
|
||||
tapit.deleteWebTemplate(w,r)
|
||||
} else if strings.ToUpper(r.Method) == "GET" {
|
||||
tapit.getWebTemplate(w,r)
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) updateWebTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
requestBody, err:= ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
var newWebTemplateJson WebTemplateJson
|
||||
err = json.Unmarshal(requestBody, &newWebTemplateJson)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
if newWebTemplateJson.Name != "" && newWebTemplateJson.TemplateType != "" {
|
||||
var newWebTemplate WebTemplate
|
||||
|
||||
// get current phonebook
|
||||
var dbSearchWT WebTemplate
|
||||
dbSearchWT.ID = uint(newWebTemplateJson.Id)
|
||||
tapit.db.Where(&dbSearchWT).First(&newWebTemplate)
|
||||
|
||||
if newWebTemplate.ID == uint(newWebTemplateJson.Id) {
|
||||
// update name & template
|
||||
newWebTemplate.Name = newWebTemplateJson.Name
|
||||
newWebTemplate.TemplateType = newWebTemplateJson.TemplateType
|
||||
newWebTemplate.RedirectAgent = newWebTemplateJson.RedirectAgent
|
||||
newWebTemplate.RedirectNegAgent = newWebTemplateJson.RedirectNegAgent
|
||||
newWebTemplate.RedirectPlaceholderHtml = newWebTemplateJson.RedirectPlaceholderHtml
|
||||
newWebTemplate.RedirectUrl = newWebTemplateJson.RedirectUrl
|
||||
newWebTemplate.HarvesterBeforeHtml = newWebTemplateJson.HarvesterBeforeHtml
|
||||
newWebTemplate.HarvesterAfterHtml = newWebTemplateJson.HarvesterAfterHtml
|
||||
|
||||
// update database
|
||||
tapit.db.Save(&newWebTemplate)
|
||||
if newWebTemplate.ID == 0 {
|
||||
notifyPopup(w, r, "failure", "Failed to update phonebook", nil)
|
||||
return
|
||||
}
|
||||
newWebTemplateJson.Id = int(newWebTemplate.ID)
|
||||
newWebTemplateJson.CreateDate = newWebTemplate.CreatedAt
|
||||
|
||||
notifyPopup(w, r, "success", "Successfully updated web template", newWebTemplateJson)
|
||||
return
|
||||
} else {
|
||||
notifyPopup(w, r, "failure", "Failed to update web template", nil)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
notifyPopup(w, r, "failure", "Please enter all details", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) deleteWebTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
tempID, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
// start working
|
||||
var webTemplate WebTemplate
|
||||
|
||||
// get tt
|
||||
var dbSearchWT WebTemplate
|
||||
dbSearchWT.ID = uint(tempID)
|
||||
tapit.db.Where(dbSearchWT).First(&webTemplate)
|
||||
|
||||
if webTemplate.ID == uint(tempID) {
|
||||
// finally delete it
|
||||
tapit.db.Delete(&webTemplate)
|
||||
notifyPopup(w, r, "success", "Successfully deleted phonebook", nil)
|
||||
return
|
||||
} else {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) getWebTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
tempID, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
// start working
|
||||
var webTemplate WebTemplate
|
||||
|
||||
// get tt
|
||||
var dbSearchWT WebTemplate
|
||||
dbSearchWT.ID = uint(tempID)
|
||||
tapit.db.Where(dbSearchWT).First(&webTemplate)
|
||||
|
||||
if webTemplate.ID == uint(tempID) {
|
||||
jsonResults, err := json.Marshal(webTemplateToJson(webTemplate))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(jsonResults)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) generateWebTemplateRoute() string {
|
||||
charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||||
// generate 5 char
|
||||
var newRoute string
|
||||
var successRoute bool
|
||||
successRoute = false
|
||||
|
||||
for !successRoute {
|
||||
newRoute = ""
|
||||
for i:=0; i<5; i++ {
|
||||
num := rand.Int() % len(charset)
|
||||
newRoute = newRoute + string(charset[num])
|
||||
|
||||
// search if route already exists
|
||||
var dbSearchJob Job
|
||||
var jobs []Job
|
||||
dbSearchJob.WebRoute = newRoute
|
||||
tapit.db.Where(&dbSearchJob).Find(&jobs)
|
||||
if len(jobs) == 0 {
|
||||
successRoute = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return newRoute
|
||||
}
|
||||
|
||||
func webTemplateToJson(webTemplate WebTemplate) WebTemplateJson {
|
||||
var currentWebTemplateJson WebTemplateJson
|
||||
currentWebTemplateJson.Id = int(webTemplate.ID)
|
||||
currentWebTemplateJson.Name = webTemplate.Name
|
||||
currentWebTemplateJson.TemplateType = webTemplate.TemplateType
|
||||
currentWebTemplateJson.RedirectAgent = webTemplate.RedirectAgent
|
||||
currentWebTemplateJson.RedirectNegAgent = webTemplate.RedirectNegAgent
|
||||
currentWebTemplateJson.RedirectPlaceholderHtml = webTemplate.RedirectPlaceholderHtml
|
||||
currentWebTemplateJson.RedirectUrl = webTemplate.RedirectUrl
|
||||
currentWebTemplateJson.HarvesterBeforeHtml = webTemplate.HarvesterBeforeHtml
|
||||
currentWebTemplateJson.HarvesterAfterHtml = webTemplate.HarvesterAfterHtml
|
||||
currentWebTemplateJson.CreateDate = webTemplate.CreatedAt
|
||||
return currentWebTemplateJson
|
||||
}
|
||||
|
||||
func (tapit *Tapit) webTemplateRouteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var err error
|
||||
vars := mux.Vars(r)
|
||||
currRoute := vars["route"]
|
||||
|
||||
currJob := Job{}
|
||||
err = tapit.db.Where(&Job{WebRoute:currRoute}).First(&currJob).Error
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
currCampaign := Campaign{}
|
||||
err = tapit.db.Where(&Campaign{Model: gorm.Model{ID:currJob.CampaignId}}).First(&currCampaign).Error
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
currWebTemplate := WebTemplate{}
|
||||
err = tapit.db.Where(&WebTemplate{Model: gorm.Model{ID:currCampaign.WebTemplateId}}).First(&currWebTemplate).Error
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
// check type for "redirect" or "harvester"
|
||||
if currWebTemplate.TemplateType == "redirect" {
|
||||
if currWebTemplate.RedirectAgent != "" {
|
||||
listOfUA := strings.Split(currWebTemplate.RedirectAgent, ",")
|
||||
currCheck := false
|
||||
for _, currUA := range listOfUA {
|
||||
// check if user agent matches
|
||||
if strings.Contains(r.UserAgent(), currUA) {
|
||||
currCheck = true
|
||||
}
|
||||
}
|
||||
|
||||
// if matches at least once, redirect, otherwise placeholder
|
||||
if currCheck == true {
|
||||
http.Redirect(w, r, currWebTemplate.RedirectUrl, 302)
|
||||
} else {
|
||||
w.Write([]byte(currWebTemplate.RedirectPlaceholderHtml))
|
||||
}
|
||||
} else {
|
||||
listOfUA := strings.Split(currWebTemplate.RedirectNegAgent, ",")
|
||||
currCheck := true
|
||||
for _, currUA := range listOfUA {
|
||||
// check if user agent matches
|
||||
if strings.Contains(r.UserAgent(), currUA) {
|
||||
currCheck = false
|
||||
}
|
||||
}
|
||||
|
||||
// if matches at least once, redirect, otherwise placeholder
|
||||
if currCheck == true {
|
||||
http.Redirect(w, r, currWebTemplate.RedirectUrl, 302)
|
||||
} else {
|
||||
w.Write([]byte(currWebTemplate.RedirectPlaceholderHtml))
|
||||
}
|
||||
}
|
||||
} else if currWebTemplate.TemplateType == "harvester" {
|
||||
// if get show before, if post show after
|
||||
if strings.ToUpper(r.Method) == "GET"{
|
||||
w.Write([]byte(currWebTemplate.HarvesterBeforeHtml))
|
||||
} else if strings.ToUpper(r.Method) == "POST"{
|
||||
w.Write([]byte(currWebTemplate.HarvesterAfterHtml))
|
||||
} else {
|
||||
http.Error(w, "Bad request", 400)
|
||||
}
|
||||
}
|
||||
|
||||
// saving records
|
||||
requestBody, err:= ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
var newVisit Visit
|
||||
|
||||
newVisit = Visit{}
|
||||
newVisit.JobId = currJob.ID
|
||||
if r.Header.Get("X-Forwarded-For") == "" {
|
||||
newVisit.SourceIp = r.RemoteAddr
|
||||
} else {
|
||||
newVisit.SourceIp = r.Header.Get("X-Forwarded-For")
|
||||
}
|
||||
newVisit.UserAgent = r.UserAgent()
|
||||
newVisit.Method = r.Method
|
||||
newVisit.BodyContent = string(requestBody)
|
||||
rawReqBytes, err := httputil.DumpRequest(r, true)
|
||||
if err == nil {
|
||||
newVisit.RawRequest = string(rawReqBytes)
|
||||
}
|
||||
|
||||
// Update visited status
|
||||
var visits []Visit
|
||||
tapit.db.Where(Visit{JobId: uint(currJob.ID)}).Find(&visits)
|
||||
currJob.WebStatus = strconv.Itoa(len(visits) + 1) + " visits"
|
||||
|
||||
tapit.db.Save(&currJob)
|
||||
|
||||
tapit.db.NewRecord(&newVisit)
|
||||
tapit.db.Create(&newVisit)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (tapit *Tapit) handleDownloadView(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "GET" {
|
||||
var csvBuffer bytes.Buffer
|
||||
vars := mux.Vars(r)
|
||||
tempID, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
var visits []Visit
|
||||
tapit.db.Where(Visit{JobId: uint(tempID)}).Find(&visits)
|
||||
|
||||
// generate csv
|
||||
csvWriter := csv.NewWriter(&csvBuffer)
|
||||
csvWriter.Write([]string{"ID", "Time", "Source IP", "User Agent", "Method", "Body Content", "Raw Request"})
|
||||
for _, visit := range visits {
|
||||
csvWriter.Write([]string{strconv.Itoa(int(visit.ID)), visit.CreatedAt.String(), visit.SourceIp, visit.UserAgent, visit.Method, visit.BodyContent, visit.RawRequest})
|
||||
}
|
||||
csvWriter.Flush()
|
||||
w.Header().Set("Content-Disposition", "attachment; filename=\"results.csv\"")
|
||||
w.Write(csvBuffer.Bytes())
|
||||
return
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user