add OptTimedelta datastore option and remove Kerberos-specific clock skew parsing
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/exploit/remote/kerberos/clock_skew'
|
||||
require 'msf/core/opt_timedelta'
|
||||
|
||||
module Msf
|
||||
class Exploit
|
||||
@@ -45,8 +45,7 @@ module Msf
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptString.new('KrbClockSkew', [true, 'Adjust Kerberos client clock by this offset (e.g. 90s, -5m, 1h)', '0s'],
|
||||
regex: Msf::Exploit::Remote::Kerberos::ClockSkew::CLOCK_SKEW_REGEX)
|
||||
OptTimedelta.new('KrbClockSkew', [true, 'Adjust Kerberos client clock by this offset (e.g. 90s, -5m, 1h)', '0s'])
|
||||
], self.class
|
||||
)
|
||||
end
|
||||
@@ -90,7 +89,7 @@ module Msf
|
||||
#
|
||||
# @param value [String, Numeric, nil]
|
||||
def kerberos_clock_skew=(value)
|
||||
@kerberos_clock_skew = Msf::Exploit::Remote::Kerberos::ClockSkew.parse(value)
|
||||
@kerberos_clock_skew = Msf::OptTimedelta.parse(value)
|
||||
end
|
||||
|
||||
# Returns the current time adjusted for Kerberos clock skew in UTC.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#
|
||||
# This class stores Metasploit option configuration used across service authentication
|
||||
#
|
||||
require 'msf/core/exploit/remote/kerberos/clock_skew'
|
||||
require 'msf/core/opt_timedelta'
|
||||
|
||||
module Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::Options
|
||||
# Create the list of options that a module must provide for Kerberos authentication via the given protocol
|
||||
@@ -38,10 +38,9 @@ module Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::Options
|
||||
fallbacks: ['Rhostname'],
|
||||
conditions: option_conditions
|
||||
),
|
||||
Msf::OptString.new(
|
||||
Msf::OptTimedelta.new(
|
||||
'KrbClockSkew',
|
||||
[true, 'Adjust Kerberos client clock by this offset (e.g. 90s, -5m, 1h)', '0s'],
|
||||
regex: Msf::Exploit::Remote::Kerberos::ClockSkew::CLOCK_SKEW_REGEX,
|
||||
conditions: option_conditions
|
||||
),
|
||||
Msf::OptAddress.new(
|
||||
@@ -66,6 +65,6 @@ module Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::Options
|
||||
#
|
||||
# @return [Float]
|
||||
def kerberos_clock_skew_seconds
|
||||
Msf::Exploit::Remote::Kerberos::ClockSkew.parse(datastore['KrbClockSkew'])
|
||||
Msf::OptTimedelta.parse(datastore['KrbClockSkew'])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
class OptTimedelta < OptBase
|
||||
TIMEDELTA_REGEX = /\A([+-]?\d+(?:\.\d+)?(?:[smhd])?)+\z/i.freeze
|
||||
|
||||
UNIT_IN_SECONDS = {
|
||||
's' => 1,
|
||||
'm' => 60,
|
||||
'h' => 3_600,
|
||||
'd' => 86_400
|
||||
}.freeze
|
||||
|
||||
attr_reader :allow_negative
|
||||
|
||||
def initialize(in_name, attrs = [], allow_negative: true, **kwargs)
|
||||
super(in_name, attrs, **kwargs)
|
||||
@allow_negative = allow_negative
|
||||
end
|
||||
|
||||
def type
|
||||
'timedelta'
|
||||
end
|
||||
|
||||
def normalize(value)
|
||||
self.class.parse(value)
|
||||
end
|
||||
|
||||
def valid?(value, check_empty: true, datastore: nil)
|
||||
return false if check_empty && empty_required_value?(value)
|
||||
|
||||
begin
|
||||
parsed_value = self.class.parse(value)
|
||||
rescue Msf::OptionValidateError
|
||||
return false
|
||||
end
|
||||
|
||||
return false if !allow_negative && parsed_value.negative?
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def self.parse(value)
|
||||
return 0 if value.nil?
|
||||
return value.to_f if value.is_a?(Numeric)
|
||||
|
||||
trimmed_value = value.to_s.strip
|
||||
return 0 if trimmed_value.empty?
|
||||
return trimmed_value.to_f if trimmed_value.match?(/\A[+-]?\d+(?:\.\d+)?\z/)
|
||||
raise Msf::OptionValidateError.new([], message: 'Invalid timedelta format') unless trimmed_value.match?(TIMEDELTA_REGEX)
|
||||
|
||||
|
||||
total = 0
|
||||
trimmed_value.scan(/([+-]?\d+(?:\.\d+)?)([smhd]?)/i) do |amount, unit|
|
||||
unit = 's' if unit.blank?
|
||||
multiplier = UNIT_IN_SECONDS[unit.downcase]
|
||||
total += amount.to_f * multiplier
|
||||
end
|
||||
total
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,7 +3,7 @@ require 'rex/proto/mssql/client_mixin'
|
||||
require 'rex/text'
|
||||
require 'msf/core/exploit'
|
||||
require 'msf/core/exploit/remote'
|
||||
require 'msf/core/exploit/remote/kerberos/clock_skew'
|
||||
require 'msf/core/opt_timedelta'
|
||||
|
||||
module Rex
|
||||
module Proto
|
||||
@@ -389,7 +389,7 @@ module Rex
|
||||
framework: framework,
|
||||
framework_module: framework_module,
|
||||
ticket_storage: Msf::Exploit::Remote::Kerberos::Ticket::Storage::WriteOnly.new(framework: framework, framework_module: framework_module),
|
||||
clock_skew: Msf::Exploit::Remote::Kerberos::ClockSkew.parse(framework_module.datastore['KrbClockSkew'])
|
||||
clock_skew: Msf::OptTimedelta.parse(framework_module.datastore['KrbClockSkew'])
|
||||
)
|
||||
|
||||
kerberos_result = kerberos_authenticator.authenticate
|
||||
|
||||
@@ -11,6 +11,13 @@ RSpec.describe Msf::Exploit::Remote::Kerberos::Client do
|
||||
mod
|
||||
end
|
||||
|
||||
|
||||
describe 'KrbClockSkew option' do
|
||||
it 'is registered as an OptTimedelta datastore option' do
|
||||
expect(subject.options['KrbClockSkew']).to be_a(Msf::OptTimedelta)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#kerberos_clock_skew' do
|
||||
it 'defaults to zero' do
|
||||
expect(subject.kerberos_clock_skew).to eq(0)
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# -*- coding:binary -*-
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Msf::OptTimedelta do
|
||||
valid_values = [
|
||||
{ value: '120', normalized: 120.0 },
|
||||
{ value: '-5m', normalized: -300.0 },
|
||||
{ value: '1h30m', normalized: 5_400.0 },
|
||||
{ value: '2d', normalized: 172_800.0 },
|
||||
{ value: '+1.5h', normalized: 5_400.0 }
|
||||
]
|
||||
|
||||
invalid_values = [
|
||||
{ value: 'yolo' },
|
||||
{ value: '1w' },
|
||||
{ value: '5mfoo' }
|
||||
]
|
||||
|
||||
it_behaves_like 'an option', valid_values, invalid_values, 'timedelta'
|
||||
|
||||
describe '#valid?' do
|
||||
it 'can enforce positive-only values' do
|
||||
subject = described_class.new('Duration', [true, 'Duration'], allow_negative: false)
|
||||
|
||||
expect(subject.valid?('5m')).to be(true)
|
||||
expect(subject.valid?('-5m')).to be(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user