new: now request object can be changed during OnRequest handlers (closes #135)

This commit is contained in:
evilsocket 2018-03-05 16:48:45 +01:00
parent cb58258bd7
commit 07fe790ad1
3 changed files with 111 additions and 34 deletions

View file

@ -77,9 +77,12 @@ func NewHTTPProxy(s *session.Session) *HTTPProxy {
p.Proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { p.Proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
log.Debug("(%s) < %s %s %s%s", core.Green(p.Name), req.RemoteAddr, req.Method, req.Host, req.URL.Path) log.Debug("(%s) < %s %s %s%s", core.Green(p.Name), req.RemoteAddr, req.Method, req.Host, req.URL.Path)
if p.Script != nil { if p.Script != nil {
jsres := p.Script.OnRequest(req) jsreq, jsres := p.Script.OnRequest(req)
if jsres != nil { if jsreq != nil {
p.logAction(req, jsres) p.logRequestAction(req, jsreq)
return jsreq.ToRequest(), nil
} else if jsres != nil {
p.logResponseAction(req, jsres)
return req, jsres.ToResponse(req) return req, jsres.ToResponse(req)
} }
} }
@ -91,9 +94,9 @@ func NewHTTPProxy(s *session.Session) *HTTPProxy {
req := res.Request req := res.Request
log.Debug("(%s) > %s %s %s%s", core.Green(p.Name), req.RemoteAddr, req.Method, req.Host, req.URL.Path) log.Debug("(%s) > %s %s %s%s", core.Green(p.Name), req.RemoteAddr, req.Method, req.Host, req.URL.Path)
if p.Script != nil { if p.Script != nil {
jsres := p.Script.OnResponse(res) _, jsres := p.Script.OnResponse(res)
if jsres != nil { if jsres != nil {
p.logAction(res.Request, jsres) p.logResponseAction(res.Request, jsres)
return jsres.ToResponse(res.Request) return jsres.ToResponse(res.Request)
} }
} }
@ -104,7 +107,23 @@ func NewHTTPProxy(s *session.Session) *HTTPProxy {
return p return p
} }
func (p *HTTPProxy) logAction(req *http.Request, jsres *JSResponse) { func (p *HTTPProxy) logRequestAction(req *http.Request, jsreq *JSRequest) {
p.sess.Events.Add(p.Name+".spoofed-request", struct {
To string
Method string
Host string
Path string
Size int
}{
strings.Split(req.RemoteAddr, ":")[0],
jsreq.Method,
jsreq.Hostname,
jsreq.Path,
len(jsreq.Body),
})
}
func (p *HTTPProxy) logResponseAction(req *http.Request, jsres *JSResponse) {
p.sess.Events.Add(p.Name+".spoofed-response", struct { p.sess.Events.Add(p.Name+".spoofed-response", struct {
To string To string
Method string Method string

View file

@ -24,7 +24,10 @@ type JSRequest struct {
ContentType string ContentType string
Headers []JSHeader Headers []JSHeader
Body string Body string
req *http.Request
req *http.Request
refHash string
bodyRead bool
} }
func NewJSRequest(req *http.Request) *JSRequest { func NewJSRequest(req *http.Request) *JSRequest {
@ -41,7 +44,7 @@ func NewJSRequest(req *http.Request) *JSRequest {
} }
} }
return &JSRequest{ jreq := &JSRequest{
Client: strings.Split(req.RemoteAddr, ":")[0], Client: strings.Split(req.RemoteAddr, ":")[0],
Method: req.Method, Method: req.Method,
Version: fmt.Sprintf("%d.%d", req.ProtoMajor, req.ProtoMinor), Version: fmt.Sprintf("%d.%d", req.ProtoMajor, req.ProtoMinor),
@ -51,8 +54,38 @@ func NewJSRequest(req *http.Request) *JSRequest {
ContentType: cType, ContentType: cType,
Headers: headers, Headers: headers,
req: req, req: req,
bodyRead: false,
} }
jreq.UpdateHash()
return jreq
}
func (j *JSRequest) NewHash() string {
hash := fmt.Sprintf("%s.%s.%s.%s.%s.%s.%s", j.Client, j.Method, j.Version, j.Hostname, j.Path, j.Query, j.ContentType)
for _, h := range j.Headers {
hash += fmt.Sprintf(".%s-%s", h.Name, h.Value)
}
hash += "." + j.Body
return hash
}
func (j *JSRequest) UpdateHash() {
j.refHash = j.NewHash()
}
func (j *JSRequest) WasModified() bool {
// body was read
if j.bodyRead == true {
return true
}
// check if any of the fields has been changed
newHash := j.NewHash()
if newHash != j.refHash {
return true
}
return false
} }
func (j *JSRequest) ReadBody() string { func (j *JSRequest) ReadBody() string {
@ -62,6 +95,7 @@ func (j *JSRequest) ReadBody() string {
} }
j.Body = string(raw) j.Body = string(raw)
j.bodyRead = true
// reset the request body to the original unread state // reset the request body to the original unread state
j.req.Body = ioutil.NopCloser(bytes.NewBuffer(raw)) j.req.Body = ioutil.NopCloser(bytes.NewBuffer(raw))
@ -90,3 +124,26 @@ func (j *JSRequest) ParseForm() map[string]string {
return form return form
} }
func (j *JSRequest) ToRequest() (req *http.Request) {
url := fmt.Sprintf("%s://%s:%s%s?%s", j.req.URL.Scheme, j.Hostname, j.req.URL.Port(), j.Path, j.Query)
if j.Body == "" {
req, _ = http.NewRequest(j.Method, url, j.req.Body)
} else {
req, _ = http.NewRequest(j.Method, url, strings.NewReader(j.Body))
}
hadType := false
for _, h := range j.Headers {
req.Header.Set(h.Name, h.Value)
if h.Name == "Content-Type" {
hadType = true
}
}
if hadType == false && j.ContentType != "" {
req.Header.Set("Content-Type", j.ContentType)
}
return
}

View file

@ -60,9 +60,8 @@ func LoadHttpProxyScript(path string, sess *session.Session) (err error, s *Http
return LoadHttpProxyScriptSource(path, string(raw), sess) return LoadHttpProxyScriptSource(path, string(raw), sess)
} }
func (s *HttpProxyScript) doRequestDefines(req *http.Request) (err error, jsres *JSResponse) { func (s *HttpProxyScript) doRequestDefines(req *http.Request) (err error, jsreq *JSRequest, jsres *JSResponse) {
// convert request and define empty response to be optionally filled jsreq = NewJSRequest(req)
jsreq := NewJSRequest(req)
if err = s.VM.Set("req", jsreq); err != nil { if err = s.VM.Set("req", jsreq); err != nil {
log.Error("Error while defining request: %s", err) log.Error("Error while defining request: %s", err)
return return
@ -76,9 +75,8 @@ func (s *HttpProxyScript) doRequestDefines(req *http.Request) (err error, jsres
return return
} }
func (s *HttpProxyScript) doResponseDefines(res *http.Response) (err error, jsres *JSResponse) { func (s *HttpProxyScript) doResponseDefines(res *http.Response) (err error, jsreq *JSRequest, jsres *JSResponse) {
// convert both request and response jsreq = NewJSRequest(res.Request)
jsreq := NewJSRequest(res.Request)
if err = s.VM.Set("req", jsreq); err != nil { if err = s.VM.Set("req", jsreq); err != nil {
log.Error("Error while defining request: %s", err) log.Error("Error while defining request: %s", err)
return return
@ -93,54 +91,57 @@ func (s *HttpProxyScript) doResponseDefines(res *http.Response) (err error, jsre
return return
} }
func (s *HttpProxyScript) OnRequest(req *http.Request) *JSResponse { func (s *HttpProxyScript) OnRequest(original *http.Request) (jsreq *JSRequest, jsres *JSResponse) {
var err error
if s.onRequestScript != nil { if s.onRequestScript != nil {
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
err, jsres := s.doRequestDefines(req) if err, jsreq, jsres = s.doRequestDefines(original); err != nil {
if err != nil {
log.Error("Error while running bootstrap definitions: %s", err) log.Error("Error while running bootstrap definitions: %s", err)
return nil return nil, nil
} }
_, err = s.VM.Run(s.onRequestScript) if _, err = s.VM.Run(s.onRequestScript); err != nil {
if err != nil {
log.Error("Error while executing onRequest callback: %s", err) log.Error("Error while executing onRequest callback: %s", err)
return nil return nil, nil
} }
if jsres.WasModified() { if jsreq.WasModified() {
jsreq.UpdateHash()
return jsreq, nil
} else if jsres.WasModified() {
jsres.UpdateHash() jsres.UpdateHash()
return jsres return nil, jsres
} }
} }
return nil return nil, nil
} }
func (s *HttpProxyScript) OnResponse(res *http.Response) *JSResponse { func (s *HttpProxyScript) OnResponse(res *http.Response) (jsreq *JSRequest, jsres *JSResponse) {
var err error
if s.onResponseScript != nil { if s.onResponseScript != nil {
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
err, jsres := s.doResponseDefines(res) if err, jsreq, jsres = s.doResponseDefines(res); err != nil {
if err != nil {
log.Error("Error while running bootstrap definitions: %s", err) log.Error("Error while running bootstrap definitions: %s", err)
return nil return nil, nil
} }
_, err = s.VM.Run(s.onResponseScript) if _, err = s.VM.Run(s.onResponseScript); err != nil {
if err != nil {
log.Error("Error while executing onRequest callback: %s", err) log.Error("Error while executing onRequest callback: %s", err)
return nil return nil, nil
} }
if jsres.WasModified() { if jsres.WasModified() {
jsres.UpdateHash() jsres.UpdateHash()
return jsres return nil, jsres
} }
} }
return nil return nil, nil
} }