Skip to content

Commit

Permalink
added support to use custom tls certificates, updated certmagic
Browse files Browse the repository at this point in the history
  • Loading branch information
kgretzky committed Mar 1, 2024
1 parent d8f7d44 commit 3b0f5c9
Show file tree
Hide file tree
Showing 690 changed files with 58,112 additions and 16,485 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
release/
build/
private/
/phishlets
!/phishlets/example.yaml
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Unreleased
- Feature: Added support to load custom TLS certificates from a public certificate file and a private key file stored in `~/.evilginx/crt/sites/<hostname>/`. Will load `fullchain.pem` and `privkey.pem` pair or a combination of a `.pem`/`.crt` (public certificate) and a `.key` (private key) file. Make sure to run without `-developer` flag and disable autocert retrieval with `config autocert off`.
- Feature: Added ability to disable automated TLS certificate retrieval from LetsEncrypt with `config autocert <on/off>`.
- Fixed: Added support for exported cookies with names prefixed with `__Host-` and `__Secure-`.
- Fixed: Global `unauth_url` can now be set to an empty string to have the server return `403` on unauthorized requests.
- Fixed: Unauthorized redirects and blacklisting would be ignored for `proxy_hosts` with `session: false` (default) making it easy to detect evilginx by external scanners.
Expand Down
86 changes: 85 additions & 1 deletion core/certdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,13 @@ func NewCertDb(cache_dir string, cfg *Config, ns *Nameserver) (*CertDb, error) {
tlsCache: make(map[string]*tls.Certificate),
}

if err := os.MkdirAll(filepath.Join(cache_dir, "sites"), 0700); err != nil {
return nil, err
}

certmagic.DefaultACME.Agreed = true
certmagic.DefaultACME.Email = o.GetEmail()


