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