http_proxy_base_filters.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package http_proxy
  2. import (
  3. "io/ioutil"
  4. "net/http"
  5. "strings"
  6. "strconv"
  7. "github.com/elazarl/goproxy"
  8. "github.com/evilsocket/islazy/tui"
  9. )
  10. func (p *HTTPProxy) fixRequestHeaders(req *http.Request) {
  11. req.Header.Del("Accept-Encoding")
  12. req.Header.Del("If-None-Match")
  13. req.Header.Del("If-Modified-Since")
  14. req.Header.Del("Upgrade-Insecure-Requests")
  15. req.Header.Set("Pragma", "no-cache")
  16. }
  17. func (p *HTTPProxy) onRequestFilter(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
  18. if p.shouldProxy(req) {
  19. p.Debug("< %s %s %s%s", req.RemoteAddr, req.Method, req.Host, req.URL.Path)
  20. p.fixRequestHeaders(req)
  21. redir := p.Stripper.Preprocess(req, ctx)
  22. if redir != nil {
  23. // we need to redirect the user in order to make
  24. // some session cookie expire
  25. return req, redir
  26. }
  27. // do we have a proxy script?
  28. if p.Script == nil {
  29. return req, nil
  30. }
  31. // run the module OnRequest callback if defined
  32. jsreq, jsres := p.Script.OnRequest(req)
  33. if jsreq != nil {
  34. // the request has been changed by the script
  35. p.logRequestAction(req, jsreq)
  36. return jsreq.ToRequest(), nil
  37. } else if jsres != nil {
  38. // a fake response has been returned by the script
  39. p.logResponseAction(req, jsres)
  40. return req, jsres.ToResponse(req)
  41. }
  42. }
  43. return req, nil
  44. }
  45. func (p *HTTPProxy) getHeader(res *http.Response, header string) string {
  46. header = strings.ToLower(header)
  47. for name, values := range res.Header {
  48. for _, value := range values {
  49. if strings.ToLower(name) == header {
  50. return value
  51. }
  52. }
  53. }
  54. return ""
  55. }
  56. func (p *HTTPProxy) isScriptInjectable(res *http.Response) (bool, string) {
  57. if p.jsHook == "" {
  58. return false, ""
  59. } else if contentType := p.getHeader(res, "Content-Type"); strings.Contains(contentType, "text/html") {
  60. return true, contentType
  61. }
  62. return false, ""
  63. }
  64. func (p *HTTPProxy) doScriptInjection(res *http.Response, cType string) (error) {
  65. defer res.Body.Close()
  66. raw, err := ioutil.ReadAll(res.Body)
  67. if err != nil {
  68. return err
  69. } else if html := string(raw); strings.Contains(html, "</head>") {
  70. p.Info("> injecting javascript (%d bytes) into %s (%d bytes) for %s",
  71. len(p.jsHook),
  72. tui.Yellow(res.Request.Host+res.Request.URL.Path),
  73. len(raw),
  74. tui.Bold(strings.Split(res.Request.RemoteAddr, ":")[0]))
  75. html = strings.Replace(html, "</head>", p.jsHook, -1)
  76. res.Header.Set("Content-Length", strconv.Itoa(len(html)))
  77. // reset the response body to the original unread state
  78. res.Body = ioutil.NopCloser(strings.NewReader(html))
  79. return nil
  80. }
  81. return nil
  82. }
  83. func (p *HTTPProxy) onResponseFilter(res *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
  84. // sometimes it happens ¯\_(ツ)_/¯
  85. if res == nil {
  86. return nil
  87. }
  88. if p.shouldProxy(res.Request) {
  89. p.Debug("> %s %s %s%s", res.Request.RemoteAddr, res.Request.Method, res.Request.Host, res.Request.URL.Path)
  90. p.Stripper.Process(res, ctx)
  91. // do we have a proxy script?
  92. if p.Script != nil {
  93. _, jsres := p.Script.OnResponse(res)
  94. if jsres != nil {
  95. // the response has been changed by the script
  96. p.logResponseAction(res.Request, jsres)
  97. return jsres.ToResponse(res.Request)
  98. }
  99. }
  100. // inject javascript code if specified and needed
  101. if doInject, cType := p.isScriptInjectable(res); doInject {
  102. if err := p.doScriptInjection(res, cType); err != nil {
  103. p.Error("error while injecting javascript: %s", err)
  104. }
  105. }
  106. }
  107. return res
  108. }
  109. func (p *HTTPProxy) logRequestAction(req *http.Request, jsreq *JSRequest) {
  110. p.Sess.Events.Add(p.Name+".spoofed-request", struct {
  111. To string
  112. Method string
  113. Host string
  114. Path string
  115. Size int
  116. }{
  117. strings.Split(req.RemoteAddr, ":")[0],
  118. jsreq.Method,
  119. jsreq.Hostname,
  120. jsreq.Path,
  121. len(jsreq.Body),
  122. })
  123. }
  124. func (p *HTTPProxy) logResponseAction(req *http.Request, jsres *JSResponse) {
  125. p.Sess.Events.Add(p.Name+".spoofed-response", struct {
  126. To string
  127. Method string
  128. Host string
  129. Path string
  130. Size int
  131. }{
  132. strings.Split(req.RemoteAddr, ":")[0],
  133. req.Method,
  134. req.Host,
  135. req.URL.Path,
  136. len(jsres.Body),
  137. })
  138. }