Skip to content

Instantly share code, notes, and snippets.

@kevthehermit
Created April 9, 2022 09:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevthehermit/e7fce7b8749226340928e58f2b991021 to your computer and use it in GitHub Desktop.
Save kevthehermit/e7fce7b8749226340928e58f2b991021 to your computer and use it in GitHub Desktop.
Scans a uhppote access controller and retrieves Access Cards
-- 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