CallableFile.java

1
package com.jsql.model.accessible;
2
3
import com.jsql.model.InjectionModel;
4
import com.jsql.model.bean.database.MockElement;
5
import com.jsql.model.exception.InjectionFailureException;
6
import com.jsql.model.exception.LoopDetectedSlidingException;
7
import com.jsql.model.exception.StoppedByUserSlidingException;
8
import com.jsql.model.injection.vendor.model.VendorYaml;
9
import com.jsql.model.suspendable.SuspendableGetRows;
10
import com.jsql.util.LogLevelUtil;
11
import org.apache.commons.codec.binary.Hex;
12
import org.apache.commons.lang3.RandomStringUtils;
13
import org.apache.commons.lang3.StringUtils;
14
import org.apache.logging.log4j.LogManager;
15
import org.apache.logging.log4j.Logger;
16
17
import java.nio.charset.StandardCharsets;
18
import java.util.concurrent.Callable;
19
20
/**
21
 * Thread unit to read source of a file by SQL injection.
22
 * User can interrupt the process and get a partial result of the file content.
23
 */
24
public class CallableFile implements Callable<CallableFile> {
25
    
26
    /**
27
     * Log4j logger sent to view.
28
     */
29
    private static final Logger LOGGER = LogManager.getRootLogger();
30
    private static final String REQUIRE_STACK = "Read file requirement : stack query";
31
32
    /**
33
     * Path to the file to read.
34
     */
35
    private final String pathFile;
36
37
    /**
38
     * Source of file.
39
     */
40
    private String sourceFile = StringUtils.EMPTY;
41
    
42
    /**
43
     * Suspendable task that reads lines of the file by injection.
44
     */
45
    private final SuspendableGetRows suspendableReadFile;
46
47
    private final InjectionModel injectionModel;
48
    
49
    /**
50
     * Create Callable to read a file.
51
     */
52
    public CallableFile(String pathFile, InjectionModel injectionModel) {
53
        this.pathFile = pathFile;
54
        this.injectionModel= injectionModel;
55
        this.suspendableReadFile = new SuspendableGetRows(injectionModel);
56
    }
57
    
58
    /**
59
     * Read a file on the server using SQL injection.
60
     * Get partial result if user interrupts the process.
61
     */
62
    @Override
63
    public CallableFile call() throws Exception {
64
        var sourcePage = new String[]{ StringUtils.EMPTY };
65
66
        String resultToParse = StringUtils.EMPTY;
67
        try {
68 1 1. call : negated conditional → NO_COVERAGE
            if (this.injectionModel.getMediatorVendor().getVendor() == this.injectionModel.getMediatorVendor().getMysql()) {
69
                LOGGER.log(LogLevelUtil.CONSOLE_INFORM, "Read file requirement : user FILE privilege");
70
                resultToParse = this.suspendableReadFile.run(
71
                    this.injectionModel.getResourceAccess().getExploitMysql().getModelYaml().getFile().getRead().replace(
72
                        VendorYaml.FILEPATH_HEX,
73
                        Hex.encodeHexString(this.pathFile.getBytes(StandardCharsets.UTF_8))
74
                    ),
75
                    sourcePage,
76
                    false,
77
                    1,
78
                    MockElement.MOCK,
79
                    ResourceAccess.FILE_READ
80
                );
81 1 1. call : negated conditional → NO_COVERAGE
            } else if (this.injectionModel.getMediatorVendor().getVendor() == this.injectionModel.getMediatorVendor().getH2()) {
82
                resultToParse = this.suspendableReadFile.run(
83
                    String.format(
84
                        this.injectionModel.getResourceAccess().getExploitH2().getModelYaml().getFile().getReadFromPath(),
85
                        this.pathFile
86
                    ),
87
                    sourcePage,
88
                    false,
89
                    1,
90
                    MockElement.MOCK,
91
                    ResourceAccess.FILE_READ
92
                );
93 1 1. call : negated conditional → NO_COVERAGE
            } else if (this.injectionModel.getMediatorVendor().getVendor() == this.injectionModel.getMediatorVendor().getSqlite()) {
94
                LOGGER.log(LogLevelUtil.CONSOLE_INFORM, "Read file requirement : extension fileio loaded");
95
                resultToParse = this.suspendableReadFile.run(
96
                    String.format(
97
                        this.injectionModel.getResourceAccess().getExploitSqlite().getModelYaml().getExtension().getFileioRead(),
98
                        this.pathFile
99
                    ),
100
                    sourcePage,
101
                    false,
102
                    1,
103
                    MockElement.MOCK,
104
                    ResourceAccess.FILE_READ
105
                );
106 1 1. call : negated conditional → NO_COVERAGE
            } else if (this.injectionModel.getMediatorVendor().getVendor() == this.injectionModel.getMediatorVendor().getDerby()) {
107
                LOGGER.log(LogLevelUtil.CONSOLE_INFORM, CallableFile.REQUIRE_STACK);
108
                var nameTable = RandomStringUtils.secure().nextAlphabetic(8);
109
                this.injectionModel.injectWithoutIndex(String.format(
110
                    this.injectionModel.getResourceAccess().getExploitDerby().getModelYaml().getFile().getCreateTable(),
111
                    nameTable,
112
                    nameTable, this.pathFile
113
                ), ResourceAccess.TBL_FILL);
114
                resultToParse = this.suspendableReadFile.run(
115
                    String.format(
116
                        this.injectionModel.getResourceAccess().getExploitDerby().getModelYaml().getFile().getRead(),
117
                        nameTable
118
                    ),
119
                    sourcePage,
120
                    true,
121
                    0,
122
                    MockElement.MOCK,
123
                    ResourceAccess.FILE_READ
124
                );
125 1 1. call : negated conditional → NO_COVERAGE
            } else if (this.injectionModel.getMediatorVendor().getVendor() == this.injectionModel.getMediatorVendor().getHsqldb()) {
126
                LOGGER.log(LogLevelUtil.CONSOLE_INFORM, CallableFile.REQUIRE_STACK);
127
                var nameTable = RandomStringUtils.secure().nextAlphabetic(8);
128
                this.injectionModel.injectWithoutIndex(String.format(
129
                    this.injectionModel.getResourceAccess().getExploitHsqldb().getModelYaml().getFile().getRead().getCreateTable(),
130
                    nameTable,
131
                    nameTable, this.pathFile
132
                ), ResourceAccess.TBL_FILL);
133
                resultToParse = this.suspendableReadFile.run(
134
                    String.format(
135
                        this.injectionModel.getResourceAccess().getExploitHsqldb().getModelYaml().getFile().getRead().getResult(),
136
                        VendorYaml.TRAIL_SQL,
137
                        nameTable
138
                    ),
139
                    sourcePage,
140
                    false,
141
                    1,
142
                    MockElement.MOCK,
143
                    ResourceAccess.TBL_READ
144
                );
145 1 1. call : negated conditional → NO_COVERAGE
            } else if (this.injectionModel.getMediatorVendor().getVendor() == this.injectionModel.getMediatorVendor().getPostgres()) {
146
                try {
147
                    resultToParse = this.suspendableReadFile.run(
148
                        String.format(
149
                            this.injectionModel.getResourceAccess().getExploitPostgres().getModelYaml().getFile().getRead().getFromDataFolder(),
150
                            this.pathFile
151
                        ),
152
                        sourcePage,
153
                        false,
154
                        1,
155
                        MockElement.MOCK,
156
                        ResourceAccess.FILE_READ
157
                    );
158
                } catch (InjectionFailureException e) {
159
                    LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Read data folder failure, trying with large object");
160
                    var loid = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
161
                        this.injectionModel.getResourceAccess().getExploitPostgres().getModelYaml().getFile().getRead().getLargeObject().getFromPath(),
162
                        this.pathFile
163
                    ), ResourceAccess.ADD_LOID);
164 1 1. call : negated conditional → NO_COVERAGE
                    if (StringUtils.isNotEmpty(loid)) {
165
                        resultToParse = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
166
                            this.injectionModel.getResourceAccess().getExploitPostgres().getModelYaml().getFile().getRead().getLargeObject().getToText(),
167
                            loid
168
                        ), ResourceAccess.READ_LOID);
169
                    }
170 1 1. call : negated conditional → NO_COVERAGE
                    if (StringUtils.isEmpty(resultToParse)) {
171
                        LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Read large object failure, trying with stack read");
172
                        var nameLibraryRandom = "tmp_" + RandomStringUtils.secure().nextAlphabetic(8);  // no dash in table name
173
                        this.injectionModel.injectWithoutIndex(String.format(
174
                            this.injectionModel.getResourceAccess().getExploitPostgres().getModelYaml().getFile().getWrite().getTempTable().getDrop(),
175
                            nameLibraryRandom
176
                        ), ResourceAccess.TBL_DROP);
177
                        this.injectionModel.injectWithoutIndex(String.format(
178
                            this.injectionModel.getResourceAccess().getExploitPostgres().getModelYaml().getFile().getWrite().getTempTable().getAdd(),
179
                            nameLibraryRandom
180
                        ), ResourceAccess.TBL_CREATE);
181
                        this.injectionModel.injectWithoutIndex(String.format(
182
                            this.injectionModel.getResourceAccess().getExploitPostgres().getModelYaml().getFile().getWrite().getTempTable().getFill(),
183
                            nameLibraryRandom,
184
                            this.pathFile
185
                        ), ResourceAccess.TBL_FILL);
186
                        resultToParse = this.suspendableReadFile.run(
187
                            String.format(
188
                                this.injectionModel.getResourceAccess().getExploitPostgres().getModelYaml().getFile().getRead().getFromTempTable(),
189
                                nameLibraryRandom
190
                            ),
191
                            sourcePage,
192
                            false,
193
                            1,
194
                            MockElement.MOCK,
195
                            ResourceAccess.TBL_READ
196
                        );
197
                    }
198
                }
