Issues (119)

tests/test_rules.py (18 issues)

1
from time import strftime, localtime
2
import re
3
4
from spike.model import db
5
from spike.model.naxsi_rules import NaxsiRules
6
7
from tests import TestsThatNeedsRules
8
9
try:
10
    from urlparse import urlparse
11
except ImportError:  # python3
12
    from urllib.parse import urlparse
13
14
15
class FlaskrTestCase(TestsThatNeedsRules):
16
    def test_index(self):
17
        rv = self.app.get('/', follow_redirects=True)
18
        self.assertEqual(rv.status_code, 200)
19
        self.assertIn('<title>SPIKE! - WAF Rules Builder</title>', str(rv.data))
20
        self.assertTrue(re.search(r'<h2>Naxsi - Rules \( \d+ \)</h2>', str(rv.data)) is not None)
21
22
    def test_view(self):
23
        _rule = NaxsiRules.query.order_by(NaxsiRules.sid.desc()).first()
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
24
        rv = self.app.get('/rules/view/%d' % _rule.sid)
25
        self.assertEqual(rv.status_code, 200)
26
27
        _sid = _rule.sid + 1
28
        rv = self.app.get('/rules/view/%d' % _sid)
29
        self.assertEqual(urlparse(rv.location).path, '/rules/')
30
31
    def test_new_rule(self):
32
        rv = self.app.get('/rules/new')
33
        self.assertEqual(rv.status_code, 200)
34
35
        data = {
36
            'msg': 'this is a test message',
37
            'detection': 'str:DETECTION',
38
            'mz': 'BODY',
39
            'custom_mz_val': '',
40
            'negative': 'checked',
41
            'score_$SQL': 8,
42
            'score': '$SQL',
43
            'rmks': 'this is a test remark',
44
            'ruleset': 'WEB_APPS'
45
        }
46
        self.app.post('/rules/new', data=data, follow_redirects=True)
47
48
        _rule = NaxsiRules.query.order_by(NaxsiRules.sid.desc()).first()
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
49
50
        self.assertEqual(_rule.msg, data['msg'])
51
        self.assertEqual(_rule.detection, data['detection'])
52
        self.assertEqual(_rule.mz, data['mz'])
53
        self.assertEqual(_rule.score, data['score'] + ':' + str(data['score_$SQL']))
54
        self.assertEqual(_rule.rmks, data['rmks'])
55
        self.assertEqual(_rule.ruleset, data['ruleset'])
56
        db.session.delete(_rule)
57
        db.session.commit()
58
59
        # Try to insert an invalid rule
60
        _sid = NaxsiRules.query.order_by(NaxsiRules.sid.desc()).first().sid
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
61
        data['detection'] = 'this string does not start with "str:" or "rx:", sorry'
62
        rv = self.app.post('/rules/new', data=data)
63
        self.assertEqual(rv.status_code, 302)
64
        self.assertEqual(_sid, NaxsiRules.query.order_by(NaxsiRules.sid.desc()).first().sid)
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
65
66
    def test_save_rule(self):
67
        rv = self.app.get('/rules/save')
68
        self.assertEqual(rv.status_code, 404)
69
70
        data = {
71
            'msg': 'POUET',
72
            'detection': 'str:test',
73
            'mz': 'BODY',
74
            'custom_mz_val': '',
75
            'negative': 'checked',
76
            'score_$SQL': 8,
77
            'score': '$SQL',
78
            'rmks': 'f hqewifueiwf hueiwhf uiewh fiewh fhw',
79
            'ruleset': 'WEB_APPS'
80
        }
81
        _rule = NaxsiRules.query.order_by(NaxsiRules.sid.desc()).first()
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
82
        rv = self.app.post('/rules/save/{0}'.format(_rule.sid), data=data, follow_redirects=True)
83
84
        self.assertIn(data['msg'], str(rv.data))
85
        self.assertIn(data['detection'], str(rv.data))
