(original) (raw)

local nmap = require "nmap" local shortport = require "shortport" local stdnse = require "stdnse" local string = require "string" local table = require "table" description = [[ Extracts a list of Citrix servers from the ICA Browser service. ]] --- -- @usage sudo ./nmap -sU --script=citrix-enum-servers -p 1604 -- -- @output -- PORT STATE SERVICE -- 1604/udp open unknown -- | citrix-enum-servers: -- | CITRIXSRV01 -- |_ CITRIXSRV02 -- -- Version 0.2 -- Created 11/26/2009 - v0.1 - created by Patrik Karlsson patrik@cqure.net -- Revised 11/26/2009 - v0.2 - minor packet documentation author = "Patrik Karlsson" license = "Same as Nmap--See https://nmap.org/book/man-legal.html" categories = {"discovery", "safe"} portrule = shortport.portnumber(1604, "udp") -- -- process the response from the server -- @param response string, complete server response -- @return string row delimited with \n containing all published applications -- function process_server_response(response) local packet_len, pos = string.unpack("<i2", 0="" 1="" 12="" 30="" 40="" 42="" response)="" local="" server_name="" server_list="{}" if="" packet_len="" <="" then="" return="" end="" --="" the="" list="" of="" published="" applications="" starts="" at="" offset="" while="" do="" server_name,="" pos="string.unpack("z"," response:sub(offset))="" +="" -="" table.insert(server_list,="" server_name)="" action="function(host," port)="" packet,="" counter,="" socket="" query="{}" packets="" were="" intercepted="" from="" citrix="" program="" neighborhood="" client="" they="" are="" used="" to="" a="" server="" for="" its="" we're="" really="" not="" interested="" in="" responses="" first="" two="" third="" response="" contains="" i="" couldn't="" find="" any="" documentation="" on="" this="" protocol="" so="" i'm="" providing="" some="" brief="" information="" bits="" and="" bytes="" script="" uses.="" spec.="" query[2]="" that="" apps="" size="" content="" -------------------------="" 16-bit="" length="" 32-bit="" ip="" (not="" here)="" 8-bit="" last="" packet(1),="" more="" packets(0)="" null-separated="" query[0]="string.char(" 0x1e,="" 0x00,="" length:="" 0x01,="" 0x30,="" 0x02,="" 0xfd,="" 0xa8,="" 0xe3,="" 0x00="" )="" query[1]="string.char(" 0x2a,="" 0x32,="" counter="0" socket:set_timeout(5000)="" try="nmap.new_try(function()" socket:close()="" end)="" try(socket:connect(host,="" port))="" send="" never="" look="" back="" repeat="" try(socket:send(query[counter]))="" packet="try(socket:receive())" until="" (counter="">#query) -- process the first response server_list = process_server_response( packet ) -- -- the byte at offset 31 in the response has a really magic function -- if it is set to zero (0) we have more response packets to process -- if it is set to one (1) we have arrived at the last packet of our journey -- while packet:sub(31,31) ~= "\x01" do packet = try( socket:receive() ) local tmp_table = process_server_response( packet ) for _, v in ipairs(tmp_table) do table.insert(server_list, v) end end if #server_list>0 then nmap.set_port_state(host, port, "open") end socket:close() return stdnse.format_output(true, server_list) end </i2",>/patrik@cqure.net