err := o.generateCertificates()
if err != nil {
return nil, err
Expand Down Expand Up @@ -166,6 +169,87 @@ func (o *CertDb) setManagedSync(hosts []string, t time.Duration) error {
return err
}

func (o *CertDb) setUnmanagedSync(verbose bool) error {
sitesDir := filepath.Join(o.cache_dir, "sites")

files, err := os.ReadDir(sitesDir)
if err != nil {
return fmt.Errorf("failed to list certificates in directory '%s': %v", sitesDir, err)
}

for _, f := range files {
if f.IsDir() {
certDir := filepath.Join(sitesDir, f.Name())

certFiles, err := os.ReadDir(certDir)
if err != nil {
return fmt.Errorf("failed to list certificate directory '%s': %v", certDir, err)
}

var certPath, keyPath string

var pemCnt, crtCnt, keyCnt int
for _, cf := range certFiles {
//log.Debug("%s", cf.Name())
if !cf.IsDir() {
switch strings.ToLower(filepath.Ext(cf.Name())) {
case ".pem":
pemCnt += 1
if certPath == "" {
certPath = filepath.Join(certDir, cf.Name())
}
if cf.Name() == "fullchain.pem" {
certPath = filepath.Join(certDir, cf.Name())
}
if cf.Name() == "privkey.pem" {
keyPath = filepath.Join(certDir, cf.Name())
}
case ".crt":
crtCnt += 1
if certPath == "" {
certPath = filepath.Join(certDir, cf.Name())
}
case ".key":
keyCnt += 1
if keyPath == "" {
keyPath = filepath.Join(certDir, cf.Name())
}
}
}
}
if pemCnt > 0 && crtCnt > 0 {
if verbose {
log.Warning("cert_db: found multiple .crt and .pem files in the same directory: %s", certDir)
}
continue
}
if certPath == "" {
if verbose {
log.Warning("cert_db: not a single public certificate found in directory: %s", certDir)
}
continue
}
if keyPath == "" {
if verbose {
log.Warning("cert_db: not a single private key found in directory: %s", certDir)
}
continue
}

log.Debug("caching certificate: cert:%s key:%s", certPath, keyPath)
ctx := context.Background()
_, err = o.magic.CacheUnmanagedCertificatePEMFile(ctx, certPath, keyPath, []string{})
if err != nil {
if verbose {
log.Error("cert_db: failed to load certificate key-pair: %v", err)
}
continue
}
}
}
return nil
}

func (o *CertDb) reloadCertificates() error {
// TODO: load private certificates from disk
return nil
Expand Down
25 changes: 25 additions & 0 deletions core/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type GeneralConfig struct {
UnauthUrl string `mapstructure:"unauth_url" json:"unauth_url" yaml:"unauth_url"`
HttpsPort int `mapstructure:"https_port" json:"https_port" yaml:"https_port"`
DnsPort int `mapstructure:"dns_port" json:"dns_port" yaml:"dns_port"`
Autocert bool `mapstructure:"autocert" json:"autocert" yaml:"autocert"`
}

type Config struct {
Expand Down Expand Up @@ -134,6 +135,11 @@ func NewConfig(cfg_dir string, path string) (*Config, error) {
}

c.cfg.UnmarshalKey(CFG_GENERAL, &c.general)
if c.cfg.Get("general.autocert") == nil {
c.cfg.Set("general.autocert", true)
c.general.Autocert = true
}

c.cfg.UnmarshalKey(CFG_BLACKLIST, &c.blacklistConfig)

if c.general.OldIpv4 != "" {
Expand All @@ -156,6 +162,9 @@ func NewConfig(cfg_dir string, path string) (*Config, error) {
if c.general.DnsPort == 0 {
c.SetDnsPort(53)
}
if created_cfg {
c.EnableAutocert(true)
}

c.lures = []*Lure{}
c.cfg.UnmarshalKey(CFG_LURES, &c.lures)
Expand All @@ -168,6 +177,7 @@ func NewConfig(cfg_dir string, path string) (*Config, error) {
c.lureIds = append(c.lureIds, GenRandomToken())
}

c.cfg.WriteConfig()
return c, nil
}

Expand Down Expand Up @@ -437,6 +447,17 @@ func (c *Config) SetUnauthUrl(_url string) {
c.cfg.WriteConfig()
}

func (c *Config) EnableAutocert(enabled bool) {
c.general.Autocert = enabled
if enabled {
log.Info("autocert is now enabled")
} else {
log.Info("autocert is now disabled")
}
c.cfg.Set(CFG_GENERAL, c.general)
c.cfg.WriteConfig()
}

func (c *Config) refreshActiveHostnames() {
c.activeHostnames = []string{}
sites := c.GetEnabledSites()
Expand Down Expand Up @@ -743,3 +764,7 @@ func (c *Config) GetRedirectorsDir() string {
func (c *Config) GetBlacklistMode() string {
return c.blacklistConfig.Mode
}

func (c *Config) IsAutocertEnabled() bool {
return c.general.Autocert
}
62 changes: 44 additions & 18 deletions core/terminal.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,13 @@ func (t *Terminal) DoWork() {
func (t *Terminal) handleConfig(args []string) error {
pn := len(args)
if pn == 0 {
keys := []string{"domain", "external_ipv4", "bind_ipv4", "https_port", "dns_port", "unauth_url"}
vals := []string{t.cfg.general.Domain, t.cfg.general.ExternalIpv4, t.cfg.general.BindIpv4, strconv.Itoa(t.cfg.general.HttpsPort), strconv.Itoa(t.cfg.general.DnsPort), t.cfg.general.UnauthUrl}
autocertOnOff := "off"
if t.cfg.IsAutocertEnabled() {
autocertOnOff = "on"
}

keys := []string{"domain", "external_ipv4", "bind_ipv4", "https_port", "dns_port", "unauth_url", "autocert"}
vals := []string{t.cfg.general.Domain, t.cfg.general.ExternalIpv4, t.cfg.general.BindIpv4, strconv.Itoa(t.cfg.general.HttpsPort), strconv.Itoa(t.cfg.general.DnsPort), t.cfg.general.UnauthUrl, autocertOnOff}
log.Printf("\n%s\n", AsRows(keys, vals))
return nil
} else if pn == 2 {
Expand All @@ -205,6 +210,17 @@ func (t *Terminal) handleConfig(args []string) error {
}
t.cfg.SetUnauthUrl(args[1])
return nil
case "autocert":
switch args[1] {
case "on":
t.cfg.EnableAutocert(true)
t.manageCertificates(true)
return nil
case "off":
t.cfg.EnableAutocert(false)
t.manageCertificates(true)
return nil
}
}
} else if pn == 3 {
switch args[0] {
Expand Down Expand Up @@ -1109,13 +1125,14 @@ func (t *Terminal) monitorLurePause() {
func (t *Terminal) createHelp() {
h, _ := NewHelp()
h.AddCommand("config", "general", "manage general configuration", "Shows values of all configuration variables and allows to change them.", LAYER_TOP,
readline.PcItem("config", readline.PcItem("domain"), readline.PcItem("ipv4", readline.PcItem("external"), readline.PcItem("bind")), readline.PcItem("unauth_url"), readline.PcItem("wildcards")))
readline.PcItem("config", readline.PcItem("domain"), readline.PcItem("ipv4", readline.PcItem("external"), readline.PcItem("bind")), readline.PcItem("unauth_url"), readline.PcItem("autocert", readline.PcItem("on"), readline.PcItem("off"))))
h.AddSubCommand("config", nil, "", "show all configuration variables")
h.AddSubCommand("config", []string{"domain"}, "domain <domain>", "set base domain for all phishlets (e.g. evilsite.com)")
h.AddSubCommand("config", []string{"ipv4"}, "ipv4 <ipv4_address>", "set ipv4 external address of the current server")
h.AddSubCommand("config", []string{"ipv4", "external"}, "ipv4 external <ipv4_address>", "set ipv4 external address of the current server")
h.AddSubCommand("config", []string{"ipv4", "bind"}, "ipv4 bind <ipv4_address>", "set ipv4 bind address of the current server")
h.AddSubCommand("config", []string{"unauth_url"}, "unauth_url <url>", "change the url where all unauthorized requests will be redirected to")
h.AddSubCommand("config", []string{"autocert"}, "autocert <on|off>", "enable or disable the automated certificate retrieval from letsencrypt")

h.AddCommand("proxy", "general", "manage proxy configuration", "Configures proxy which will be used to proxy the connection to remote website", LAYER_TOP,
readline.PcItem("proxy", readline.PcItem("enable"), readline.PcItem("disable"), readline.PcItem("type"), readline.PcItem("address"), readline.PcItem("port"), readline.PcItem("username"), readline.PcItem("password")))
Expand Down Expand Up @@ -1262,21 +1279,30 @@ func (t *Terminal) checkStatus() {

func (t *Terminal) manageCertificates(verbose bool) {
if !t.p.developer {
hosts := t.p.cfg.GetActiveHostnames("")
//wc_host := t.p.cfg.GetWildcardHostname()
//hosts := []string{wc_host}
//hosts = append(hosts, t.p.cfg.GetActiveHostnames("")...)
if verbose {
log.Info("obtaining and setting up %d TLS certificates - please wait up to 60 seconds...", len(hosts))
}
err := t.p.crt_db.setManagedSync(hosts, 60*time.Second)
if err != nil {
log.Error("failed to set up TLS certificates: %s", err)
log.Error("run 'test-certs' command to retry")
return
}
if verbose {
log.Info("successfully set up all TLS certificates")
if t.cfg.IsAutocertEnabled() {
hosts := t.p.cfg.GetActiveHostnames("")
//wc_host := t.p.cfg.GetWildcardHostname()
//hosts := []string{wc_host}
//hosts = append(hosts, t.p.cfg.GetActiveHostnames("")...)
if verbose {
log.Info("obtaining and setting up %d TLS certificates - please wait up to 60 seconds...", len(hosts))
}
err := t.p.crt_db.setManagedSync(hosts, 60*time.Second)
if err != nil {
log.Error("failed to set up TLS certificates: %s", err)
log.Error("run 'test-certs' command to retry")
return
}
if verbose {
log.Info("successfully set up all TLS certificates")
}
} else {
err := t.p.crt_db.setUnmanagedSync(verbose)
if err != nil {
log.Error("failed to set up TLS certificates: %s", err)
log.Error("run 'test-certs' command to retry")
return
}
}
}
}
Expand Down
27 changes: 14 additions & 13 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,30 @@ module github.com/kgretzky/evilginx2
go 1.18

require (
github.com/caddyserver/certmagic v0.16.1
github.com/caddyserver/certmagic v0.20.0
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
github.com/elazarl/goproxy v0.0.0-20220529153421-8ea89ba92021
github.com/fatih/color v1.13.0
github.com/go-acme/lego/v3 v3.1.0
github.com/gorilla/mux v1.7.3
github.com/inconshreveable/go-vhost v0.0.0-20160627193104-06d84117953b
github.com/miekg/dns v1.1.50
github.com/miekg/dns v1.1.58
github.com/mwitkow/go-http-dialer v0.0.0-20161116154839-378f744fb2b8
github.com/spf13/viper v1.10.1
github.com/tidwall/buntdb v1.1.0
golang.org/x/net v0.0.0-20220728211354-c7608f3a8462
golang.org/x/net v0.21.0
)

require (
github.com/cenkalti/backoff/v3 v3.0.0 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/klauspost/cpuid/v2 v2.1.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/libdns/libdns v0.2.1 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mholt/acmez v1.0.3 // indirect
github.com/mholt/acmez v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/spf13/afero v1.8.1 // indirect
Expand All @@ -41,14 +41,15 @@ require (
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e // indirect
github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/sys v0.0.0-20220731174439-a90be440212d // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.12 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.20.0 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.18.0 // indirect
gopkg.in/ini.v1 v1.66.4 // indirect
gopkg.in/square/go-jose.v2 v2.3.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
Expand Down
Loading

0 comments on commit 3b0f5c9

Please sign in to comment.