86
        self.assertIn(data['mz'], str(rv.data))
87
        self.assertIn(data['score'], str(rv.data))
88
        self.assertIn(data['rmks'], str(rv.data))
89
        self.assertIn(data['ruleset'], str(rv.data))
90
91
        _rule = NaxsiRules.query.order_by(NaxsiRules.sid.desc()).first()
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
92
        data['detection'] = 'rx:^lol$'
93
        rv = self.app.post('/rules/save/{0}'.format(_rule.sid), data=data, follow_redirects=True)
94
        self.assertIn(data['detection'], str(rv.data))
95
96
        _rule = NaxsiRules.query.order_by(NaxsiRules.sid.desc()).first()
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
97
        data['detection'] = 'not str: nor rx:'
98
        rv = self.app.post('/rules/save/{0}'.format(_rule.sid), data=data)
99
        self.assertEqual(rv.status_code, 302)
100
        self.assertEqual(urlparse(rv.location).path, '/rules/edit/{}'.format(_rule.sid))
101
102
        _rule = NaxsiRules.query.order_by(NaxsiRules.sid.desc()).first()
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
103
        db.session.delete(_rule)
104
        db.session.commit()
105
106
    def test_del_rule(self):
107
        _rule = NaxsiRules.query.order_by(NaxsiRules.sid.desc()).first()
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
108
109
        db.session.add(NaxsiRules(u'PIF', 'str:test', u'BODY', u'$SQL:8', _rule.sid + 1, u'WEB_APPS',
110
                                  u'f hqewifueiwf hueiwhf uiewh fiewh fhw', '1', True, 1457101045))
111
        _sid = _rule.sid + 1
112
        rv = self.app.get('/rules/del/%d' % _sid)
113
        self.assertEqual(rv.status_code, 302)
114
115
        _rule = NaxsiRules.query.order_by(NaxsiRules.sid.desc()).first()
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
116
        self.assertEqual(_rule.sid, _rule.sid)
117
118
    def test_plain_rule(self):
119
        _rule = NaxsiRules.query.order_by(NaxsiRules.sid.desc()).first()
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
120
        rv = self.app.get('/rules/plain/%d' % _rule.sid)
121
        self.assertEqual(rv.status_code, 200)
122
        rdate = strftime("%F - %H:%M", localtime(float(str(_rule.timestamp))))
123
        rmks = "# ".join(_rule.rmks.strip().split("\n"))
124
        expected = """#
125
# sid: {0} | date: {1}
126
#
127
# {2}
128
#
129
{3}""".format(_rule.sid, rdate, rmks, str(_rule))
130
        self.assertEqual(expected.encode(), rv.data)
131
132
    def test_deact_rule(self):
133
        last_insert = NaxsiRules.query.order_by(NaxsiRules.sid.desc()).first().sid
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
134
135
        rv = self.app.get('/rules/deact/%d' % last_insert)  # deactivate
136
        self.assertEqual(rv.status_code, 200)
137
        _rule = NaxsiRules.query.filter(NaxsiRules.sid == last_insert).first()
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
138
        self.assertEqual(_rule.active, 0)
139
140
        rv = self.app.get('/rules/deact/%d' % last_insert)  # activate
141
        self.assertEqual(rv.status_code, 200)
142
        _rule = NaxsiRules.query.filter(NaxsiRules.sid == last_insert).first()
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
143
        self.assertEqual(_rule.active, 1)
144
145
        non_existent_sid = last_insert + 1
146
        rv = self.app.get('/rules/deact/%d' % non_existent_sid)
147
        self.assertEqual(rv.status_code, 302)
148
149
        rv = self.app.get('/rules/deact/')
150
        self.assertEqual(rv.status_code, 404)
151
152
    def test_search_rule(self):
153
        rv = self.app.get('/rules/search/')
154
        self.assertEqual(rv.status_code, 302)
155
156
        rv = self.app.get('/rules/search/?s=a')
157
        self.assertEqual(rv.status_code, 302)
158
159
        rv = self.app.get('/rules/search/?s="OR 1=1;--')
160
        self.assertEqual(rv.status_code, 200)
161
        self.assertIn('value="&#34;OR 1=1;--"', str(rv.data))
162
        self.assertIn('<p><strong>Search: OR 11--</strong></p>', str(rv.data))  # filtered data
163
164
        rv = self.app.get('/rules/search/?s=1337')  # get rule by id
165
        self.assertEqual(rv.status_code, 200)
166
167
        rv = self.app.get('/rules/search/?s=cve:2015-1234')  # get rule by id
168
        self.assertEqual(rv.status_code, 200)
169
170
    def test_edit_rule(self):
171
        non_existent_sid = NaxsiRules.query.order_by(NaxsiRules.sid.desc()).first().sid + 1
0 ignored issues
show
The Class NaxsiRules does not seem to have a member named query.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
172
        rv = self.app.get('/rules/edit/%d' % non_existent_sid)
173
        self.assertEqual(rv.status_code, 302)
174
175
    def test_parse_rule(self):
176
        rule_parser = NaxsiRules()
177
178
        errors, warnings, ret = rule_parser.parse_rule('MainRule "rx:select|union|update|delete|insert|table|from|ascii|hex|unhex|drop"'
0 ignored issues
show
This line is too long as per the coding-style (136/120).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
The variable ret seems to be unused.
Loading history...
179
                                    '"msg:sql keywords" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1000;')
180
        self.assertEqual(warnings,
181
                         ['Cookie in $HEADERS_VAR:Cookie is not lowercase. naxsi is case-insensitive',
182
                          'rule IDs below 10k are reserved (1000)'])
183
184
        errors, warnings, ret = rule_parser.parse_rule('BasicRule "rx:^ratata$" "mz:$URL:/foobar" '
185
                                    'id:4200001 "s:$SQL:8";')
186
        self.assertIn('$URL', str(errors))
187
        self.assertIn("The rule/whitelist doesn\'t target any zone.", str(errors))
188
        self.assertIn("Parsing of element \'mz:$URL:/foobar\' failed.", str(errors))
189
190
        errors, warnings, ret = rule_parser.parse_rule('"rx:^ratata$" "mz:$URL:/foobar|$BODY_VAR_X:^tutu$"'
191
                                    'id:4200001 "s:$SQL:8";')
192
        self.assertIn('No mainrule/basicrule keyword.', str(errors))
193
194
        errors, warnings, ret = rule_parser.parse_rule('MainRule BasicRule "rx:select"'
195
                                    '"msg:sql keywords" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1000;')
196
        self.assertEqual(['Both BasicRule and MainRule are present.'], errors)
197
198
        errors, warnings, ret = rule_parser.parse_rule('MainRule "rx:select"'
199
                                    '"msg:sql keywords" "mz:BODY" "s:$SQL:4" id:1000 "wrong:LOL";')
200
        self.assertIn("'wrong:LOL' is an invalid element and thus can not be parsed.", str(errors))
201
202
        errors, warnings, ret = rule_parser.parse_rule('MainRule "rx:select"'
203
                                    '"msg:sql keywords" "mz:BODY" "s:$SQL:4" "id:non_numeric";')
204
        self.assertEqual(['id:non_numeric is not numeric', "Parsing of element 'id:non_numeric' failed."],
205
                         errors)
206
207
        errors, warnings, ret = rule_parser.parse_rule('MainRule "rx:select" "mz:wrong" "msg:sql keywords" "s:$SQL:4" "id:10000";')
0 ignored issues
show
This line is too long as per the coding-style (131/120).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
208
        self.assertIn("'wrong' is not a known sub-part of mz : ", str(errors))
209
        self.assertIn("Parsing of element 'mz:wrong' failed.", str(errors))
210