TapIt - SMS Phishing Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

468 lines
16 KiB

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
}
}