nasl-pedant 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,189 @@
1
+ ################################################################################
2
+ # Copyright (c) 2016, Tenable Network Security
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright notice, this
9
+ # list of conditions and the following disclaimer.
10
+ #
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+ ################################################################################
26
+
27
+ module Pedant
28
+ class CheckSocketLeak < Check
29
+ def self.requires
30
+ super + [:trees]
31
+ end
32
+
33
+ ##
34
+ # Breaks the tree up into functions and feeds them into block_parser
35
+ # @param file the current file being examined
36
+ # @param tree the entire file tree
37
+ ##
38
+ def check(file, tree)
39
+
40
+ ##
41
+ # If the allFound contains anything then throw up a warning
42
+ ##
43
+ def report_findings(allFound)
44
+ if allFound.size() > 0
45
+ warn
46
+ output = ""
47
+ allFound.each do |handle|
48
+ if !output.empty?
49
+ output += ", "
50
+ end
51
+ if handle == ""
52
+ handle = "<unassigned>"
53
+ end
54
+ output += handle
55
+ end
56
+ report(:warn, "Possibly leaked socket handle(s): " + output)
57
+ end
58
+ end
59
+
60
+ ##
61
+ # Examines a single passed in node and tries to appropriately handle it
62
+ # based on the type. This function ignores "g_sock" and _ssh_socket as both
63
+ # of these are handled in a way that this parser can't really handle
64
+ #
65
+ # @param bnode the node to examine
66
+ # @param found a set of active "open_sock_tcp" items
67
+ # @return the new list of open_sock_tcp items
68
+ ##
69
+ def node_parser(bnode, found)
70
+ if bnode.is_a?(Nasl::Assignment)
71
+ name = ""
72
+ if bnode.lval.is_a?(Nasl::Lvalue)
73
+ name = bnode.lval.ident.name;
74
+ end
75
+ if bnode.expr.is_a?(Nasl::Call)
76
+ if ((bnode.expr.name.ident.name == "open_sock_tcp" ||
77
+ bnode.expr.name.ident.name == "http_open_socket") &&
78
+ name != "g_sock" && name != "_ssh_socket")
79
+ found.add(name)
80
+ end
81
+ end
82
+ elsif bnode.is_a?(Nasl::Local)
83
+ bnode.idents.each do |idents|
84
+ if idents.is_a?(Nasl::Assignment)
85
+ name = ""
86
+ if idents.lval.is_a?(Nasl::Lvalue)
87
+ name = idents.lval.ident.name
88
+ elsif idents.lval.is_a?(Nasl::Identifier)
89
+ name = idents.lval.name
90
+ end
91
+ if idents.expr.is_a?(Nasl::Call)
92
+ if ((idents.expr.name.ident.name == "open_sock_tcp" ||
93
+ idents.expr.name.ident.name == "http_open_socket") &&
94
+ name != "g_sock" && name != "_ssh_socket")
95
+ found.add(name)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ elsif bnode.is_a?(Nasl::Return)
101
+ # if the socket we are tracking gets returned then never mark it as
102
+ # a leak
103
+ if bnode.expr.is_a?(Nasl::Lvalue)
104
+ found = found - [bnode.expr.ident.name]
105
+ end
106
+ elsif (bnode.is_a?(Nasl::Break) || bnode.is_a?(Nasl::Continue) ||
107
+ (bnode.is_a?(Nasl::Call) && (bnode.name.ident.name == "exit" ||
108
+ bnode.name.ident.name == "audit")))
109
+ report_findings(found)
110
+ elsif bnode.is_a?(Nasl::If)
111
+ if (bnode.cond.is_a?(Nasl::Expression) and bnode.cond.rhs.is_a?(Nasl::Lvalue))
112
+ if bnode.cond.op.to_s() == "!"
113
+ if found.any? {|varName| varName == bnode.cond.rhs.ident.name}
114
+ # don't go down this path. This is the !soc path
115
+ return found;
116
+ end
117
+ end
118
+ end
119
+ # the if statement provides us with a block we can peak down to.
120
+ # However, it isn't always enumerable so handle accordingly
121
+ if (bnode.true.is_a?(Enumerable))
122
+ found = block_parser(bnode.true, found)
123
+ else
124
+ found = node_parser(bnode.true, found);
125
+ end
126
+ if (bnode.false.is_a?(Enumerable))
127
+ found = block_parser(bnode.false, found)
128
+ else
129
+ found = node_parser(bnode.false, found);
130
+ end
131
+ elsif bnode.is_a?(Nasl::Block)
132
+ found = block_parser(bnode.body, found);
133
+ elsif bnode.is_a?(Nasl::Call)
134
+ if (bnode.name.ident.name == "open_sock_tcp" ||
135
+ bnode.name.ident.name == "http_open_socket")
136
+ found.add("")
137
+ elsif (bnode.name.ident.name == "close" ||
138
+ bnode.name.ident.name == "ftp_close" ||
139
+ bnode.name.ident.name == "http_close_socket" ||
140
+ bnode.name.ident.name == "smtp_close")
141
+ # Check that this is an Lvalue. It could be a call or something
142
+ # which is just too complicated to handle and doesn't really work
143
+ # with our variable tracking system
144
+ if bnode.args[0].expr.is_a?(Nasl::Lvalue)
145
+ found = found - [bnode.args[0].expr.ident.name]
146
+ end
147
+ elsif (bnode.name.ident.name == "session_init" ||
148
+ bnode.name.ident.name == "ssh_close_connection")
149
+ pass
150
+ end
151
+ end
152
+ return found
153
+ end
154
+
155
+ ##
156
+ # Iterates over the blocks and hands individual nodes up to the node_parser
157
+ # @param block the current Block node to examine
158
+ # @param found the current list of found open_sock_tcp
159
+ # @param all the found open_sock_tcp that haven't been closed
160
+ ##
161
+ def block_parser(block, found)
162
+ block.each do |node|
163
+ found = node_parser(node, found);
164
+ end
165
+ return found;
166
+ end
167
+
168
+ # Extract by the block. Will help us since we don't dive down into all
169
+ # blocks as of yet (only if statements)
170
+ allFound = Set.new
171
+ tree.all(:Function).each do |node|
172
+ allFound.merge(block_parser(node.body, Set.new))
173
+ end
174
+
175
+ # The main body of a file is not a Block, so it must be considered
176
+ # separately.
177
+ allFound.merge(block_parser(tree, Set.new))
178
+ report_findings(allFound)
179
+ end
180
+
181
+ def run
182
+ # This check will pass by default.
183
+ pass
184
+
185
+ # Run this check on the tree from every file.
186
+ @kb[:trees].each { |file, tree| check(file, tree) }
187
+ end
188
+ end
189
+ end
@@ -1,3 +1,3 @@
1
1
  module Pedant
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
data/pedant.gemspec CHANGED
@@ -51,4 +51,5 @@ Gem::Specification.new do |s|
51
51
 
