mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
Rename scripts (almost all of them) to make their names more consistent and
make them look better in output. The full list of changes is anonFTP => ftp-anon ASN => asn-query brutePOP3 => pop3-brute bruteTelnet => telnet-brute daytimeTest => daytime dns-safe-recursion-port => dns-random-srcport dns-safe-recursion-txid => dns-random-txid dns-test-open-recursion => dns-recursion ftpbounce => ftp-bounce HTTPAuth => http-auth HTTP_open_proxy => http-open-proxy HTTPpasswd => http-passwd HTTPtrace => http-trace iax2Detect => iax2-version ircServerInfo => irc-info ircZombieTest => irc-zombie MSSQLm => ms-sql-info MySQLinfo => mysql-info popcapa => pop3-capabilities PPTPversion => pptp-version promiscuous => sniffer-detect RealVNC_auth_bypass => realvnc-auth-bypass robots => robots.txt showHTMLTitle => html-title showOwner => identd-owners skype_v2-version => skypev2-version smb-enumdomains => smb-enum-domains smb-enumsessions => smb-enum-sessions smb-enumshares => smb-enum-shares smb-enumusers => smb-enum-users smb-serverstats => smb-server-stats smb-systeminfo => smb-system-info SMTPcommands => smtp-commands SMTP_openrelay_test => smtp-open-relay SNMPcommunitybrute => snmp-brute SNMPsysdescr => snmp-sysdescr SQLInject => sql-injection SSH-hostkey => ssh-hostkey SSHv1-support => sshv1 SSLv2-support => sslv2 strangeSMTPport => smtp-strangeport UPnP-info => upnp-info xamppDefaultPass => xampp-default-auth zoneTrans => zone-transfer
This commit is contained in:
325
scripts/smb-enum-sessions.nse
Normal file
325
scripts/smb-enum-sessions.nse
Normal file
@@ -0,0 +1,325 @@
|
||||
description = [[
|
||||
Enumerates the users logged into a system either locally, through a remote desktop client (terminal
|
||||
services), or through a SMB share.
|
||||
|
||||
Enumerating the local and terminal services users is done by reading the remote registry. Keys under
|
||||
<code>HKEY_USERS</code> are SIDs that represent the currently logged in users, and those SIDs can be converted
|
||||
to proper names by using the <code>LsaLookupSids()</code> function. Doing this requires any access higher than
|
||||
anonymous. Guests, users, or administrators are all able to perform this request on the operating
|
||||
systems I (Ron Bowes) tested.
|
||||
|
||||
Enumerating SMB connections is done using the <code>srvsvc.netsessenum()</code> function, which returns who's
|
||||
logged in, when they logged in, and how long they've been idle for. Unfortunately, I couldn't find
|
||||
a way to get the user's domain with this function, so the domain isn't printed. The level of access
|
||||
required for this varies between Windows versions, but in Windows 2000 anybody (including the
|
||||
anonymous account) can access this, and in Windows 2003 a user or administrator account is
|
||||
required.
|
||||
|
||||
Since both of these are related to users being logged into the server, it seemed logical to combine
|
||||
them into a single script.
|
||||
|
||||
I learned the idea and technique for this from sysinternals' tool, PsLoggedOn.exe. I use similar
|
||||
function calls to what they use, so thanks go out to them. Thanks also to Matt, for giving me the
|
||||
idea to write this one.
|
||||
]]
|
||||
|
||||
---
|
||||
--@usage
|
||||
-- nmap --script smb-enumsessions.nse -p445 <host>
|
||||
-- sudo nmap -sU -sS --script smb-enumsessions.nse -p U:137,T:139 <host>
|
||||
--
|
||||
--@output
|
||||
-- Host script results:
|
||||
-- | smb-enum-sessions:
|
||||
-- | Users logged in:
|
||||
-- | |_ TESTBOX\Administrator since 2008-10-21 08:17:14
|
||||
-- | |_ DOMAIN\rbowes since 2008-10-20 09:03:23
|
||||
-- | Active SMB Sessions:
|
||||
-- |_ |_ ADMINISTRATOR is connected from 10.100.254.138 for [just logged in, it's probably you], idle for [not idle]
|
||||
--
|
||||
-- @args smb* This script supports the <code>smbusername</code>,
|
||||
-- <code>smbpassword</code>, <code>smbhash</code>, <code>smbguest</code>, and
|
||||
-- <code>smbtype</code> script arguments of the <code>smb</code> module.
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
author = "Ron Bowes"
|
||||
copyright = "Ron Bowes"
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
categories = {"discovery","intrusive"}
|
||||
|
||||
require 'msrpc'
|
||||
require 'smb'
|
||||
require 'stdnse'
|
||||
|
||||
hostrule = function(host)
|
||||
|
||||
local port = smb.get_port(host)
|
||||
|
||||
if(port == nil) then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
---Attempts to enumerate the sessions on a remote system using MSRPC calls. This will likely fail
|
||||
-- against a modern system, but will succeed against Windows 2000.
|
||||
--
|
||||
--@param host The host object.
|
||||
--@return Status (true or false).
|
||||
--@return List of sessions (if status is true) or an an error string (if status is false).
|
||||
local function srvsvc_enum_sessions(host)
|
||||
local i
|
||||
local status, smbstate
|
||||
local bind_result, netsessenum_result
|
||||
|
||||
-- Create the SMB session
|
||||
status, smbstate = msrpc.start_smb(host, msrpc.SRVSVC_PATH)
|
||||
if(status == false) then
|
||||
return false, smbstate
|
||||
end
|
||||
|
||||
-- Bind to SRVSVC service
|
||||
status, bind_result = msrpc.bind(smbstate, msrpc.SRVSVC_UUID, msrpc.SRVSVC_VERSION, nil)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, bind_result
|
||||
end
|
||||
|
||||
-- Call netsessenum
|
||||
status, netsessenum_result = msrpc.srvsvc_netsessenum(smbstate, host.ip)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, netsessenum_result
|
||||
end
|
||||
|
||||
-- Stop the SMB session
|
||||
msrpc.stop_smb(smbstate)
|
||||
|
||||
return true, netsessenum_result['sessions']
|
||||
end
|
||||
|
||||
---Enumerates the users logged in locally (or through terminal services) by using functions
|
||||
-- that access the registry. To perform this check, guest access or higher is required.
|
||||
--
|
||||
--@param host The host object.
|
||||
--@return An array of user tables, each with the keys <code>name</code>, <code>domain</code>, and <code>changed_date</code> (representing
|
||||
-- when they logged in).
|
||||
local function winreg_enum_rids(host)
|
||||
local i, j
|
||||
local elements = {}
|
||||
|
||||
-- Create the SMB session
|
||||
status, smbstate = msrpc.start_smb(host, msrpc.WINREG_PATH)
|
||||
if(status == false) then
|
||||
return false, smbstate
|
||||
end
|
||||
|
||||
-- Bind to WINREG service
|
||||
status, bind_result = msrpc.bind(smbstate, msrpc.WINREG_UUID, msrpc.WINREG_VERSION, nil)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, bind_result
|
||||
end
|
||||
|
||||
status, openhku_result = msrpc.winreg_openhku(smbstate)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, openhku_result
|
||||
end
|
||||
|
||||
-- Loop through the keys under HKEY_USERS and grab the names
|
||||
i = 0
|
||||
repeat
|
||||
status, enumkey_result = msrpc.winreg_enumkey(smbstate, openhku_result['handle'], i)
|
||||
|
||||
if(status == true) then
|
||||
local status, openkey_result
|
||||
|
||||
local element = {}
|
||||
element['name'] = enumkey_result['name']
|
||||
element['sid'] = msrpc.string_to_sid(enumkey_result['name'])
|
||||
|
||||
-- To get the time the user logged in, we check the 'Volatile Environment' key
|
||||
-- This can fail with the 'guest' account due to access restrictions
|
||||
status, openkey_result = msrpc.winreg_openkey(smbstate, openhku_result['handle'], element['name'] .. "\\Volatile Environment")
|
||||
if(status ~= false) then
|
||||
local queryinfokey_result, closekey_result
|
||||
|
||||
-- Query the info about this key. The response will tell us when the user logged into the server.
|
||||
status, queryinfokey_result = msrpc.winreg_queryinfokey(smbstate, openkey_result['handle'])
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, queryinfokey_result
|
||||
end
|
||||
|
||||
status, closekey_result = msrpc.winreg_closekey(smbstate, openkey_result['handle'])
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, closekey_result
|
||||
end
|
||||
|
||||
element['changed_date'] = queryinfokey_result['last_changed_date']
|
||||
else
|
||||
-- Getting extra details failed, but we can still handle this
|
||||
element['changed_date'] = "<unknown>"
|
||||
end
|
||||
elements[#elements + 1] = element
|
||||
end
|
||||
|
||||
i = i + 1
|
||||
until status ~= true
|
||||
|
||||
status, closekey_result = msrpc.winreg_closekey(smbstate, openhku_result['handle'])
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, closekey_result
|
||||
end
|
||||
|
||||
msrpc.stop_smb(smbstate)
|
||||
|
||||
-- Start a new SMB session
|
||||
status, smbstate = msrpc.start_smb(host, msrpc.LSA_PATH)
|
||||
if(status == false) then
|
||||
return false, smbstate
|
||||
end
|
||||
|
||||
-- Bind to LSA service
|
||||
status, bind_result = msrpc.bind(smbstate, msrpc.LSA_UUID, msrpc.LSA_VERSION, nil)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, bind_result
|
||||
end
|
||||
|
||||
-- Get a policy handle
|
||||
status, openpolicy2_result = msrpc.lsa_openpolicy2(smbstate, host.ip)
|
||||
if(status == false) then
|
||||
msrpc.stop_smb(smbstate)
|
||||
return false, openpolicy2_result
|
||||
end
|
||||
|
||||
-- Convert the RIDs to names
|
||||
local results = {}
|
||||
stdnse.print_debug(3, "MSRPC: Found %d SIDs that might be logged in", #elements)
|
||||
for i = 1, #elements, 1 do
|
||||
if(elements[i]['sid'] ~= nil) then
|
||||
-- The RID is the last subauthority
|
||||
local rid = elements[i]['sid']['subauthorities'][elements[i]['sid']['count']]
|
||||
stdnse.print_debug(3, "MSRPC: Found an actual RID: %d", rid)
|
||||
|
||||
-- The server is the rest of the SID, so remove the last subauthority
|
||||
elements[i]['sid']['subauthorities'][elements[i]['sid']['count']] = nil
|
||||
elements[i]['sid']['count'] = elements[i]['sid']['count'] - 1
|
||||
|
||||
-- Look up the RID
|
||||
stdnse.print_debug(3, "MSRPC: Looking up RID %s in SID %s", rid, msrpc.sid_to_string(elements[i]['sid']))
|
||||
status, lookupsids2_result = msrpc.lsa_lookupsids2(smbstate, openpolicy2_result['policy_handle'], elements[i]['sid'], {rid})
|
||||
if(status == false) then
|
||||
-- It may not succeed, if it doesn't that's ok
|
||||
stdnse.print_debug(3, "MSRPC: Lookup failed")
|
||||
else
|
||||
-- Create the result array
|
||||
local result = {}
|
||||
result['rid'] = rid
|
||||
result['changed_date'] = elements[i]['changed_date']
|
||||
|
||||
-- Fill in the result from the response
|
||||
if(lookupsids2_result['details'][1] == nil) then
|
||||
result['name'] = "<unknown>"
|
||||
result['domain'] = ""
|
||||
else
|
||||
result['name'] = lookupsids2_result['details'][1]['name']
|
||||
result['type'] = lookupsids2_result['details'][1]['type']
|
||||
result['domain'] = lookupsids2_result['domains'][1]['name']
|
||||
end
|
||||
|
||||
if(result['type'] ~= 5) then -- Don't show "well known" accounts
|
||||
-- Add it to the results
|
||||
results[#results + 1] = result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Close the policy
|
||||
msrpc.lsa_close(smbstate, openpolicy2_result['policy_handle'])
|
||||
|
||||
-- Stop the session
|
||||
msrpc.stop_smb(smbstate)
|
||||
|
||||
return true, results
|
||||
end
|
||||
|
||||
action = function(host)
|
||||
local response = " \n"
|
||||
|
||||
local status1, status2
|
||||
|
||||
-- Enumerate the logged in users
|
||||
status1, users = winreg_enum_rids(host)
|
||||
if(status1 == false) then
|
||||
response = response .. "ERROR: Couldn't enumerate login sessions: " .. users .. "\n"
|
||||
else
|
||||
response = response .. "Users logged in:\n"
|
||||
if(#users == 0) then
|
||||
response = response .. "|_ <nobody>\n"
|
||||
else
|
||||
for i = 1, #users, 1 do
|
||||
response = response .. string.format("|_ %s\\%s since %s\n", users[i]['domain'], users[i]['name'], users[i]['changed_date'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Get the connected sessions
|
||||
status2, sessions = srvsvc_enum_sessions(host)
|
||||
if(status2 == false) then
|
||||
response = response .. "ERROR: Couldn't enumerate network sessions: " .. sessions .. "\n"
|
||||
else
|
||||
response = response .. "Active SMB Sessions:\n"
|
||||
if(#sessions == 0) then
|
||||
response = response .. "|_ <none>\n"
|
||||
else
|
||||
-- Format the result
|
||||
for i = 1, #sessions, 1 do
|
||||
|
||||
local active = sessions[i]['active']
|
||||
if(active == 0) then
|
||||
active = "[just logged in, it's probably you]"
|
||||
elseif(active > 60 * 60 * 24) then
|
||||
active = string.format("%dd%dh%02dm%02ds", active / (60*60*24), (active % (60*60*24)) / 3600, (active % 3600) / 60, active % 60)
|
||||
elseif(active > 60 * 60) then
|
||||
active = string.format("%dh%02dm%02ds", active / 3600, (active % 3600) / 60, active % 60)
|
||||
else
|
||||
active = string.format("%02dm%02ds", active / 60, active % 60)
|
||||
end
|
||||
|
||||
local idle = sessions[i]['idle']
|
||||
if(idle == 0) then
|
||||
idle = "[not idle]"
|
||||
elseif(idle > 60 * 60 * 24) then
|
||||
idle = string.format("%dd%dh%02dm%02ds", idle / (60*60*24), (idle % (60*60*24)) / 3600, (idle % 3600) / 60, idle % 60)
|
||||
elseif(idle > 60 * 60) then
|
||||
idle = string.format("%dh%02dm%02ds", idle / 3600, (idle % 3600) / 60, idle % 60)
|
||||
else
|
||||
idle = string.format("%02dm%02ds", idle / 60, idle % 60)
|
||||
end
|
||||
|
||||
response = response .. string.format("|_ %s is connected from %s for %s, idle for %s\n", sessions[i]['user'], sessions[i]['client'], active, idle)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if(status1 == false and status2 == false) then
|
||||
if(nmap.debugging() > 0) then
|
||||
return response
|
||||
else
|
||||
return nil
|
||||
end
|
||||
else
|
||||
return response
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user