violent_ruby 1.0.0

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,38 @@
1
+ # Unix Password Cracker
2
+
3
+ The unix password cracker provide a simple interface to crack unix passwords. As hackers do.
4
+
5
+ ## Initialization
6
+
7
+ You can create a new password cracker in a few ways. You can set the `/etc/passwd` and `dictionary` file later if you want to:
8
+
9
+ ### Create a new Unix Password Cracker, with a Config
10
+
11
+ ```ruby
12
+ require 'violent_ruby'
13
+ config = { file: "/etc/passwd", dictionry: "dictionary.txt" }
14
+ upc = ViolentRuby::UnixPasswordCracker.new(config)
15
+ ```
16
+
17
+ ### Create a new Unix Password Cracker, setting stuff later
18
+
19
+ ```ruby
20
+ require 'violent_ruby'
21
+ upc = ViolentRuby::UnixPasswordCracker.new
22
+ upc.file = "/etc/passwd"
23
+ upc.dictionary = "dictionary.txt"
24
+ ```
25
+
26
+ ## Several Ways to Crack'a Password
27
+
28
+ Because aliases are fun. You can crack passwords in a few ways.
29
+
30
+ ```ruby
31
+ require 'violent_ruby'
32
+ upc = ViolentRuby::UnixPasswordCracker.new(file: "/etc/passwd", dictionry: "dictionary.txt")
33
+ upc.crack_passwords
34
+ upc.crack!
35
+ upc.get_crackn
36
+ up.release_the_kraken
37
+ ```
38
+
@@ -0,0 +1,117 @@
1
+ module ViolentRuby
2
+ # Unix Password Cracker provides a friendly interface to
3
+ # crack unix passwords. Because all hackers totes do this.
4
+ # @author Kent 'picat' Gruber
5
+ #
6
+ # == Create a new Unix Password Cracker
7
+ # In order for the password cracker to work, we're going to need a +dictionary+,
8
+ # and an /etc/passwd +file+ we want to crack.
9
+ #
10
+ # @example Basic Usage
11
+ # config = { file: "/etc/passwd", dictionry: "dictionary.txt" }
12
+ # upc = ViolentRuby::UnixPasswordCracker.new(config)
13
+ # upc.crack!
14
+ class UnixPasswordCracker
15
+ # @attr [String] file Path to /etc/passwd file.
16
+ attr_accessor :file
17
+ # @attr [String] dictionary Path to dictionary file.
18
+ attr_accessor :dictionary
19
+
20
+ # Create a new Unix Password Cracker.
21
+ #
22
+ # @param [Hash] args The options to create a new Unix Password Cracker.
23
+ # @param args [String] :file The path to an /etc/passwd file.
24
+ # @param args [String] :dictionary The path to a dictionry of passwords.
25
+ def initialize(args = {})
26
+ @file = false
27
+ @dictionary = false
28
+ if args[:file] && File.readable?(args[:file])
29
+ @file = args[:file]
30
+ @credentials = parse_etc_file(file: args[:file])
31
+ end
32
+ return unless args[:dictionary]
33
+ return unless File.readable?(args[:dictionary])
34
+ @dictionary = args[:dictionary]
35
+ end
36
+
37
+ # Parse a unix /etc/passwd file into a more mangeable form.
38
+ #
39
+ # @param [Hash] args The options when parsing the file.
40
+ # @param args [String] :file The path to an /etc/passwd file.
41
+ # @param args [Boolean] :users Specify that only users should be returned ( default: +false+ ).
42
+ # @param args [Boolean] :passwords Specify that only passwords should be returned ( default: +false+ ).
43
+ # @return [Hash]
44
+ def parse_etc_file(args = {})
45
+ raise 'No /etc/passwd file given.' unless args[:file]
46
+ raise "File #{args[:file]} not readable!" unless File.readable?(args[:file])
47
+ lines = File.readlines(args[:file]).collect do |line|
48
+ line unless line.split(':').first.chars.first.include?('#')
49
+ end
50
+ users = lines.collect { |x| x.split(':')[0] }.map(&:strip)
51
+ return users if args[:users]
52
+ passwords = lines.collect { |x| x.split(':')[1] }.map(&:strip)
53
+ return passwords if args[:passwords]
54
+ users_passwords = Hash[users.zip(passwords)]
55
+ if block_given?
56
+ users_passwords.each do |user, password|
57
+ yield user, password
58
+ end
59
+ else
60
+ users_passwords
61
+ end
62
+ end
63
+
64
+ # Crack unix passwords.
65
+ #
66
+ # @param [Hash] args The options when crack'n some passwords.
67
+ # @param args [String] :file The path to an /etc/passwd file.
68
+ # @param args [String] :dictionary The path to a dictionry of passwords.
69
+ # @return [Array<Hash>]
70
+ def crack_passwords(args = {})
71
+ file = args[:file] || @file
72
+ dict = args[:dictionary] || @dictionary
73
+ results = []
74
+ parse_etc_file(file: file) do |user, password|
75
+ File.readlines(dict).map(&:strip).each do |word|
76
+ results << format_result(user, password, word) if cracked?(password, word)
77
+ end
78
+ end
79
+ results
80
+ end
81
+
82
+ alias crack! crack_passwords
83
+
84
+ alias get_crackn crack_passwords
85
+
86
+ alias release_the_kraken crack_passwords
87
+
88
+ # Check if a given encrypted password matches a given plaintext
89
+ # word when the same crytographic operation is performed on it.
90
+ #
91
+ # @param [String] encrypted_password The encrypted password to check against.
92
+ # @param [String] word The plaintext password to check against.
93
+ # @return [Boolean]
94
+ def check_password(encrypted_password, word)
95
+ if word.strip.crypt(encrypted_password[0, 2]) == encrypted_password
96
+ true
97
+ else
98
+ false
99
+ end
100
+ end
101
+
102
+ alias cracked? check_password
103
+
104
+ private
105
+
106
+ # @api private
107
+ # Format the results for the password crack'n.
108
+ #
109
+ # @param [String] user
110
+ # @param [String] encrypted_pass
111
+ # @param [String] plaintext_pass
112
+ # @return [Hash]
113
+ def format_result(user, encrypted_pass, plaintext_pass)
114
+ { username: user, encrypted_password: encrypted_pass, plaintext_password: plaintext_pass }
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,3 @@
1
+ module ViolentRuby
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,88 @@
1
+ # Vulnerability Scanner
2
+
3
+ The vulnerability scanner class provides a simple way to check if service banners match a list of known vulnerabilities.
4
+
5
+ ## Initialization
6
+
7
+ The Vulnerability Scanner scanner class can be setup in a few flexible ways.
8
+
9
+ ### Basic Setup
10
+
11
+ Provide no targets, ip addresses or even a file. I'll be there for you~
12
+
13
+ ```ruby
14
+ require 'violent_ruby'
15
+ scanner = ViolentRuby::VulnerabilityScanner.new
16
+ ```
17
+
18
+ ### Provide Some Targets with Setup
19
+
20
+ Targets are the known IP addresses for the scanner class. Though, note: you can scan IP addresses that are set during the scan method call. Because I do like flexibility quite a bit, don't I?
21
+
22
+ ```ruby
23
+ require 'violent_ruby'
24
+ ipaddrs = ['192.168.0.2', '192.168.0.3', '192.168.0.4']
25
+ scanner = ViolentRuby::VulnerabilityScanner.new(targets: ipaddrs)
26
+ ```
27
+
28
+ ### Provide a Dictionary with Setup
29
+
30
+ Because you can do that.
31
+
32
+ ```ruby
33
+ require 'violent_ruby'
34
+ scanner = ViolentRuby::VulnerabilityScanner.new(dictionary: "known_vulnerable_banners.txt")
35
+ ```
36
+
37
+ ## Banner Grabbing
38
+
39
+ Maybe you just wana grab some banners? I feel you bruhv. Let's do that.
40
+
41
+ ### Grab Banner from 192.168.0.2 on port 8080
42
+
43
+ ```ruby
44
+ require 'violent_ruby'
45
+ scanner = ViolentRuby::VulnerabilityScanner.new
46
+ scanner.retrieve_banner('192.168.0.2', 8080)
47
+ # => "MS-IIS WEB SERVER 5.0"
48
+ ```
49
+
50
+ ### Banner Grabbing, in'a Block
51
+
52
+ Because maybe expressing things in blocks is just the best thing every.
53
+
54
+ ```ruby
55
+ require 'violent_ruby'
56
+ scanner = ViolentRuby::VulnerabilityScanner.new
57
+ scanner.retrieve_banner('192.168.0.2', 8080) do |banner|
58
+ puts "Banner found: " + banner if banner
59
+ end
60
+ ```
61
+
62
+ ## Basic Scanning
63
+
64
+ The Vulnerability Scanner class does have a `scan()` method, because that makes a lot of sense!
65
+
66
+ ### Method to the Madness
67
+
68
+ The scan method provides most of the underlying magic for this class.
69
+
70
+ ```ruby
71
+ require 'violent_ruby'
72
+ scanner = ViolentRuby::VulnerabilityScanner.new
73
+ scanner.scan(ip: "192.168.0.2", port: 8080, file: "dictionary.txt")
74
+ ```
75
+
76
+ ```ruby
77
+ require 'violent_ruby'
78
+ scanner = ViolentRuby::VulnerabilityScanner.new
79
+ scanner.scan(ips: ["192.168.0.2", "192.168.0.3" ], port: 8080, file: "dictionary.txt")
80
+ ```
81
+
82
+ ```ruby
83
+ require 'violent_ruby'
84
+ scanner = ViolentRuby::VulnerabilityScanner.new
85
+ scanner.file = "dictionary.txt"
86
+ scanner.scan(ips: ["192.168.0.2", "192.168.0.3" ], ports: [80, 8080])
87
+ ```
88
+
@@ -0,0 +1,275 @@
1
+ require 'socket'
2
+ require 'timeout'
3
+
4
+ module ViolentRuby
5
+ # Vulnerability Scanner provides a friendly interface to easily manage
6
+ # banner grabbing +targets+ to match a list of +known vulnerable services+
7
+ # that we want to identify.
8
+ # @author Kent 'picat' Gruber
9
+ #
10
+ # == Create a new Vulnerability Scanner
11
+ # The Vulnerability Scanner scanner class can be setup in a few flexible ways.
12
+ #
13
+ # @example Provide no targets, ip addresses or even a file.
14
+ # scanner = ViolentRuby::VulnerabilityScanner.new
15
+ #
16
+ # @example Provide targets.
17
+ # ipaddrs = ['192.168.0.2', '192.168.0.3', '192.168.0.4']
18
+ # scanner = ViolentRuby::VulnerabilityScanner.new(targets: ipaddrs)
19
+ #
20
+ # @example Provide a file of known vulnerabilities.
21
+ # scanner = ViolentRuby::VulnerabilityScanner.new(known_vulnerabilities: "vuln_banners.txt")
22
+ #
23
+ # @example Just set targets and provide a file later.
24
+ # scanner = ViolentRuby::VulnerabilityScanner.new
25
+ # ['192.168.0.2', '192.168.0.3'].each do |ip|
26
+ # scanner.targets << ip
27
+ # end
28
+ # scanner.targets
29
+ # # => ['192.168.0.2', '192.168.0.3']
30
+ # File.readlines("vuln_banners.txt").map(&:strip).each |banner|
31
+ # scanner.known_vulnerabilities << banner
32
+ # end
33
+ # # => ['MS-IIS WEB SERVER 4.0', 'MS-IIS WEB SERVER 5.0']
34
+ # scanner.scan
35
+ #
36
+ # == Banner Grabbing
37
+ # The Vulnerability Scanner provides a simple banner grabbing method which can be used.
38
+ #
39
+ # @example Connect to 192.168.0.2 on port 8080
40
+ # scanner = ViolentRuby::VulnerabilityScanner.new
41
+ #
42
+ # # If no banner, or hit timeout.
43
+ # scanner.retrieve_banner('192.168.0.2', 8080)
44
+ # # => false
45
+ #
46
+ # # If banner exists.
47
+ # scanner.retrieve_banner('192.168.0.2', 80)
48
+ # # => "MS-IIS WEB SERVER 5.0"
49
+ #
50
+ # @example Connect to 192.168.0.2 on port 8080, trying for 10 seconds
51
+ # scanner = ViolentRuby::VulnerabilityScanner.new
52
+ # scanner.retrieve_banner('192.168.0.2', 8080, 10)
53
+ #
54
+ # @example Connect to 192.168.0.2 on port 8080, with a given block
55
+ # scanner = ViolentRuby::VulnerabilityScanner.new
56
+ # scanner.retrieve_banner('192.168.0.2', 8080) do |banner|
57
+ # # do something with banner ( false if none found )
58
+ # if banner
59
+ # puts "Banner found: " + banner
60
+ # else
61
+ # puts "Banner not found."
62
+ # end
63
+ # end
64
+ #
65
+ # == Example Usage
66
+ # The VulnerabilityScanner is meant to be easy and flexible to use.
67
+ #
68
+ # @example Basic
69
+ # require 'violent_ruby'
70
+ # config = { targets: ['192.168.0.2', '192.168.0.3' ], known_vulnerabilities: 'vulns.txt' }
71
+ # scanner = ViolentRuby::VulnerabilityScanner.new(config)
72
+ # scanner.scan
73
+ #
74
+ # @example Advanced (sort'a)
75
+ # require 'violent_ruby'
76
+ # scanner = ViolentRuby::VulnerabilityScanner.new
77
+ # scanner.targets = ['192.168.0.2', '192.168.0.3' ]
78
+ # scanner.known_vulnerabilities = 'vulns.txt'
79
+ # scanner.scan(port: 8080)
80
+ #
81
+ class VulnerabilityScanner
82
+ # @attr [Array<String>] targets List of target ip addresses.
83
+ attr_accessor :targets
84
+ # @attr [Array<String>] known_vulnerabilities List of known vulnerabilities.
85
+ attr_accessor :known_vulnerabilities
86
+
87
+ # Create a new instance of the vulnerability scanner.
88
+ #
89
+ # @param [Hash] args The options to create a new Vulnerability Scanner. Very optional.
90
+ # @param args [Array<String>] :targets The targets to work with.
91
+ # @param args [Array<String>] :known_vulnerabilities A file containing known vulnerabilities.
92
+ # @return [VulnerabilityScanner]
93
+ def initialize(args = {})
94
+ @targets = []
95
+ @known_vulnerabilities = []
96
+ self.targets = args[:targets] if args[:targets]
97
+ self.known_vulnerabilities = args[:known_vulnerabilities] if args[:known_vulnerabilities]
98
+ end
99
+
100
+ # Retrieve a banner from a given ip and port for a given ammount
101
+ # of seconds, or default for two seconds.
102
+ #
103
+ # @param [String] ip Target ip address.
104
+ # @param [Integer] port Target port number.
105
+ # @param [Integer] seconds Timeout value.
106
+ # @return [String,Boolean]
107
+ def retrieve_banner(ip, port, seconds = 2)
108
+ banner = false
109
+ Timeout.timeout(seconds) do
110
+ socket = TCPSocket.new(ip, port)
111
+ banner = socket.recv(1024)
112
+ socket.close
113
+ end
114
+ return false unless banner
115
+ banner.strip!
116
+ yield banner if block_given?
117
+ banner
118
+ rescue
119
+ false
120
+ end
121
+
122
+ # Check if a given banner is included in a given file which
123
+ # should contain a list of vulnerable banners to match
124
+ # against in order to determine vulnerabilities.
125
+ #
126
+ # @param [String] banner Target banner to check.
127
+ # @param optional [String] file A file containing vulnerable banners.
128
+ # @return [Boolean]
129
+ def check_vulnerabilities(banner, file = false)
130
+ if file
131
+ File.readlines(file).map(&:strip).each do |line|
132
+ return true if line.match?(banner)
133
+ end
134
+ else
135
+ @known_vulnerabilities.each do |vulnerability|
136
+ return true if vulnerability.match?(banner)
137
+ end
138
+ end
139
+ false
140
+ end
141
+
142
+ # Human readable alias.
143
+ alias :vulnerable? :check_vulnerabilities
144
+
145
+ # Do the scanning!
146
+ #
147
+ # @param [Hash] args Scan arguments.
148
+ # @param args [String] :ip @see handle_ip
149
+ # @param args [Array<String>] :ips @see handle_ip
150
+ # @param args [Integer] :port @see handle_port
151
+ # @param args [Array<Integer>] :ports @see handle_port
152
+ # @param args [String] :file @see handle_file
153
+ # @param args [Integer] :timeout @see handle_timeout
154
+ # @return [void]
155
+ def scan(args = {})
156
+ ip_addrs = handle_ip(args)
157
+ ports = handle_port(args)
158
+ timeout = handle_timeout(args)
159
+ file = handle_file(args)
160
+ results = []
161
+ ip_addrs.each do |ip|
162
+ ports.each do |port|
163
+ retrieve_banner(ip, port, timeout) do |banner|
164
+ results << result(ip, port, banner) if vulnerable?(banner, file)
165
+ end
166
+ end
167
+ end
168
+ results
169
+ end
170
+
171
+ # @param [String,Array<String>] args Either a IP address or an array of IP addresses.
172
+ # @return [void]
173
+ def targets=(args)
174
+ if args.is_a? String
175
+ @targets << args
176
+ else args.is_a? Array
177
+ args.each { |target| @targets << target }
178
+ end
179
+ end
180
+
181
+ # @param [String,Array<String>] args Either a banner string or an array of banner strings.
182
+ # @return [void]
183
+ def known_vulnerabilities=(args)
184
+ if File.readable?(args)
185
+ File.readlines(args[:known_vulnerabilities]).map(&:strip).each do |line|
186
+ @known_vulnerabilities << line
187
+ end
188
+ elsif args.is_a? String
189
+ @known_vulnerabilities << args
190
+ elsif args.is_a? Array
191
+ args.each { |vulnerability| @known_vulnerabilities << vulnerability }
192
+ end
193
+ end
194
+
195
+ private
196
+
197
+ # @api private
198
+ # This method manages what is done with the result once we know
199
+ # a vulnerable banner is found.
200
+ #
201
+ # @param [String] ip
202
+ # @param [Integer] port
203
+ # @param [String] banner
204
+ # @return [Hash]
205
+ def result(ip, port, banner)
206
+ {ip: ip, port: port, banner: banner}
207
+ end
208
+
209
+ # @api private
210
+ # This method manages dealing with handling the +ip+ arguments
211
+ # for the +scan+ method in a clean manner.
212
+ #
213
+ # @param [Hash] args
214
+ # @param args [String] :ip Single ip address.
215
+ # @param args [Array<String>] :ips Multiple ip addresses.
216
+ # @return [Array<String>]
217
+ def handle_ip(args = {})
218
+ if args[:ip]
219
+ [args[:ip]]
220
+ elsif args[:ips]
221
+ args[:ips]
222
+ else
223
+ @targets
224
+ end
225
+ end
226
+
227
+ # @api private
228
+ # This method manages dealing with handling the +port+ arguments
229
+ # for the +scan+ method in a clean manner.
230
+ #
231
+ # @param [Hash] args
232
+ # @param args [String] :port Single port.
233
+ # @param args [Array<String>] :ips Multiple ports.
234
+ # @return [Array<Integer>]
235
+ def handle_port(args = {})
236
+ if args[:port]
237
+ [args[:port]]
238
+ elsif args[:ports]
239
+ args[:ports]
240
+ else
241
+ [21, 22, 25, 80, 110, 443]
242
+ end
243
+ end
244
+
245
+ # @api private
246
+ # This method manages dealing with handling the +timeout+ argument
247
+ # for the +scan+ method in a clean manner.
248
+ #
249
+ # @param [Hash] args
250
+ # @param args [Integer] :timeout Timeout in seconds.
251
+ # @return [Integer]
252
+ def handle_timeout(args = {})
253
+ if args[:timeout]
254
+ args[:timeout]
255
+ else
256
+ 2
257
+ end
258
+ end
259
+
260
+ # @api private
261
+ # This method manages dealing with handling the +file+ argument
262
+ # for the +scan+ method in a clean manner.
263
+ #
264
+ # @param [Hash] args
265
+ # @param args [Integer] :file File containing vulnerable banners.
266
+ # @return [String, Boolean]
267
+ def handle_file(args = {})
268
+ if args[:file]
269
+ args[:file]
270
+ else
271
+ false
272
+ end
273
+ end
274
+ end
275
+ end