mirror of
https://github.com/nmap/nmap.git
synced 2026-08-04 06:40:48 +00:00
Adding the optimized snmp-brute script, unpwdb library , snmpcommunities wordlist
This commit is contained in:
parent
09562381ec
commit
d509ad055a
3 changed files with 329 additions and 84 deletions
91
nselib/data/snmpcommunities.lst
Normal file
91
nselib/data/snmpcommunities.lst
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#!comment: ***********************IMPORTANT NMAP LICENSE TERMS************************
|
||||
#!comment: * *
|
||||
#!comment: * The Nmap Security Scanner is (C) 1996-2010 Insecure.Com LLC. Nmap is *
|
||||
#!comment: * also a registered trademark of Insecure.Com LLC. This program is free *
|
||||
#!comment: * software; you may redistribute and/or modify it under the terms of the *
|
||||
#!comment: * GNU General Public License as published by the Free Software *
|
||||
#!comment: * Foundation; Version 2 with the clarifications and exceptions described *
|
||||
#!comment: * below. This guarantees your right to use, modify, and redistribute *
|
||||
#!comment: * this software under certain conditions. If you wish to embed Nmap *
|
||||
#!comment: * technology into proprietary software, we sell alternative licenses *
|
||||
#!comment: * (contact sales@insecure.com). Dozens of software vendors already *
|
||||
#!comment: * license Nmap technology such as host discovery, port scanning, OS *
|
||||
#!comment: * detection, and version detection. *
|
||||
#!comment: * *
|
||||
#!comment: * Note that the GPL places important restrictions on "derived works", yet *
|
||||
#!comment: * it does not provide a detailed definition of that term. To avoid *
|
||||
#!comment: * misunderstandings, we consider an application to constitute a *
|
||||
#!comment: * "derivative work" for the purpose of this license if it does any of the *
|
||||
#!comment: * following: *
|
||||
#!comment: * o Integrates source code from Nmap *
|
||||
#!comment: * o Reads or includes Nmap copyrighted data files, such as *
|
||||
#!comment: * nmap-os-db or nmap-service-probes. *
|
||||
#!comment: * o Executes Nmap and parses the results (as opposed to typical shell or *
|
||||
#!comment: * execution-menu apps, which simply display raw Nmap output and so are *
|
||||
#!comment: * not derivative works.) *
|
||||
#!comment: * o Integrates/includes/aggregates Nmap into a proprietary executable *
|
||||
#!comment: * installer, such as those produced by InstallShield. *
|
||||
#!comment: * o Links to a library or executes a program that does any of the above *
|
||||
#!comment: * *
|
||||
#!comment: * The term "Nmap" should be taken to also include any portions or derived *
|
||||
#!comment: * works of Nmap. This list is not exclusive, but is meant to clarify our *
|
||||
#!comment: * interpretation of derived works with some common examples. Our *
|
||||
#!comment: * interpretation applies only to Nmap--we don't speak for other people's *
|
||||
#!comment: * GPL works. *
|
||||
#!comment: * *
|
||||
#!comment: * If you have any questions about the GPL licensing restrictions on using *
|
||||
#!comment: * Nmap in non-GPL works, we would be happy to help. As mentioned above, *
|
||||
#!comment: * we also offer alternative license to integrate Nmap into proprietary *
|
||||
#!comment: * applications and appliances. These contracts have been sold to dozens *
|
||||
#!comment: * of software vendors, and generally include a perpetual license as well *
|
||||
#!comment: * as providing for priority support and updates as well as helping to *
|
||||
#!comment: * fund the continued development of Nmap technology. Please email *
|
||||
#!comment: * sales@insecure.com for further information. *
|
||||
#!comment: * *
|
||||
#!comment: * As a special exception to the GPL terms, Insecure.Com LLC grants *
|
||||
#!comment: * permission to link the code of this program with any version of the *
|
||||
#!comment: * OpenSSL library which is distributed under a license identical to that *
|
||||
#!comment: * listed in the included docs/licenses/OpenSSL.txt file, and distribute *
|
||||
#!comment: * linked combinations including the two. You must obey the GNU GPL in all *
|
||||
#!comment: * respects for all of the code used other than OpenSSL. If you modify *
|
||||
#!comment: * this file, you may extend this exception to your version of the file, *
|
||||
#!comment: * but you are not obligated to do so. *
|
||||
#!comment: * *
|
||||
#!comment: * If you received these files with a written license agreement or *
|
||||
#!comment: * contract stating terms other than the terms above, then that *
|
||||
#!comment: * alternative license agreement takes precedence over these comments. *
|
||||
#!comment: * *
|
||||
#!comment: * Source is provided to this software because we believe users have a *
|
||||
#!comment: * right to know exactly what a program is going to do before they run it. *
|
||||
#!comment: * This also allows you to audit the software for security holes (none *
|
||||
#!comment: * have been found so far). *
|
||||
#!comment: * *
|
||||
#!comment: * Source code also allows you to port Nmap to new platforms, fix bugs, *
|
||||
#!comment: * and add new features. You are highly encouraged to send your changes *
|
||||
#!comment: * to nmap-dev@insecure.org for possible incorporation into the main *
|
||||
#!comment: * distribution. By sending these changes to Fyodor or one of the *
|
||||
#!comment: * Insecure.Org development mailing lists, it is assumed that you are *
|
||||
#!comment: * offering the Nmap Project (Insecure.Com LLC) the unlimited, *
|
||||
#!comment: * non-exclusive right to reuse, modify, and relicense the code. Nmap *
|
||||
#!comment: * will always be available Open Source, but this is important because the *
|
||||
#!comment: * inability to relicense code has caused devastating problems for other *
|
||||
#!comment: * Free Software projects (such as KDE and NASM). We also occasionally *
|
||||
#!comment: * relicense the code to third parties as discussed above. If you wish to *
|
||||
#!comment: * specify special license conditions of your contributions, just say so *
|
||||
#!comment: * when you send them. *
|
||||
#!comment: * *
|
||||
#!comment: * This program is distributed in the hope that it will be useful, but *
|
||||
#!comment: * WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#!comment: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
#!comment: * General Public License v2.0 for more details at *
|
||||
#!comment: * http://www.gnu.org/licenses/gpl-2.0.html , or in the COPYING file *
|
||||
#!comment: * included with Nmap. *
|
||||
#!comment: * *
|
||||
#!comment: ***************************************************************************/
|
||||
|
||||
public
|
||||
private
|
||||
snmpd
|
||||
mngt
|
||||
cisco
|
||||
admin
|
||||
|
|
@ -212,7 +212,7 @@ end
|
|||
-- @param count_limit Count limit in seconds. Use 0 or <code>nil</code> for no limit.
|
||||
-- @return boolean Status.
|
||||
-- @return function The wrapped iterator.
|
||||
local limited_iterator = function(iterator, time_limit, count_limit)
|
||||
limited_iterator = function(iterator, time_limit, count_limit)
|
||||
local start, count, elem
|
||||
|
||||
time_limit = (time_limit and time_limit > 0) and time_limit
|
||||
|
|
|
|||
|
|
@ -1,9 +1,29 @@
|
|||
description = [[
|
||||
Attempts to find an SNMP community string by brute force guessing.
|
||||
|
||||
This script opens a sending socket and a sniffing pcap socket in parallel
|
||||
threads. The sending socket sends the SNMP probes with the community strings,
|
||||
while the pcap socket sniffs the network for an answer to the probes. If
|
||||
valid community strings are found, they are added to the creds database and
|
||||
reported in the output.
|
||||
|
||||
The default wordlists used to bruteforce the SNMP community strings are
|
||||
<code>nselib/data/snmpcommunities.lst</code> and
|
||||
<code>nselib/data/passwords.lst</code>. If the <code>passdb</code> or
|
||||
<code>snmplist</code> argument is specified, that one is used as the wordlist.
|
||||
The <code>passdb</code> argument has precedence over <code>snmplist</code>.
|
||||
|
||||
No output is reported if no valid account is found.
|
||||
]]
|
||||
-- 2008-07-03
|
||||
-- 2008-07-03 Philip Pickering, basic verstion
|
||||
-- 2011-07-17 Gorjan Petrovski, Patrik Karlsson, optimization and creds
|
||||
-- accounts, rejected use of the brute library because of
|
||||
-- implementation using unconnected sockets.
|
||||
|
||||
---
|
||||
-- @usage
|
||||
-- nmap -sU --script snmp-brute <target> [--script-args [ passdb=<wordlist> | snmplist=<wordlist> ]]
|
||||
--
|
||||
-- @args snmpcommunity The SNMP community string to use. If it's supplied, this
|
||||
-- script will not run.
|
||||
-- @args snmplist The filename of a list of community strings to try.
|
||||
|
|
@ -11,9 +31,11 @@ Attempts to find an SNMP community string by brute force guessing.
|
|||
-- @output
|
||||
-- PORT STATE SERVICE
|
||||
-- 161/udp open snmp
|
||||
-- |_snmp-brute: public
|
||||
-- | snmp-brute:
|
||||
-- | dragon - Account is valid
|
||||
-- |_ jordan - Account is valid
|
||||
|
||||
author = "Philip Pickering"
|
||||
author = "Philip Pickering, Gorjan Petrovski, Patrik Karlsson"
|
||||
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
|
||||
|
|
@ -22,91 +44,223 @@ categories = {"intrusive", "auth"}
|
|||
require "shortport"
|
||||
require "snmp"
|
||||
require "creds"
|
||||
require "unpwdb"
|
||||
require "nmap"
|
||||
require "packet"
|
||||
|
||||
portrule = shortport.portnumber(161, "udp", {"open", "open|filtered"})
|
||||
|
||||
action = function(host, port)
|
||||
local filltable = function(filename, table)
|
||||
local file = io.open(filename, "r")
|
||||
|
||||
if nmap.registry.snmpcommunity or nmap.registry.args.snmpcommunity then return end
|
||||
|
||||
-- create the socket used for our connection
|
||||
local socket = nmap.new_socket()
|
||||
|
||||
-- set a reasonable timeout value
|
||||
socket:set_timeout(5000)
|
||||
|
||||
-- do some exception handling / cleanup
|
||||
local catch = function()
|
||||
socket:close()
|
||||
end
|
||||
|
||||
local try = nmap.new_try(catch)
|
||||
|
||||
-- connect to the potential SNMP system
|
||||
try(socket:connect(host, port))
|
||||
|
||||
|
||||
local request = snmp.buildGetRequest({}, "1.3.6.1.2.1.1.3.0")
|
||||
|
||||
local commFile = nmap.registry.args.snmplist and nmap.fetchfile(nmap.registry.args.snmplist)
|
||||
local commTable
|
||||
|
||||
-- fetch wordlist from file (from unpwdb-lib)
|
||||
if commFile then
|
||||
local file = io.open(commFile)
|
||||
|
||||
if file then
|
||||
commTable = {}
|
||||
while true do
|
||||
local l = file:read()
|
||||
|
||||
if not l then
|
||||
break
|
||||
end
|
||||
|
||||
-- Comments takes up a whole line
|
||||
if not l:match("#!comment:") then
|
||||
table.insert(commTable, l)
|
||||
end
|
||||
if not file then
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
for l in file:lines() do
|
||||
-- Comments takes up a whole line
|
||||
if not l:match("#!comment:") then
|
||||
table[#table + 1] = l
|
||||
end
|
||||
end
|
||||
|
||||
file:close()
|
||||
end
|
||||
end
|
||||
|
||||
-- default wordlist
|
||||
if (not commTable) then commTable = {'public', 'private', 'snmpd', 'snmp', 'mngt', 'cisco', 'admin'} end
|
||||
|
||||
-- send all possible words out before waiting for an answer
|
||||
for _, commStr in ipairs(commTable) do
|
||||
local payload = snmp.encode(snmp.buildPacket(request, 0, commStr))
|
||||
try(socket:send(payload))
|
||||
end
|
||||
|
||||
-- finally wait for a response
|
||||
local status
|
||||
local response
|
||||
|
||||
status, response = socket:receive_bytes(1)
|
||||
|
||||
if (not status) then
|
||||
return
|
||||
end
|
||||
|
||||
if (response == "TIMEOUT") then
|
||||
return
|
||||
end
|
||||
nmap.set_port_state(host, port, "open")
|
||||
|
||||
local result
|
||||
_, result = snmp.decode(response)
|
||||
|
||||
-- response contains valid community string
|
||||
if type(result) == "table" then
|
||||
nmap.registry.snmpcommunity = result[2]
|
||||
return result[2]
|
||||
end
|
||||
|
||||
return
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local communities_iterator = function()
|
||||
local function next_community()
|
||||
local snmplist = stdnse.get_script_args("snmplist")
|
||||
local passdb = stdnse.get_script_args("passdb")
|
||||
if passdb then
|
||||
local communities = {}
|
||||
local filename = nmap.fetchfile(passdb)
|
||||
|
||||
if not filltable(filename, communities) then
|
||||
stdnse.print_debug("Cannot open snmplist file")
|
||||
return
|
||||
end
|
||||
|
||||
for _, c in ipairs(communities) do
|
||||
coroutine.yield(c)
|
||||
end
|
||||
elseif snmplist then
|
||||
local communities = {}
|
||||
local filename = nmap.fetchfile(snmplist)
|
||||
|
||||
if not filltable(filename, communities) then
|
||||
stdnse.print_debug("Cannot open snmplist file")
|
||||
return
|
||||
end
|
||||
|
||||
for _, c in ipairs(communities) do
|
||||
coroutine.yield(c)
|
||||
end
|
||||
else
|
||||
local communities = {}
|
||||
local filename = nmap.fetchfile("nselib/data/snmpcommunities.lst")
|
||||
if not filltable(filename, communities) then
|
||||
stdnse.print_debug("Cannot open snmp communities file.")
|
||||
return
|
||||
end
|
||||
|
||||
for _, c in ipairs(communities) do
|
||||
coroutine.yield(c)
|
||||
end
|
||||
|
||||
local try = nmap.new_try()
|
||||
passwords = try(unpwdb.passwords())
|
||||
for p in passwords do
|
||||
coroutine.yield(p)
|
||||
end
|
||||
end
|
||||
|
||||
while(true) do coroutine.yield(nil, nil) end
|
||||
end
|
||||
return coroutine.wrap(next_community)
|
||||
end
|
||||
|
||||
local communities = function()
|
||||
local time_limit = unpwdb.timelimit()
|
||||
local count_limit = 0
|
||||
if stdnse.get_script_args("unpwdb.passlimit") then
|
||||
count_limit = tonumber(stdnse.get_script_args("unpwdb.passlimit"))
|
||||
end
|
||||
return unpwdb.limited_iterator(communities_iterator, time_limit, count_limit)
|
||||
end
|
||||
|
||||
local send_snmp_queries = function(host, port, result)
|
||||
local condvar = nmap.condvar(result)
|
||||
|
||||
local socket = nmap.new_socket("udp")
|
||||
--socket:set_timeout(host.times.timeout*1000)
|
||||
|
||||
local request = snmp.buildGetRequest({}, "1.3.6.1.2.1.1.3.0")
|
||||
|
||||
local payload, status, response
|
||||
local comm_iter = communities()
|
||||
for community_string in comm_iter() do
|
||||
|
||||
if result.status == false then
|
||||
--in case the sniff_snmp_responses thread was shut down
|
||||
condvar("signal")
|
||||
return
|
||||
end
|
||||
payload = snmp.encode(snmp.buildPacket(request, 0, community_string))
|
||||
status, err = socket:sendto(host, port, payload)
|
||||
if not status then
|
||||
result.status = false
|
||||
result.msg = "Could not send SNMP probe"
|
||||
condvar "signal"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
socket:close()
|
||||
result.sent = true
|
||||
condvar("signal")
|
||||
end
|
||||
|
||||
local sniff_snmp_responses = function(host, port, result)
|
||||
local condvar = nmap.condvar(result)
|
||||
|
||||
local pcap = nmap.new_socket()
|
||||
pcap:set_timeout(host.times.timeout * 1000 * 3)
|
||||
local ip = host.bin_ip_src
|
||||
ip = string.format("%d.%d.%d.%d",ip:byte(1),ip:byte(2),ip:byte(3),ip:byte(4))
|
||||
pcap:pcap_open(host.interface, 104, false,"dst host " .. ip .. " and udp and port 161")
|
||||
|
||||
-- last_run indicated whether there will be only one more receive
|
||||
local last_run = false
|
||||
|
||||
-- receive even when status=false untill all the probes are sent
|
||||
while true do
|
||||
local status, plen, l2, l3, _ = pcap:pcap_receive()
|
||||
|
||||
if status then
|
||||
local p = packet.Packet:new(l3,#l3)
|
||||
if not p:udp_parse() then
|
||||
--shouldn't happen
|
||||
result.status = false
|
||||
result.msg = "Wrong type of packet received"
|
||||
condvar "signal"
|
||||
return
|
||||
end
|
||||
|
||||
local response = p:raw(28, #p.buf)
|
||||
local res
|
||||
_, res = snmp.decode(response)
|
||||
|
||||
if type(res) == "table" then
|
||||
result.communities[ #(result.communities) + 1 ] = res[2]
|
||||
else
|
||||
result.status = false
|
||||
result.msg = "Wrong type of SNMP response received"
|
||||
condvar "signal"
|
||||
return
|
||||
end
|
||||
else
|
||||
if last_run then
|
||||
condvar "signal"
|
||||
return
|
||||
else
|
||||
if result.sent then
|
||||
last_run = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
pcap:close()
|
||||
condvar "signal"
|
||||
return
|
||||
end
|
||||
|
||||
action = function(host, port)
|
||||
if nmap.registry.snmpcommunity or nmap.registry.args.snmpcommunity then return end
|
||||
|
||||
local result = {}
|
||||
local threads = {}
|
||||
|
||||
local condvar = nmap.condvar(result)
|
||||
|
||||
result.sent = false --whether the probes are sent
|
||||
result.communities = {} -- list of valid community strings
|
||||
result.msg = "" -- Error/Status msg
|
||||
result.status = true -- Status (is everything ok)
|
||||
|
||||
|
||||
local recv_co = stdnse.new_thread(sniff_snmp_responses, host, port, result)
|
||||
local send_co = stdnse.new_thread(send_snmp_queries, host, port, result)
|
||||
|
||||
local recv_dead, send_dead
|
||||
while true do
|
||||
condvar "wait"
|
||||
recv_dead = (coroutine.status(recv_co) == "dead")
|
||||
send_dead = (coroutine.status(send_co) == "dead")
|
||||
if recv_dead then break end
|
||||
end
|
||||
|
||||
if result.status then
|
||||
-- add the community strings to the creds database
|
||||
local c = creds.Credentials:new(SCRIPT_NAME, host, port)
|
||||
for _, community_string in ipairs(result.communities) do
|
||||
c:add("",community_string, creds.State.VALID)
|
||||
end
|
||||
|
||||
-- insert the first community string as a snmpcommunity registry field
|
||||
local creds_iter = c:getCredentials()
|
||||
if creds_iter then
|
||||
local account = creds_iter()
|
||||
if account then
|
||||
nmap.registry.snmpcommunity = account.pass
|
||||
end
|
||||
end
|
||||
|
||||
-- return output
|
||||
return tostring(c)
|
||||
else
|
||||
stdnse.print_debug("An error occured: "..result.msg)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue