github.com/edermi/gophish_mods@v0.7.0/util/util.go (about)

     1  package util
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"crypto/elliptic"
     6  	"crypto/rand"
     7  	"crypto/x509"
     8  	"crypto/x509/pkix"
     9  	"encoding/csv"
    10  	"encoding/pem"
    11  	"fmt"
    12  	"io"
    13  	"io/ioutil"
    14  	"math/big"
    15  	"net/http"
    16  	"net/mail"
    17  	"os"
    18  	"regexp"
    19  	"time"
    20  
    21  	log "github.com/gophish/gophish/logger"
    22  	"github.com/gophish/gophish/models"
    23  	"github.com/jordan-wright/email"
    24  )
    25  
    26  var (
    27  	firstNameRegex = regexp.MustCompile(`(?i)first[\s_-]*name`)
    28  	lastNameRegex  = regexp.MustCompile(`(?i)last[\s_-]*name`)
    29  	emailRegex     = regexp.MustCompile(`(?i)email`)
    30  	positionRegex  = regexp.MustCompile(`(?i)position`)
    31  )
    32  
    33  // ParseMail takes in an HTTP Request and returns an Email object
    34  // TODO: This function will likely be changed to take in a []byte
    35  func ParseMail(r *http.Request) (email.Email, error) {
    36  	e := email.Email{}
    37  	m, err := mail.ReadMessage(r.Body)
    38  	if err != nil {
    39  		fmt.Println(err)
    40  	}
    41  	body, err := ioutil.ReadAll(m.Body)
    42  	e.HTML = body
    43  	return e, err
    44  }
    45  
    46  // ParseCSV contains the logic to parse the user provided csv file containing Target entries
    47  func ParseCSV(r *http.Request) ([]models.Target, error) {
    48  	mr, err := r.MultipartReader()
    49  	ts := []models.Target{}
    50  	if err != nil {
    51  		return ts, err
    52  	}
    53  	for {
    54  		part, err := mr.NextPart()
    55  		if err == io.EOF {
    56  			break
    57  		}
    58  		// Skip the "submit" part
    59  		if part.FileName() == "" {
    60  			continue
    61  		}
    62  		defer part.Close()
    63  		reader := csv.NewReader(part)
    64  		reader.TrimLeadingSpace = true
    65  		record, err := reader.Read()
    66  		if err == io.EOF {
    67  			break
    68  		}
    69  		fi := -1
    70  		li := -1
    71  		ei := -1
    72  		pi := -1
    73  		fn := ""
    74  		ln := ""
    75  		ea := ""
    76  		ps := ""
    77  		for i, v := range record {
    78  			switch {
    79  			case firstNameRegex.MatchString(v):
    80  				fi = i
    81  			case lastNameRegex.MatchString(v):
    82  				li = i
    83  			case emailRegex.MatchString(v):
    84  				ei = i
    85  			case positionRegex.MatchString(v):
    86  				pi = i
    87  			}
    88  		}
    89  		for {
    90  			record, err := reader.Read()
    91  			if err == io.EOF {
    92  				break
    93  			}
    94  			if fi != -1 && len(record) > fi {
    95  				fn = record[fi]
    96  			}
    97  			if li != -1 && len(record) > li {
    98  				ln = record[li]
    99  			}
   100  			if ei != -1 && len(record) > ei {
   101  				csvEmail, err := mail.ParseAddress(record[ei])
   102  				if err != nil {
   103  					continue
   104  				}
   105  				ea = csvEmail.Address
   106  			}
   107  			if pi != -1 && len(record) > pi {
   108  				ps = record[pi]
   109  			}
   110  			t := models.Target{
   111  				BaseRecipient: models.BaseRecipient{
   112  					FirstName: fn,
   113  					LastName:  ln,
   114  					Email:     ea,
   115  					Position:  ps,
   116  				},
   117  			}
   118  			ts = append(ts, t)
   119  		}
   120  	}
   121  	return ts, nil
   122  }
   123  
   124  // CheckAndCreateSSL is a helper to setup self-signed certificates for the administrative interface.
   125  func CheckAndCreateSSL(cp string, kp string) error {
   126  	// Check whether there is an existing SSL certificate and/or key, and if so, abort execution of this function
   127  	if _, err := os.Stat(cp); !os.IsNotExist(err) {
   128  		return nil
   129  	}
   130  	if _, err := os.Stat(kp); !os.IsNotExist(err) {
   131  		return nil
   132  	}
   133  
   134  	log.Infof("Creating new self-signed certificates for administration interface")
   135  
   136  	priv, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
   137  
   138  	notBefore := time.Now()
   139  	// Generate a certificate that lasts for 10 years
   140  	notAfter := notBefore.Add(10 * 365 * 24 * time.Hour)
   141  
   142  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
   143  	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
   144  
   145  	if err != nil {
   146  		return fmt.Errorf("TLS Certificate Generation: Failed to generate a random serial number: %s", err)
   147  	}
   148  
   149  	template := x509.Certificate{
   150  		SerialNumber: serialNumber,
   151  		Subject: pkix.Name{
   152  			Organization: []string{"Gophish"},
   153  		},
   154  		NotBefore: notBefore,
   155  		NotAfter:  notAfter,
   156  
   157  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
   158  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   159  		BasicConstraintsValid: true,
   160  	}
   161  
   162  	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, priv.Public(), priv)
   163  	if err != nil {
   164  		return fmt.Errorf("TLS Certificate Generation: Failed to create certificate: %s", err)
   165  	}
   166  
   167  	certOut, err := os.Create(cp)
   168  	if err != nil {
   169  		return fmt.Errorf("TLS Certificate Generation: Failed to open %s for writing: %s", cp, err)
   170  	}
   171  	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
   172  	certOut.Close()
   173  
   174  	keyOut, err := os.OpenFile(kp, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
   175  	if err != nil {
   176  		return fmt.Errorf("TLS Certificate Generation: Failed to open %s for writing", kp)
   177  	}
   178  
   179  	b, err := x509.MarshalECPrivateKey(priv)
   180  	if err != nil {
   181  		return fmt.Errorf("TLS Certificate Generation: Unable to marshal ECDSA private key: %v", err)
   182  	}
   183  
   184  	pem.Encode(keyOut, &pem.Block{Type: "EC PRIVATE KEY", Bytes: b})
   185  	keyOut.Close()
   186  
   187  	log.Info("TLS Certificate Generation complete")
   188  	return nil
   189  }