69 lines
1.9 KiB
Ruby
69 lines
1.9 KiB
Ruby
# -*- coding: binary -*-
|
|
|
|
module Rex
|
|
module Exploit
|
|
class ViewState
|
|
class Error < Rex::RuntimeError
|
|
end
|
|
|
|
def self.decode_viewstate(encoded_viewstate, algo: 'sha1')
|
|
viewstate = Rex::Text.decode_base64(encoded_viewstate)
|
|
|
|
unless Rex::Text.encode_base64(viewstate) == encoded_viewstate
|
|
raise Error.new('Could not decode ViewState')
|
|
end
|
|
|
|
hmac_len = OpenSSL::Digest.new(algo).digest_length
|
|
|
|
if (data = viewstate[0...-hmac_len]).empty?
|
|
data = nil
|
|
end
|
|
|
|
hmac = viewstate[-hmac_len..-1]
|
|
unless hmac&.length == hmac_len
|
|
raise Error.new('Could not decode ViewState')
|
|
end
|
|
|
|
{ data: data, hmac: hmac }
|
|
end
|
|
|
|
def self.generate_viewstate(data, extra: '', algo: 'sha1', key: '')
|
|
# Generate ViewState HMAC from known values and validation key
|
|
hmac = generate_viewstate_hmac(data + extra, algo: algo, key: key)
|
|
|
|
# Append HMAC to provided data and Base64-encode the whole shebang
|
|
Rex::Text.encode_base64(data + hmac)
|
|
end
|
|
|
|
def self.generate_viewstate_hmac(data, algo: 'sha1', key: '')
|
|
OpenSSL::HMAC.digest(algo, key, data)
|
|
end
|
|
|
|
def self.is_viewstate_valid?(encoded_viewstate, extra: '', algo: 'sha1', key: '')
|
|
viewstate = decode_viewstate(encoded_viewstate)
|
|
|
|
unless viewstate[:data]
|
|
raise Error.new('Could not retrieve ViewState data')
|
|
end
|
|
|
|
unless (their_hmac = viewstate[:hmac])
|
|
raise Error.new('Could not retrieve ViewState HMAC')
|
|
end
|
|
|
|
our_hmac = generate_viewstate_hmac(
|
|
viewstate[:data] + extra,
|
|
algo: algo,
|
|
key: key
|
|
)
|
|
|
|
# Do we have what it takes?
|
|
our_hmac == their_hmac
|
|
end
|
|
|
|
class << self
|
|
alias_method :can_sign_viewstate?, :is_viewstate_valid?
|
|
end
|
|
end
|
|
end
|
|
end
|