199
            } else {
200
                LOGGER.log(
201
                    LogLevelUtil.CONSOLE_DEFAULT,
202
                    "Read file not implemented for [{}], share a working example to GitHub to speed up release",
203
                    this.injectionModel.getMediatorVendor().getVendor()
204
                );
205
            }
206
        } catch (InjectionFailureException e) {
207
            // Usually thrown if File does not exist
208
            LOGGER.log(LogLevelUtil.IGNORE, e);
209
        } catch (LoopDetectedSlidingException | StoppedByUserSlidingException e) {
210
            // Get partial source
211 1 1. call : negated conditional → NO_COVERAGE
            if (StringUtils.isNotEmpty(e.getSlidingWindowAllRows())) {
212
                resultToParse = e.getSlidingWindowAllRows();
213 1 1. call : negated conditional → NO_COVERAGE
            } else if (StringUtils.isNotEmpty(e.getSlidingWindowCurrentRows())) {
214
                resultToParse = e.getSlidingWindowCurrentRows();
215
            }
216
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e);
217
        }
218
        
219
        this.sourceFile = resultToParse;
220 1 1. call : replaced return value with null for com/jsql/model/accessible/CallableFile::call → NO_COVERAGE
        return this;
221
    }
222
223
224
    // Getters
225
    
226
    public String getPathFile() {
227 1 1. getPathFile : replaced return value with "" for com/jsql/model/accessible/CallableFile::getPathFile → NO_COVERAGE
        return this.pathFile;
228
    }
229
230
    public String getSourceFile() {
231 1 1. getSourceFile : replaced return value with "" for com/jsql/model/accessible/CallableFile::getSourceFile → NO_COVERAGE
        return this.sourceFile;
232
    }
233
234
    public SuspendableGetRows getSuspendableReadFile() {
235 1 1. getSuspendableReadFile : replaced return value with null for com/jsql/model/accessible/CallableFile::getSuspendableReadFile → NO_COVERAGE
        return this.suspendableReadFile;
236
    }
237
}

Mutations

68

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

81

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

93

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

106

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

125

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

145

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

164

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

170

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

211

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

213

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

220

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

227

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

231

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

235

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

Active mutators

Tests examined


Report generated by PIT 1.19.1