52
52
  s.add_runtime_dependency 'rainbow', '=2.0.0'
53
53
  s.add_runtime_dependency 'nasl', '~> 0.2', '>= 0.2.0'
54
+ s.add_runtime_dependency 'test-unit-minitest'
54
55
  end
@@ -0,0 +1,53 @@
1
+ ################################################################################
2
+ # Copyright (c) 2016, Tenable Network Security
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright notice, this
9
+ # list of conditions and the following disclaimer.
10
+ #
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+ ################################################################################
26
+
27
+ class TestContainsDisplay < Test::Unit::TestCase
28
+ include Pedant::Test
29
+
30
+ def test_empty
31
+ check(
32
+ :pass,
33
+ :CheckContainsDisplay,
34
+ %Q||
35
+ )
36
+ end
37
+
38
+ def test_with_display
39
+ check(
40
+ :warn,
41
+ :CheckContainsDisplay,
42
+ %q|display("test"); exit(0);|
43
+ )
44
+ end
45
+
46
+ def test_without
47
+ check(
48
+ :pass,
49
+ :CheckContainsDisplay,
50
+ %q|exit(0);|
51
+ )
52
+ end
53
+ end
@@ -40,6 +40,12 @@ class TestContainsUnreachableCode < Test::Unit::TestCase
40
40
  %q|exit(); foo();|
41
41
  )
42
42
 
43
+ check(
44
+ :fail,
45
+ :CheckContainsUnreachableCode,
46
+ %q|audit(); foo();|
47
+ )
48
+
43
49
  check(
44
50
  :fail,
45
51
  :CheckContainsUnreachableCode,
@@ -100,4 +106,12 @@ class TestContainsUnreachableCode < Test::Unit::TestCase
100
106
  %q|{ exit.foo(); foo(); }|
101
107
  )
