seeker-junos 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ gems
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,34 @@
1
+ # Seeker JunOS
2
+ Finds hidden commands from JunOS devices by brute-forcing commands over SSH
3
+
4
+ ## Install
5
+ ```
6
+ % gem install seeker-junos
7
+ % cat >> ~/.netrc
8
+ machine Seeker
9
+ login <username>
10
+ password <passwrod>
11
+ ^d
12
+ ```
13
+
14
+ ## Run
15
+ ```
16
+ % seeker-junos --level routing-options 193.88.239.31
17
+ I, [2014-03-22T13:15:09.320710 #66906] INFO -- : starting
18
+ I, [2014-03-22T13:25:09.544325 #66906] INFO -- : now at 'inhed', found 0 so far
19
+ I, [2014-03-22T13:29:00.236750 #66906] INFO -- : Found: 'kernel-options'
20
+ I, [2014-03-22T13:31:59.445597 #66906] INFO -- : Found: 'maximum-routes'
21
+ I, [2014-03-22T13:34:41.146006 #66906] INFO -- : Found: 'max-interface-supported'
22
+ I, [2014-03-22T13:35:10.340298 #66906] INFO -- : now at 'max-interface-supps', found 3 so far
23
+ I, [2014-03-22T13:39:07.812630 #66906] INFO -- : Found: 'nsr-phantom-holdtime'
24
+ I, [2014-03-22T13:43:15.168970 #66906] INFO -- : Found: 'rpd-server'
25
+ I, [2014-03-22T13:45:09.499291 #66906] INFO -- : now at 'task-accounc', found 5 so far
26
+ I, [2014-03-22T13:45:31.663623 #66906] INFO -- : Found: 'task-accounting'
27
+ I, [2014-03-22T13:47:18.411653 #66906] INFO -- : Found: 'task-scheduling'
28
+ I, [2014-03-22T13:49:00.204509 #66906] INFO -- : finishing, took 33.84805928741667 minutes
29
+ ["kernel-options", "maximum-routes", "max-interface-supported", "nsr-phantom-holdtime", "rpd-server", "task-accounting", "task-scheduling"]
30
+ ```
31
+ Reports progress every 10min, outputs list of found commands when finished
32
+
33
+ ## Todo
34
+ * Full recurse, not just single level. Not sure if sane, as it already takes very fscking long to run
@@ -0,0 +1,47 @@
1
+ begin
2
+ require 'rake/testtask'
3
+ require 'bundler'
4
+ Bundler.setup
5
+ rescue LoadError
6
+ warn 'bunler missing'
7
+ exit 42
8
+ end
9
+
10
+ gemspec = eval(File.read(Dir['*.gemspec'].first))
11
+ file = [gemspec.name, gemspec.version].join('-') + '.gem'
12
+
13
+ desc 'Validate gemspec'
14
+ task :gemspec do
15
+ gemspec.validate
16
+ end
17
+
18
+ desc 'Run minitest'
19
+ task :test do
20
+ Rake::TestTask.new do |t|
21
+ t.libs.push "lib"
22
+ t.test_files = FileList['spec/*_spec.rb']
23
+ t.verbose = true
24
+ end
25
+ end
26
+
27
+ desc 'Build gem'
28
+ task :build do
29
+ system "gem build #{gemspec.name}.gemspec"
30
+ FileUtils.mkdir_p 'gems'
31
+ FileUtils.mv file, 'gems'
32
+ end
33
+
34
+ desc 'Install gem'
35
+ task :install => :build do
36
+ system "sudo -E sh -c \'umask 022; gem install gems/#{file}\'"
37
+ end
38
+
39
+ desc 'Remove gems'
40
+ task :clean do
41
+ FileUtils.rm_rf 'gems'
42
+ end
43
+
44
+ desc 'Push to rubygems'
45
+ task :push do
46
+ system "gem push gems/#{file}"
47
+ end
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby20
2
+
3
+ $: << '/home/fisakytt/tmp/seeker/lib'
4
+
5
+ begin
6
+ require 'seeker/junos/cli'
7
+ p Seeker::JunosCLI.new.result
8
+ rescue => error
9
+ warn "#{error}"
10
+ raise if Seeker.debug > 0
11
+ end
@@ -0,0 +1,15 @@
1
+ require 'logger'
2
+
3
+ module Seeker
4
+ class SeekerError < StandardError; end
5
+ class << self
6
+ def debug
7
+ @debug
8
+ end
9
+ def debug= arg
10
+ @debug=arg
11
+ end
12
+ end
13
+ Log = Logger.new STDOUT
14
+ Log.level = Logger::INFO
15
+ end
@@ -0,0 +1,35 @@
1
+ require_relative '../seeker'
2
+ require 'slop'
3
+ require 'net/netrc'
4
+
5
+ module Seeker
6
+ class CLI
7
+ NETRC_MACHINE = 'Seeker'
8
+ attr_reader :result
9
+ class NoAuthFound < SeekerError; end
10
+ class MissingHost < SeekerError; end
11
+
12
+ private
13
+ def initialize
14
+ @opts = opts_parse
15
+ if not @opts.present? :debug
16
+ Seeker.debug = 0
17
+ elsif @opts[:debug]
18
+ Seeker.debug = @opts[:debug].to_i
19
+ else
20
+ Seeker.debug = 1
21
+ end
22
+ Log.level = Logger::DEBUG if Seeker.debug > 0
23
+ args = @opts.parse
24
+ @host = args.first
25
+ raise MissingHost, 'no host given as argument' unless @host
26
+ @user, @password = netrc_get
27
+ @result = seek
28
+ end
29
+
30
+ def netrc_get machine=NETRC_MACHINE
31
+ auth = Net::Netrc.locate machine
32
+ [auth.login, auth.password] rescue raise NoAuthFound, "could not find authentication for #{machine} in .netrc"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,109 @@
1
+ require_relative '../seeker'
2
+ require_relative 'ssh'
3
+
4
+ module Seeker
5
+ class Junos
6
+ KNOWN = %w( apply-flags apply-macro inherit )
7
+ CHARS = ('a'..'z').to_a + ('0'..'9').to_a + %w( - )
8
+ REPORT_INTERVAL = 10*60
9
+ INVALID_INTERFACES = [
10
+ /^error: invalid interface type/,
11
+ /^error: missing or invalid (?:device|fpc) number/,
12
+ ]
13
+
14
+ def seek
15
+ @ssh = ssh_connect
16
+ @ssh.cmd 'configure'
17
+ start = Time.now
18
+ @report = start+REPORT_INTERVAL
19
+ Log.info "starting"
20
+ seek_level @opts[:level]
21
+ Log.info "finishing, took #{(Time.now - start)/60} minutes"
22
+ @ssh.cmd 'rollback'
23
+ @ssh.cmd 'exit'
24
+ @ssh.close
25
+ @found
26
+ end
27
+
28
+ def seek_level level
29
+ @ssh.cmd 'edit ' + level if level
30
+ @known = known_get
31
+ find_hidden
32
+ @ssh.cmd 'top'
33
+ end
34
+
35
+ private
36
+
37
+ def find_hidden
38
+ CHARS.each do |c|
39
+ cmd = @cmd.join + c
40
+ if Time.now > @report
41
+ Log.info "now at '#{cmd}', found #{@found.size} so far"
42
+ @report += REPORT_INTERVAL
43
+ end
44
+ next if @known.include? cmd
45
+ o = @ssh.cmd 'set ' + cmd
46
+ if complete? o
47
+ Log.info "Found: '#{cmd}'"
48
+ @report += REPORT_INTERVAL
49
+ @found << cmd
50
+ elsif valid? o
51
+ @cmd << c
52
+ find_hidden
53
+ @cmd.pop
54
+ end
55
+ end
56
+ end
57
+
58
+ def valid? output
59
+ valid = true
60
+ output = output.split "\n"
61
+ output = output[1..-1]
62
+ if output[1].match(/^syntax error\./)
63
+ output = output.first.sub(/^(\s+).*/, '\1')
64
+ valid = false if output.size < @min_space
65
+ end
66
+ valid = false if INVALID_INTERFACES.any? {|re| output[0].match re}
67
+ valid
68
+ end
69
+
70
+ def complete? output
71
+ output = output.split "\n"
72
+ output = output[1..-1]
73
+ complete = true
74
+ complete = false if output[1].match(/^syntax error\./)
75
+ complete = false if output[1].match(/ is ambiguous\./)
76
+ complete = false if output[0].match(/^error: syntax error:/)
77
+ complete = false if INVALID_INTERFACES.any? {|re| output[0].match re}
78
+ complete
79
+ end
80
+
81
+ def known_get
82
+ o = @ssh.cmd 'set ?'
83
+ o = o.each_line.map do |line|
84
+ re = line.match(/^[\s>+] (\S+).*/)
85
+ re[1] if re
86
+ end
87
+ o.compact + KNOWN
88
+ end
89
+
90
+ def initialize host, user, password, opts
91
+ @host, @user, @password, @opts = host, user, password, opts
92
+ @ssh = nil
93
+ @known = nil
94
+ @min_space = nil
95
+ @report = nil
96
+ @cmd = []
97
+ @found = []
98
+ end
99
+
100
+ def ssh_connect
101
+ ssh = SSH.new @host, @user, @password
102
+ ssh.cmd 'set cli complete-on-space off'
103
+ ssh.cmd 'set cli screen-length 0'
104
+ @min_space = ssh.prompt_seen.size + 5
105
+ ssh
106
+ end
107
+
108
+ end
109
+ end
@@ -0,0 +1,17 @@
1
+ require_relative '../cli'
2
+ require_relative '../junos'
3
+ module Seeker
4
+ class JunosCLI < CLI
5
+ def opts_parse
6
+ opts = Slop.parse(:help=>true) do
7
+ banner 'Usage: junos-seeker [options] hostname'
8
+ on 'l=', 'level', 'Level to start from, e.g. chassis, system, routing-options'
9
+ on 'd', 'debug', 'Debug (optionally with level)', :optional_argument=>true
10
+ end
11
+ end
12
+
13
+ def seek
14
+ Junos.new(@host, @user, @password, @opts).seek
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,64 @@
1
+ require 'net/ssh'
2
+
3
+ module Seeker
4
+ class SSH
5
+ TIMEOUT = 5
6
+ PROMPT = /^[^\s>#]+[>#] /
7
+ SLEEP = 0.001
8
+ attr_reader :prompt_seen
9
+ class NoSshShell < SeekerError; end
10
+
11
+ def cmd command
12
+ Log.debug "SSH: #{command}"
13
+ @output = ''
14
+ @session.send_data command + "\n"
15
+ @session.process
16
+ expect @prompt
17
+ @output
18
+ end
19
+
20
+ def close command='exit'
21
+ @session.send_data command +"\n"
22
+ end
23
+
24
+ private
25
+
26
+ def initialize host, user, password, prompt=PROMPT
27
+ @output = ''
28
+ @prompt = prompt
29
+ @prompt_seen = nil
30
+ @session = nil
31
+ @ssh = Net::SSH.start host, user, :password=>password, :timeout=>TIMEOUT
32
+ shell_open
33
+ expect @prompt
34
+ end
35
+
36
+ def shell_open
37
+ @session = @ssh.open_channel do |channel|
38
+ channel.on_data do |channel, data|
39
+ $stderr.print data if Seeker.debug > 1
40
+ @output << data
41
+ end
42
+ channel.request_pty do |channel, success|
43
+ raise NoSshShell, "Can't get PTY" unless success
44
+ channel.send_channel_request 'shell' do |channel, success|
45
+ raise NoSshShell, "Can't get shell" unless success
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ def expect regexp
52
+ Timeout::timeout(TIMEOUT) do
53
+ @ssh.loop(SLEEP) do
54
+ sleep SLEEP
55
+ re = @output.match regexp
56
+ @prompt_seen = re[0] if re
57
+ not re
58
+ end
59
+ end
60
+ end
61
+
62
+
63
+ end
64
+ end
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'seeker-junos'
3
+ s.version = '0.0.5'
4
+ s.platform = Gem::Platform::RUBY
5
+ s.authors = [ 'Saku Ytti' ]
6
+ s.email = %w( saku@ytti.fi )
7
+ s.homepage = 'http://github.com/ytti/seeker-junos'
8
+ s.summary = 'find hidden commands in junos'
9
+ s.description = 'logs via ssh to junos devices and brute forces hidden passwords out'
10
+ s.rubyforge_project = s.name
11
+ s.files = `git ls-files`.split("\n")
12
+ s.executables = %w( seeker-junos )
13
+ s.require_path = 'lib'
14
+
15
+ s.add_dependency 'net-ssh'
16
+ s.add_dependency 'net-netrc'
17
+ s.add_dependency 'slop'
18
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: seeker-junos
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Saku Ytti
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-03-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: net-ssh
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: net-netrc
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: slop
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: logs via ssh to junos devices and brute forces hidden passwords out
63
+ email:
64
+ - saku@ytti.fi
65
+ executables:
66
+ - seeker-junos
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - .gitignore
71
+ - Gemfile
72
+ - README.md
73
+ - Rakefile
74
+ - bin/seeker-junos
75
+ - lib/seeker.rb
76
+ - lib/seeker/cli.rb
77
+ - lib/seeker/junos.rb
78
+ - lib/seeker/junos/cli.rb
79
+ - lib/seeker/ssh.rb
80
+ - seeker-junos.gemspec
81
+ homepage: http://github.com/ytti/seeker-junos
82
+ licenses: []
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ segments:
94
+ - 0
95
+ hash: 526249442777840062
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ segments:
103
+ - 0
104
+ hash: 526249442777840062
105
+ requirements: []
106
+ rubyforge_project: seeker-junos
107
+ rubygems_version: 1.8.25
108
+ signing_key:
109
+ specification_version: 3
110
+ summary: find hidden commands in junos
111
+ test_files: []