Skip to main content

wafrift_encoding/tamper/
builtins.rs

1//! Built-in tamper strategy implementations.
2
3use super::TamperStrategy;
4
5/// URL encoding tamper strategy.
6pub 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
26/// Double URL encoding tamper strategy.
27pub 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
47/// Unicode escape tamper strategy.
48pub 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
68/// HTML entity tamper strategy.
69pub 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
89/// Case alternation tamper strategy.
90pub 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
110/// Random case tamper strategy.
111pub 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
131/// Whitespace insertion tamper strategy.
132pub 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
152/// SQL comment tamper strategy.
153pub 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
174/// Null byte tamper strategy.
175pub 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    }
189
190    fn aggressiveness(&self) -> f64 {
191        0.6
192    }
193}
194
195/// Overlong UTF-8 tamper strategy.
196pub struct OverlongUtf8Tamper;
197
198impl TamperStrategy for OverlongUtf8Tamper {
199    fn name(&self) -> &'static str {
200        "overlong_utf8"
201    }
202
203    fn description(&self) -> &'static str {
204        "Overlong UTF-8 encoding for ASCII non-alphanumeric"
205    }
206
207    fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
208        crate::encoding::structural::overlong_utf8(payload)
209    }
210
211    fn aggressiveness(&self) -> f64 {
212        0.8
213    }
214}
215
216/// Base64 tamper strategy.
217pub struct Base64Tamper;
218
219impl TamperStrategy for Base64Tamper {
220    fn name(&self) -> &'static str {
221        "base64"
222    }
223
224    fn description(&self) -> &'static str {
225        "Base64 encoding"
226    }
227
228    fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
229        crate::encoding::structural::base64_encode(payload)
230    }
231
232    fn aggressiveness(&self) -> f64 {
233        0.75
234    }
235}
236
237/// Hex encoding tamper strategy.
238pub struct HexEncodeTamper;
239
240impl TamperStrategy for HexEncodeTamper {
241    fn name(&self) -> &'static str {
242        "hex_encode"
243    }
244
245    fn description(&self) -> &'static str {
246        "Hexadecimal encoding"
247    }
248
249    fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
250        crate::encoding::structural::hex_encode(payload)
251    }
252
253    fn aggressiveness(&self) -> f64 {
254        0.85
255    }
256}
257
258#[cfg(test)]
259mod tests {
260    use super::*;
261
262    #[test]
263    fn url_encode_tamper() {
264        let strategy = UrlEncodeTamper;
265        assert_eq!(strategy.tamper("A<", None), "A%3C");
266        assert_eq!(strategy.aggressiveness(), 0.15);
267    }
268
269    #[test]
270    fn double_url_encode_tamper() {
271        let strategy = DoubleUrlEncodeTamper;
272        assert_eq!(strategy.tamper("A", None), "%2541");
273        assert!(strategy.tamper("%20", None).contains("%25"));
274    }
275
276    #[test]
277    fn case_alternation_tamper() {
278        let strategy = CaseAlternationTamper;
279        assert_eq!(strategy.tamper("select", None), "SeLeCt");
280    }
281
282    #[test]
283    fn random_case_tamper() {
284        let strategy = RandomCaseTamper;
285        let result = strategy.tamper("select", None);
286        assert_eq!(result.to_ascii_lowercase(), "select");
287    }
288
289    #[test]
290    fn null_byte_with_extension() {
291        let strategy = NullByteTamper;
292        assert_eq!(strategy.tamper("file.php", None), "file.php%00.jpg");
293    }
294
295    #[test]
296    fn null_byte_without_extension() {
297        let strategy = NullByteTamper;
298        assert_eq!(strategy.tamper("payload", None), "payload%00");
299    }
300
301    #[test]
302    fn sql_comment_insertion() {
303        let strategy = SqlCommentTamper;
304        let result = strategy.tamper("SELECT * FROM users", Some("sql"));
305        assert!(result.contains("/**/"));
306        assert_eq!(result, "SELECT/**/*/**/FROM/**/users");
307    }
308
309    #[test]
310    fn whitespace_insertion() {
311        let strategy = WhitespaceInsertionTamper;
312        let result = strategy.tamper("SELECT * FROM users", None);
313        assert!(result.contains('\t'));
314        assert_eq!(result, "SELECT\t*\tFROM\tusers");
315    }
316
317    #[test]
318    fn base64_tamper() {
319        let strategy = Base64Tamper;
320        assert_eq!(strategy.tamper("hello", None), "aGVsbG8=");
321    }
322
323    #[test]
324    fn hex_encode_tamper() {
325        let strategy = HexEncodeTamper;
326        assert_eq!(strategy.tamper("ABC", None), "414243");
327    }
328
329    #[test]
330    fn unicode_escape_tamper() {
331        let strategy = UnicodeEscapeTamper;
332        assert_eq!(strategy.tamper("AB", None), "\\u0041\\u0042");
333    }
334
335    #[test]
336    fn html_entity_tamper() {
337        let strategy = HtmlEntityTamper;
338        assert_eq!(strategy.tamper("<>", None), "&#x3C;&#x3E;");
339    }
340
341    #[test]
342    fn overlong_utf8_tamper() {
343        let strategy = OverlongUtf8Tamper;
344        let result = strategy.tamper("/", None);
345        assert!(result.contains("%C0"));
346    }
347}