1 package com.jsql.util;
2
3 import com.jsql.util.tampering.TamperingType;
4 import org.apache.commons.lang3.StringUtils;
5 import org.apache.logging.log4j.LogManager;
6 import org.apache.logging.log4j.Logger;
7
8 import javax.script.Invocable;
9 import javax.script.ScriptEngine;
10 import javax.script.ScriptEngineManager;
11 import javax.script.ScriptException;
12 import java.util.regex.Pattern;
13
14 public class TamperingUtil {
15
16 private static final Logger LOGGER = LogManager.getRootLogger();
17
18 public static final String TAG_OPENED = "<tampering>";
19 public static final String TAG_CLOSED = "</tampering>";
20
21 private boolean isBase64 = false;
22 private boolean isVersionComment = false;
23 private boolean isFunctionComment = false;
24 private boolean isEqualToLike = false;
25 private boolean isRandomCase = false;
26 private boolean isHexToChar = false;
27 private boolean isStringToChar = false;
28 private boolean isQuoteToUtf8 = false;
29 private boolean isEval = false;
30 private boolean isSpaceToMultilineComment = false;
31 private boolean isSpaceToDashComment = false;
32 private boolean isSpaceToSharpComment = false;
33
34 private String customTamper = null;
35
36 private static final ScriptEngineManager SCRIPT_ENGINE_MANAGER = new ScriptEngineManager();
37
38 private static String eval(String sqlQuery, String jsTampering) {
39 Object resultSqlTampered;
40 try {
41 if (StringUtils.isEmpty(jsTampering)) {
42 throw new ScriptException("Tampering context is empty");
43 }
44
45 ScriptEngine nashornEngine = TamperingUtil.SCRIPT_ENGINE_MANAGER.getEngineByName("nashorn");
46 nashornEngine.eval(jsTampering);
47
48 var nashornInvocable = (Invocable) nashornEngine;
49 resultSqlTampered = nashornInvocable.invokeFunction("tampering", sqlQuery);
50
51 } catch (ScriptException e) {
52 LOGGER.log(
53 LogLevelUtil.CONSOLE_ERROR,
54 String.format("Tampering context contains errors: %s", e.getMessage()),
55 e
56 );
57 resultSqlTampered = sqlQuery;
58 } catch (NoSuchMethodException e) {
59 LOGGER.log(
60 LogLevelUtil.CONSOLE_ERROR,
61 String.format("Tampering context is not properly defined: %s", e.getMessage()),
62 e
63 );
64 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Minimal tampering context is: var tampering = function(sql) {return sql}");
65 resultSqlTampered = sqlQuery;
66 }
67 return resultSqlTampered.toString();
68 }
69
70 public String tamper(String sqlQueryDefault) {
71 String lead;
72 String sqlQuery;
73 String trail;
74
75
76 String regexToMatchTamperTags = String.format("(?s)(.*%s)(.*)(%s.*)", TamperingUtil.TAG_OPENED, TamperingUtil.TAG_CLOSED);
77 var matcherSql = Pattern.compile(regexToMatchTamperTags).matcher(sqlQueryDefault);
78
79 if (matcherSql.find()) {
80 lead = matcherSql.group(1);
81 sqlQuery = matcherSql.group(2);
82 trail = matcherSql.group(3);
83 } else {
84 return sqlQueryDefault;
85 }
86
87 if (this.isEval) {
88 sqlQuery = TamperingUtil.eval(sqlQuery, this.customTamper);
89 }
90
91 sqlQuery = this.transform(sqlQuery, this.isHexToChar, TamperingType.HEX_TO_CHAR);
92 sqlQuery = this.transform(sqlQuery, this.isStringToChar, TamperingType.STRING_TO_CHAR);
93 sqlQuery = this.transform(sqlQuery, this.isFunctionComment, TamperingType.COMMENT_TO_METHOD_SIGNATURE);
94 sqlQuery = this.transform(sqlQuery, this.isVersionComment, TamperingType.VERSIONED_COMMENT_TO_METHOD_SIGNATURE);
95 sqlQuery = this.transform(sqlQuery, this.isRandomCase, TamperingType.RANDOM_CASE);
96 sqlQuery = this.transform(sqlQuery, this.isEqualToLike, TamperingType.EQUAL_TO_LIKE);
97
98 sqlQuery = lead + sqlQuery + trail;
99
100 String regexToremoveTamperTags = String.format("(?i)%s|%s", TamperingUtil.TAG_OPENED, TamperingUtil.TAG_CLOSED);
101 sqlQuery = sqlQuery.replaceAll(regexToremoveTamperTags, StringUtils.EMPTY);
102
103
104 if (StringUtils.isEmpty(sqlQuery)) {
105 return StringUtils.EMPTY;
106 }
107
108
109
110
111 if (this.isSpaceToDashComment) {
112 sqlQuery = TamperingUtil.eval(sqlQuery, TamperingType.SPACE_TO_DASH_COMMENT.instance().getJavascript());
113 } else if (this.isSpaceToMultilineComment) {
114 sqlQuery = TamperingUtil.eval(sqlQuery, TamperingType.SPACE_TO_MULTILINE_COMMENT.instance().getJavascript());
115 } else if (this.isSpaceToSharpComment) {
116 sqlQuery = TamperingUtil.eval(sqlQuery, TamperingType.SPACE_TO_SHARP_COMMENT.instance().getJavascript());
117 }
118
119 sqlQuery = this.transform(sqlQuery, this.isBase64, TamperingType.BASE64);
120 sqlQuery = this.transform(sqlQuery, this.isQuoteToUtf8, TamperingType.QUOTE_TO_UTF8);
121 return sqlQuery;
122 }
123
124 private String transform(String sqlQuery, boolean shouldApply, TamperingType tamperingType) {
125 if (shouldApply) {
126 return TamperingUtil.eval(sqlQuery, tamperingType.instance().getJavascript());
127 }
128 return sqlQuery;
129 }
130
131
132
133
134 public TamperingUtil withBase64() {
135 this.isBase64 = true;
136 return this;
137 }
138
139 public TamperingUtil withVersionComment() {
140 this.isVersionComment = true;
141 return this;
142 }
143
144 public TamperingUtil withFunctionComment() {
145 this.isFunctionComment = true;
146 return this;
147 }
148
149 public TamperingUtil withEqualToLike() {
150 this.isEqualToLike = true;
151 return this;
152 }
153
154 public TamperingUtil withRandomCase() {
155 this.isRandomCase = true;
156 return this;
157 }
158
159 public TamperingUtil withHexToChar() {
160 this.isHexToChar = true;
161 return this;
162 }
163
164 public TamperingUtil withStringToChar() {
165 this.isStringToChar = true;
166 return this;
167 }
168
169 public TamperingUtil withQuoteToUtf8() {
170 this.isQuoteToUtf8 = true;
171 return this;
172 }
173
174 public TamperingUtil withEval() {
175 this.isEval = true;
176 return this;
177 }
178
179 public TamperingUtil withSpaceToMultilineComment() {
180 this.isSpaceToMultilineComment = true;
181 return this;
182 }
183
184 public TamperingUtil withSpaceToDashComment() {
185 this.isSpaceToDashComment = true;
186 return this;
187 }
188
189 public TamperingUtil withSpaceToSharpComment() {
190 this.isSpaceToSharpComment = true;
191 return this;
192 }
193
194
195
196
197 public String getCustomTamper() {
198 return this.customTamper;
199 }
200
201 public void setCustomTamper(String customTamper) {
202 this.customTamper = customTamper;
203 }
204
205 public TamperingUtil withBase64(boolean selected) {
206 this.isBase64 = selected;
207 return this;
208 }
209
210 public TamperingUtil withEqualToLike(boolean selected) {
211 this.isEqualToLike = selected;
212 return this;
213 }
214
215 public TamperingUtil withEval(boolean selected) {
216 this.isEval = selected;
217 return this;
218 }
219
220 public TamperingUtil withFunctionComment(boolean selected) {
221 this.isFunctionComment = selected;
222 return this;
223 }
224
225 public TamperingUtil withHexToChar(boolean selected) {
226 this.isHexToChar = selected;
227 return this;
228 }
229
230 public TamperingUtil withQuoteToUtf8(boolean selected) {
231 this.isQuoteToUtf8 = selected;
232 return this;
233 }
234
235 public TamperingUtil withRandomCase(boolean selected) {
236 this.isRandomCase = selected;
237 return this;
238 }
239
240 public TamperingUtil withSpaceToDashComment(boolean selected) {
241 this.isSpaceToDashComment = selected;
242 return this;
243 }
244
245 public TamperingUtil withSpaceToMultilineComment(boolean selected) {
246 this.isSpaceToMultilineComment = selected;
247 return this;
248 }
249
250 public TamperingUtil withSpaceToSharpComment(boolean selected) {
251 this.isSpaceToSharpComment = selected;
252 return this;
253 }
254
255 public TamperingUtil withStringToChar(boolean selected) {
256 this.isStringToChar = selected;
257 return this;
258 }
259
260 public TamperingUtil withVersionComment(boolean selected) {
261 this.isVersionComment = selected;
262 return this;
263 }
264 }