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

Mutations

147

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

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

151

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

174

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

178

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

184

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

186

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

188

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

196

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

198

1.1
Location : callAdminPage
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

199

1.1
Location : callAdminPage
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

200

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

202

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

207

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

211

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

219

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

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

223

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

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

232

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

236

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

241

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

249

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

256

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

261

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

282

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

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

285

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

292

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

298

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

299

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

303

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

323

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

337

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

344

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

348

1.1
Location : runWebShell
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

349

1.1
Location : runWebShell
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

350

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

351

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

363

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

375

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

377

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

383

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

385

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

389

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

391

1.1
Location : runSqlShell
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

392

1.1
Location : runSqlShell
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

393

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

395

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

410

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

412

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

421

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

428

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

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

432

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

433

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

437

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

443

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

449

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

454

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

462

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

499

1.1
Location : upload
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

500

1.1
Location : upload
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

501

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

502

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

523

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

524

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

526

1.1
Location : isMysqlReadDenied
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

527

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

528

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

531

1.1
Location : isMysqlReadDenied
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

532

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

535

1.1
Location : isMysqlReadDenied
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

536

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

540

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

554

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

555

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

578

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

582

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

584

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

590

1.1
Location : readFile
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

591

1.1
Location : readFile
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

592

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

594

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

598

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

605

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

611

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

613

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

614

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

621

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

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

625

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

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

630

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

635

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

648

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

669

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

681

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

685

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

689

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

693

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

697

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

705

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

709

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

713

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

717

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

Active mutators

Tests examined


Report generated by PIT 1.19.1