wafrift_encoding/tamper/
builtins.rs1use super::TamperStrategy;
4
5pub struct UrlEncodeTamper;
7
8impl TamperStrategy for UrlEncodeTamper {
9 fn name(&self) -> &'static str {
10 "url_encode"
11 }
12
13 fn description(&self) -> &'static str {
14 "Standard URL encoding (%XX for each byte)"
15 }
16
17 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
18 crate::encoding::url::url_encode(payload)
19 }
20
21 fn aggressiveness(&self) -> f64 {
22 0.15
23 }
24}
25
26pub struct DoubleUrlEncodeTamper;
28
29impl TamperStrategy for DoubleUrlEncodeTamper {
30 fn name(&self) -> &'static str {
31 "double_url_encode"
32 }
33
34 fn description(&self) -> &'static str {
35 "Double URL encoding (%25XX) — bypasses WAFs that decode once"
36 }
37
38 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
39 crate::encoding::url::double_url_encode(payload)
40 }
41
42 fn aggressiveness(&self) -> f64 {
43 0.4
44 }
45}
46
47pub struct UnicodeEscapeTamper;
49
50impl TamperStrategy for UnicodeEscapeTamper {
51 fn name(&self) -> &'static str {
52 "unicode_escape"
53 }
54
55 fn description(&self) -> &'static str {
56 "Unicode escape sequences (\\uXXXX)"
57 }
58
59 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
60 crate::encoding::unicode::unicode_encode(payload)
61 }
62
63 fn aggressiveness(&self) -> f64 {
64 0.5
65 }
66}
67
68pub struct HtmlEntityTamper;
70
71impl TamperStrategy for HtmlEntityTamper {
72 fn name(&self) -> &'static str {
73 "html_entity"
74 }
75
76 fn description(&self) -> &'static str {
77 "HTML entity encoding (&#xXX;)"
78 }
79
80 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
81 crate::encoding::unicode::html_entity_encode(payload)
82 }
83
84 fn aggressiveness(&self) -> f64 {
85 0.3
86 }
87}
88
89pub struct CaseAlternationTamper;
91
92impl TamperStrategy for CaseAlternationTamper {
93 fn name(&self) -> &'static str {
94 "case_alternation"
95 }
96
97 fn description(&self) -> &'static str {
98 "Alternating upper/lower case (SeLeCt)"
99 }
100
101 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
102 crate::encoding::keyword::case_alternate(payload)
103 }
104
105 fn aggressiveness(&self) -> f64 {
106 0.1
107 }
108}
109
110pub struct RandomCaseTamper;
112
113impl TamperStrategy for RandomCaseTamper {
114 fn name(&self) -> &'static str {
115 "random_case"
116 }
117
118 fn description(&self) -> &'static str {
119 "Random mixed case"
120 }
121
122 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
123 crate::encoding::keyword::random_case_alternate(payload)
124 }
125
126 fn aggressiveness(&self) -> f64 {
127 0.12
128 }
129}
130
131pub struct WhitespaceInsertionTamper;
133
134impl TamperStrategy for WhitespaceInsertionTamper {
135 fn name(&self) -> &'static str {
136 "whitespace_insertion"
137 }
138
139 fn description(&self) -> &'static str {
140 "Replace spaces with tabs"
141 }
142
143 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
144 crate::encoding::keyword::whitespace_insert(payload)
145 }
146
147 fn aggressiveness(&self) -> f64 {
148 0.2
149 }
150}
151
152pub struct SqlCommentTamper;
154
155impl TamperStrategy for SqlCommentTamper {
156 fn name(&self) -> &'static str {
157 "sql_comment"
158 }
159
160 fn description(&self) -> &'static str {
161 "Replace spaces with SQL comments (/**/)"
162 }
163
164 fn tamper(&self, payload: &str, context: Option<&str>) -> String {
165 let _ = context;
166 crate::encoding::keyword::sql_comment_insert(payload)
167 }
168
169 fn aggressiveness(&self) -> f64 {
170 0.25
171 }
172}
173
174pub struct NullByteTamper;
176
177impl TamperStrategy for NullByteTamper {
178 fn name(&self) -> &'static str {
179 "null_byte"
180 }
181
182 fn description(&self) -> &'static str {
183 "Null byte injection (%00 or %00.jpg)"
184 }
185
186 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
187 crate::encoding::structural::null_byte_inject(payload)
188 .unwrap_or_else(|_| payload.to_string())
189 }
190
191 fn aggressiveness(&self) -> f64 {
192 0.6
193 }
194}
195
196pub struct OverlongUtf8Tamper;
198
199impl TamperStrategy for OverlongUtf8Tamper {
200 fn name(&self) -> &'static str {
201 "overlong_utf8"
202 }
203
204 fn description(&self) -> &'static str {
205 "Overlong UTF-8 encoding for ASCII non-alphanumeric"
206 }
207
208 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
209 crate::encoding::structural::overlong_utf8(payload)
210 .unwrap_or_else(|_| payload.to_string())
211 }
212
213 fn aggressiveness(&self) -> f64 {
214 0.8
215 }
216}
217
218pub struct Base64Tamper;
220
221impl TamperStrategy for Base64Tamper {
222 fn name(&self) -> &'static str {
223 "base64"
224 }
225
226 fn description(&self) -> &'static str {
227 "Base64 encoding"
228 }
229
230 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
231 crate::encoding::structural::base64_encode(payload)
232 }
233
234 fn aggressiveness(&self) -> f64 {
235 0.75
236 }
237}
238
239pub struct HexEncodeTamper;
241
242impl TamperStrategy for HexEncodeTamper {
243 fn name(&self) -> &'static str {
244 "hex_encode"
245 }
246
247 fn description(&self) -> &'static str {
248 "Hexadecimal encoding"
249 }
250
251 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
252 crate::encoding::structural::hex_encode(payload)
253 }
254
255 fn aggressiveness(&self) -> f64 {
256 0.85
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263
264 #[test]
265 fn url_encode_tamper() {
266 let strategy = UrlEncodeTamper;
267 assert_eq!(strategy.tamper("A<", None), "A%3C");
268 assert_eq!(strategy.aggressiveness(), 0.15);
269 }
270
271 #[test]
272 fn double_url_encode_tamper() {
273 let strategy = DoubleUrlEncodeTamper;
274 assert_eq!(strategy.tamper("A", None), "%2541");
275 assert!(strategy.tamper("%20", None).contains("%25"));
276 }
277
278 #[test]
279 fn case_alternation_tamper() {
280 let strategy = CaseAlternationTamper;
281 assert_eq!(strategy.tamper("select", None), "SeLeCt");
282 }
283
284 #[test]
285 fn random_case_tamper() {
286 let strategy = RandomCaseTamper;
287 let result = strategy.tamper("select", None);
288 assert_eq!(result.to_ascii_lowercase(), "select");
289 }
290
291 #[test]
292 fn null_byte_with_extension() {
293 let strategy = NullByteTamper;
294 assert_eq!(strategy.tamper("file.php", None), "file.php%00.jpg");
295 }
296
297 #[test]
298 fn null_byte_without_extension() {
299 let strategy = NullByteTamper;
300 assert_eq!(strategy.tamper("payload", None), "payload%00");
301 }
302
303 #[test]
304 fn sql_comment_insertion() {
305 let strategy = SqlCommentTamper;
306 let result = strategy.tamper("SELECT * FROM users", Some("sql"));
307 assert!(result.contains("/**/"));
308 assert_eq!(result, "SELECT/**/*/**/FROM/**/users");
309 }
310
311 #[test]
312 fn whitespace_insertion() {
313 let strategy = WhitespaceInsertionTamper;
314 let result = strategy.tamper("SELECT * FROM users", None);
315 assert!(result.contains('\t'));
316 assert_eq!(result, "SELECT\t*\tFROM\tusers");
317 }
318
319 #[test]
320 fn base64_tamper() {
321 let strategy = Base64Tamper;
322 assert_eq!(strategy.tamper("hello", None), "aGVsbG8=");
323 }
324
325 #[test]
326 fn hex_encode_tamper() {
327 let strategy = HexEncodeTamper;
328 assert_eq!(strategy.tamper("ABC", None), "414243");
329 }
330
331 #[test]
332 fn unicode_escape_tamper() {
333 let strategy = UnicodeEscapeTamper;
334 assert_eq!(strategy.tamper("AB", None), "\\u0041\\u0042");
335 }
336
337 #[test]
338 fn html_entity_tamper() {
339 let strategy = HtmlEntityTamper;
340 assert_eq!(strategy.tamper("<>", None), "<>");
341 }
342
343 #[test]
344 fn overlong_utf8_tamper() {
345 let strategy = OverlongUtf8Tamper;
346 let result = strategy.tamper("/", None);
347 assert!(result.contains("%C0"));
348 }
349}