Due to backward compatibility to Go 1, it won't be possible to avoid net.url to sort query strings. Therefore, a custom core/url.go was introduced for this purpose.
This commit is contained in:
Giuseppe Trotta 2022-03-02 11:48:52 +01:00
parent 1bcc838924
commit 7f7cbc526a
No known key found for this signature in database
GPG key ID: DB8F64DA3FD8FE10
2 changed files with 98 additions and 11 deletions

View file

@ -13,6 +13,7 @@ import (
"github.com/evilsocket/islazy/tui"
. "github.com/logrusorgru/aurora"
"github.com/muraenateam/muraena/core"
"github.com/pkg/errors"
"github.com/muraenateam/muraena/core/db"
@ -147,8 +148,8 @@ func (muraena *MuraenaProxy) RequestProcessor(request *http.Request) (err error)
//
// HEADERS
//
// Transform query string
query, err := url.ParseQuery(request.URL.RawQuery)
// Transform query string using internal core.url instead of net.url
query, err := core.ParseQuery(request.URL.RawQuery)
if err != nil {
log.Error("URL: %s \n %s", request.URL, err.Error())
}
@ -159,15 +160,6 @@ func (muraena *MuraenaProxy) RequestProcessor(request *http.Request) (err error)
}
}
// FIX #65. If the query string ends with a key without value, such as: victim.com/a?test
// the query.Encode() automatically adds an equal sign at the end it i.e. victim.com/a?test=
realLast := request.URL.RawQuery[len(request.URL.RawQuery)-1:]
request.URL.RawQuery = query.Encode()
newLast := request.URL.RawQuery[len(request.URL.RawQuery)-1:]
if newLast == "=" && realLast != "=" {
request.URL.RawQuery = strings.TrimSuffix(request.URL.RawQuery, "=")
}
// Remove headers
for _, header := range sess.Config.Remove.Request.Headers {
request.Header.Del(header)

95
core/url.go Normal file
View file

@ -0,0 +1,95 @@
package core
import (
"net/url"
"strings"
)
// Values maps a string key to a list of values.
// It is typically used for query parameters and form values.
// Unlike in the http.Header map, the keys in a Values map
// are case-sensitive.
type Values map[string][]string
// ParseQuery parses the URL-encoded query string and returns
// a map listing the values specified for each key.
// ParseQuery always returns a non-nil map containing all the
// valid query parameters found; err describes the first decoding error
// encountered, if any.
//
// Query is expected to be a list of key=value settings separated by ampersands.
// A setting without an equals sign is interpreted as a key set to an empty
// value.
// Settings containing a non-URL-encoded semicolon are considered invalid.
func ParseQuery(query string) (Values, error) {
m := make(Values)
err := parseQuery(m, query)
return m, err
}
func parseQuery(m Values, query string) (err error) {
for query != "" {
key := query
if i := strings.IndexAny(key, "&"); i >= 0 {
key, query = key[:i], key[i+1:]
} else {
query = ""
}
//if strings.Contains(key, ";") {
// err = fmt.Errorf("invalid semicolon separator in query")
// continue
//}
if key == "" {
continue
}
value := ""
if i := strings.Index(key, "="); i >= 0 {
key, value = key[:i], key[i+1:]
}
key, err1 := url.QueryUnescape(key)
if err1 != nil {
if err == nil {
err = err1
}
continue
}
value, err1 = url.QueryUnescape(value)
if err1 != nil {
if err == nil {
err = err1
}
continue
}
m[key] = append(m[key], value)
}
return err
}
// Encode encodes the values into ``URL encoded'' form
// ("bar=baz&foo=quux") NOT sorted by key.
func (v Values) Encode() string {
if v == nil {
return ""
}
var buf strings.Builder
keys := make([]string, 0, len(v))
for k := range v {
keys = append(keys, k)
}
// We don't want to be sorted
// sort.Strings(keys)
for _, k := range keys {
vs := v[k]
keyEscaped := url.QueryEscape(k)
for _, v := range vs {
if buf.Len() > 0 {
buf.WriteByte('&')
}
buf.WriteString(keyEscaped)
buf.WriteByte('=')
buf.WriteString(url.QueryEscape(v))
}
}
return buf.String()
}