1+ # frozen_string_literal: true
2+
3+ require "test_helper"
4+
5+ class Aikido ::Zen ::Scanners ::PathTraversalScannerTest < ActiveSupport ::TestCase
6+ def assert_attack ( filepath , input = filepath , reason = "#{ input } was not blocked" )
7+ assert scan ( filepath , input ) , reason
8+ end
9+
10+ def refute_attack ( filepath , input = filepath , reason = "#{ input } was blocked" )
11+ refute scan ( filepath , input ) , reason
12+ end
13+
14+ def scan ( filepath , input = query )
15+ Aikido ::Zen ::Scanners ::PathTraversalScanner . new ( filepath , input ) . attack?
16+ end
17+
18+ test "no path traversal" do
19+ refute_attack "/some-directory/sub-folder/file.txt" , "/sub-folder/file.txt"
20+ end
21+
22+ test "ignores input with length <= 1" do
23+ refute_attack ""
24+ refute_attack "a"
25+ refute_attack "abcd" , ""
26+ refute_attack "abcd" , "a"
27+ end
28+
29+ test "ignores in case the input is longer than the filepath" do
30+ refute_attack "1" , "12"
31+ refute_attack "base-string" , "base-string-plus-words"
32+ end
33+
34+ test "ignores in case the input not contained by filepath" do
35+ refute_attack "1" , "a"
36+ refute_attack "base-string" , "base-string" . reverse
37+ end
38+
39+ test "same as user input" do
40+ refute_attack "file.txt" , "file.txt"
41+ end
42+
43+ test "with directory before" do
44+ refute_attack "directory/file.txt" , "file.txt"
45+ refute_attack "directory/file.txt" , "directory/file.txt"
46+ end
47+
48+ test "it flags bad inputs" do
49+ # inputs with ../
50+ assert_attack "../file.txt" , "../"
51+ assert_attack "../file.txt" , "../file.txt"
52+ assert_attack "../../file.txt" , "../../"
53+ assert_attack "../../file.txt" , "../../file.txt"
54+
55+ # inputs with ..\\
56+ assert_attack "..\\ file.txt" , "..\\ "
57+ assert_attack "..\\ file.txt" , "..\\ file.txt"
58+ assert_attack "..\\ ..\\ file.txt" , "..\\ ..\\ "
59+ assert_attack "..\\ ..\\ file.txt" , "..\\ ..\\ file.txt"
60+
61+ # inputs with ./../
62+ assert_attack "./../file.txt" , "./../"
63+ assert_attack "./../file.txt" , "./../file.txt"
64+ assert_attack "./../../file.txt" , "./../../"
65+ assert_attack "./../../file.txt" , "./../../file.txt"
66+ end
67+
68+ test "linux paths" do
69+ refute_attack "/etc/passwd" , "/etc/"
70+ assert_attack "/etc/passwd" , "/etc/passwd"
71+ assert_attack "/etc/../etc/passwd" , "/etc/../etc/passwd"
72+ assert_attack "/home/user/file.txt" , "/home/user"
73+ end
74+
75+ test "possible bypasses" do
76+ assert_attack "/./etc/passwd" , "/./etc/passwd"
77+ assert_attack "/./././root/file.txt" , "/./././root/"
78+ assert_attack "/./././root/file.txt" , "/./././root/file.txt"
79+ end
80+
81+ test "does not detect if user input path contains no filename or subfolder" do
82+ refute_attack "/etc/app/test.txt" , "/etc/"
83+ refute_attack "/etc/app/" , "/etc/"
84+ refute_attack "/etc/app/" , "/etc"
85+ refute_attack "/etc/" , "/etc/"
86+ refute_attack "/etc" , "/etc"
87+ refute_attack "/var/a" , "/var/"
88+ refute_attack "/var/a" , "/var/b"
89+ refute_attack "/var/a" , "/var/b/test.txt"
90+ end
91+
92+ test "it does dected if user input path contains a filename or subfolder" do
93+ assert_attack "/etc/app/file.txt" , "/etc/app"
94+ assert_attack "/etc/app/file.txt" , "/etc/app/file.txt"
95+ assert_attack "/var/backups/file.txt" , "/var/backups"
96+ assert_attack "/var/backups/file.txt" , "/var/backups/file.txt"
97+ assert_attack "/var/a" , "/var/a"
98+ assert_attack "/var/a/b" , "/var/a"
99+ assert_attack "/var/a/b/test.txt" , "/var/a"
100+ end
101+ end
0 commit comments