102
108
  end
109
+
110
+ def audit_indexed_exit
111
+ check(
112
+ :pass,
113
+ :CheckContainsUnreachableCode,
114
+ %q|{ audit.foo(); foo(); }|
115
+ )
116
+ end
103
117
  end
@@ -0,0 +1,105 @@
1
+ ################################################################################
2
+ # Copyright (c) 2016, Tenable Network Security
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright notice, this
9
+ # list of conditions and the following disclaimer.
10
+ #
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+ ################################################################################
26
+
27
+ class TestGetByteUsed< Test::Unit::TestCase
28
+ include Pedant::Test
29
+
30
+ def test_get_byte_used
31
+ check(
32
+ :fail,
33
+ :CheckGetByteUsed,
34
+ %q|get_byte(blob:blah, pos:10);|
35
+ )
36
+ end
37
+
38
+ def test_get_word_used
39
+ check(
40
+ :fail,
41
+ :CheckGetByteUsed,
42
+ %q|get_word(blob:blah, pos:10);|
43
+ )
44
+ end
45
+
46
+ def test_get_dword_used
47
+ check(
48
+ :fail,
49
+ :CheckGetByteUsed,
50
+ %q|get_dword(blob:blah, pos:10);|
51
+ )
52
+ end
53
+
54
+ def test_getbyte_used
55
+ check(
56
+ :pass,
57
+ :CheckGetByteUsed,
58
+ %q|getbyte(blob:blah, pos:10);|
59
+ )
60
+ end
61
+
62
+ def test_getword_used
63
+ check(
64
+ :pass,
65
+ :CheckGetByteUsed,
66
+ %q|getword(blob:blah, pos:10);|
67
+ )
68
+ end
69
+
70
+ def test_getdword_used
71
+ check(
72
+ :pass,
73
+ :CheckGetByteUsed,
74
+ %q|getdword(blob:blah, pos:10);|
75
+ )
76
+ end
77
+
78
+ def test_get_byte_used_with_set_byte_order
79
+ check(
80
+ :fail,
81
+ :CheckGetByteUsed,
82
+ %q|set_byte_order(BYTE_ORDER_LITTLE_ENDIAN);| +
83
+ %q|get_byte(blob:blah, pos:10);|
84
+ )
85
+ end
86
+
87
+ def test_get_word_used_with_set_byte_order
88
+ check(
89
+ :fail,
90
+ :CheckGetByteUsed,
91
+ %q|set_byte_order(BYTE_ORDER_LITTLE_ENDIAN);| +
92
+ %q|get_word(blob:blah, pos:10);|
93
+ )
94
+ end
95
+
96
+ def test_get_dword_used_with_set_byte_order
97
+ check(
98
+ :fail,
99
+ :CheckGetByteUsed,
100
+ %q|set_byte_order(BYTE_ORDER_LITTLE_ENDIAN);| +
101
+ %q|get_dword(blob:blah, pos:10);|
102
+ )
103
+ end
104
+
105
+ end
@@ -0,0 +1,61 @@
1
+ ################################################################################
2
+ # Copyright (c) 2011-2016, Tenable Network Security
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright notice, this
9
+ # list of conditions and the following disclaimer.
10
+ #
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+ ################################################################################
26
+
27
+ class TestScriptDoesNotUseAuditDotInc < Test::Unit::TestCase
28
+ include Pedant::Test
29
+
30
+ def test_does
31
+ check(
32
+ :pass,
33
+ :CheckScriptDoesNotUseAuditDotInc,
34
+ %q|include("audit.inc");|+
35
+ %q|audit(AUDIT_hahaha,"really");|
36
+ )
37
+ check(
38
+ :pass,
39
+ :CheckScriptDoesNotUseAuditDotInc,
40
+ %q|include('audit.inc');|+
41
+ %q|audit(AUDIT_hahaha,"yeah really");|
42
+ )
43
+ end
44
+
45
+ def test_does_no_audit_call
46
+ check(
47
+ :warn,
48
+ :CheckScriptDoesNotUseAuditDotInc,
49
+ %q|include("audit.inc");|
50
+ )
51
+ end
52
+
53
+ def test_unexpected
54
+ check(
55
+ :fail,
56
+ :CheckScriptDoesNotUseAuditDotInc,
57
+ %q|include('audit.inc');|+
58
+ %q|include("audit.inc");|
59
+ )
60
+ end
61
+ end