nasl-pedant 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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