Add rspec coverage for Rex::Proto::NTP
parent
bc274b358f
commit
1830bdc7a5
|
@ -1,4 +1,8 @@
|
||||||
# -*- coding: binary -*-
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
require 'rubygems'
|
||||||
|
require 'bit-struct'
|
||||||
|
|
||||||
module Rex
|
module Rex
|
||||||
module Proto
|
module Proto
|
||||||
module NTP
|
module NTP
|
||||||
|
@ -25,7 +29,7 @@ module NTP
|
||||||
unsigned :stratum, 8, default: 0
|
unsigned :stratum, 8, default: 0
|
||||||
unsigned :poll, 8, default: 0
|
unsigned :poll, 8, default: 0
|
||||||
unsigned :precision, 8, default: 0
|
unsigned :precision, 8, default: 0
|
||||||
char :payload, 352
|
rest :payload
|
||||||
end
|
end
|
||||||
|
|
||||||
# An NTP control message. Control messages are only specified for NTP
|
# An NTP control message. Control messages are only specified for NTP
|
||||||
|
@ -62,11 +66,12 @@ module NTP
|
||||||
# 0 1 2 3
|
# 0 1 2 3
|
||||||
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
# |00 | VN | 7 |A| Sequence |
|
# |R M| VN | 7 |A| Sequence |
|
||||||
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
# | Implementation| request code |
|
# | Implementation| request code |
|
||||||
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
unsigned :reserved, 2, default: 0
|
unsigned :response, 1, default: 0
|
||||||
|
unsigned :more, 1, default: 0
|
||||||
unsigned :version, 3, default: 0
|
unsigned :version, 3, default: 0
|
||||||
unsigned :mode, 3, default: 7
|
unsigned :mode, 3, default: 7
|
||||||
unsigned :auth, 1, default: 0
|
unsigned :auth, 1, default: 0
|
||||||
|
|
|
@ -86,8 +86,8 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
check_and_set('MODE_7_REQUEST_CODES')
|
check_and_set('MODE_7_REQUEST_CODES')
|
||||||
|
|
||||||
connect_udp
|
connect_udp
|
||||||
fuzz_version_mode(ip)
|
|
||||||
fuzz_version_mode(ip, true)
|
fuzz_version_mode(ip, true)
|
||||||
|
fuzz_version_mode(ip, false)
|
||||||
fuzz_short(ip)
|
fuzz_short(ip)
|
||||||
fuzz_random(ip)
|
fuzz_random(ip)
|
||||||
fuzz_control(ip) if @modes.include?(6)
|
fuzz_control(ip) if @modes.include?(6)
|
||||||
|
@ -144,6 +144,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
def fuzz_random(host)
|
def fuzz_random(host)
|
||||||
print_status("#{host}:#{rport} fuzzing random messages")
|
print_status("#{host}:#{rport} fuzzing random messages")
|
||||||
0.upto(5) do
|
0.upto(5) do
|
||||||
|
# TODO: is there a better way to pick this size? Should more than one be tried?
|
||||||
request = SecureRandom.random_bytes(48)
|
request = SecureRandom.random_bytes(48)
|
||||||
what = "random #{request.size}-byte message"
|
what = "random #{request.size}-byte message"
|
||||||
vprint_status("#{host}:#{rport} probing with #{what}")
|
vprint_status("#{host}:#{rport} probing with #{what}")
|
||||||
|
@ -154,12 +155,17 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
|
|
||||||
# Sends a series of different version + mode combinations
|
# Sends a series of different version + mode combinations
|
||||||
def fuzz_version_mode(host, short=false)
|
def fuzz_version_mode(host, short)
|
||||||
print_status("#{host}:#{rport} fuzzing #{short ? 'short ' : nil}version and mode combinations")
|
print_status("#{host}:#{rport} fuzzing #{short ? 'short ' : nil}version and mode combinations")
|
||||||
@versions.each do |version|
|
@versions.each do |version|
|
||||||
@modes.each do |mode|
|
@modes.each do |mode|
|
||||||
request = Rex::Proto::NTP.ntp_generic(version, mode)
|
request = Rex::Proto::NTP::NTPGeneric.new
|
||||||
request = request[0, 4] if short
|
request.version = version
|
||||||
|
request.mode = mode
|
||||||
|
unless short
|
||||||
|
# TODO: is there a better way to pick this size? Should more than one be tried?
|
||||||
|
request.payload = SecureRandom.random_bytes(16)
|
||||||
|
end
|
||||||
what = "#{request.size}-byte #{short ? 'short ' : nil}version #{version} mode #{mode} message"
|
what = "#{request.size}-byte #{short ? 'short ' : nil}version #{version} mode #{mode} message"
|
||||||
vprint_status("#{host}:#{rport} probing with #{what}")
|
vprint_status("#{host}:#{rport} probing with #{what}")
|
||||||
responses = probe(host, datastore['RPORT'].to_i, request)
|
responses = probe(host, datastore['RPORT'].to_i, request)
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
#
|
||||||
|
require 'rex/proto/ntp/modes'
|
||||||
|
|
||||||
|
describe "Rex::Proto::NTP mode message handling" do
|
||||||
|
before do
|
||||||
|
@payload = 'R7' * 7
|
||||||
|
end
|
||||||
|
|
||||||
|
describe Rex::Proto::NTP::NTPControl do
|
||||||
|
before do
|
||||||
|
@control_raw = "\x1e\x05\x12\x34\x12\x34\x12\x34\x00\x00\x00\x0e" + @payload
|
||||||
|
@control = Rex::Proto::NTP::NTPControl.new
|
||||||
|
@control.version = 3
|
||||||
|
@control.response = 0
|
||||||
|
@control.more = 0
|
||||||
|
@control.operation = 5
|
||||||
|
@control.sequence = 0x1234
|
||||||
|
@control.association_id = 0x1234
|
||||||
|
@control.status = 0x1234
|
||||||
|
@control.payload_offset = 0
|
||||||
|
@control.payload_size = 14
|
||||||
|
@control.payload = @payload
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Generates control NTP messages correctly' do
|
||||||
|
@control_raw.should == @control.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Parses private NTP messages correctly' do
|
||||||
|
parsed_raw = Rex::Proto::NTP::NTPControl.new(@control_raw)
|
||||||
|
@control.should == parsed_raw
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe Rex::Proto::NTP::NTPGeneric do
|
||||||
|
before do
|
||||||
|
@generic_raw = "\xcc\x12\x34\x56" + @payload
|
||||||
|
@generic = Rex::Proto::NTP::NTPGeneric.new
|
||||||
|
@generic.li = 3
|
||||||
|
@generic.version = 1
|
||||||
|
@generic.mode = 4
|
||||||
|
@generic.stratum = 0x12
|
||||||
|
@generic.poll = 0x34
|
||||||
|
@generic.precision = 0x56
|
||||||
|
@generic.payload = @payload
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Generates generic NTP messages correctly' do
|
||||||
|
@generic_raw.should == @generic.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Parses private NTP messages correctly' do
|
||||||
|
parsed_raw = Rex::Proto::NTP::NTPGeneric.new(@generic_raw)
|
||||||
|
@generic.should == parsed_raw
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe Rex::Proto::NTP::NTPPrivate do
|
||||||
|
before do
|
||||||
|
@private_raw = "\x1f\x5a\x01\x99" + @payload
|
||||||
|
@private = Rex::Proto::NTP::NTPPrivate.new
|
||||||
|
@private.response = 0
|
||||||
|
@private.more = 0
|
||||||
|
@private.version = 3
|
||||||
|
@private.mode = 7
|
||||||
|
@private.auth = 0
|
||||||
|
@private.sequence = 90
|
||||||
|
@private.implementation = 1
|
||||||
|
@private.request_code = 153
|
||||||
|
@private.payload = @payload
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Generates private NTP messages correctly' do
|
||||||
|
@private_raw.should == @private.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Parses private NTP messages correctly' do
|
||||||
|
parsed_raw = Rex::Proto::NTP::NTPPrivate.new(@private_raw)
|
||||||
|
@private.should == parsed_raw
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue