mirror of
https://github.com/nmap/nmap.git
synced 2025-12-10 09:49:05 +00:00
Added pcanywhere-brute script
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
# Nmap Changelog ($Id$); -*-text-*-
|
||||
|
||||
o [NSE] Added pcanywhere-brute script which bruteforces pcAnywhere server
|
||||
for valid logins. [Aleksandar Nikolic]
|
||||
|
||||
o [NSE] Added http-rfi-spider script that spiders webservers in search of
|
||||
remote file inclusion vulnerabilities. [Piotr Olma]
|
||||
|
||||
|
||||
158
scripts/pcanywhere-brute.nse
Normal file
158
scripts/pcanywhere-brute.nse
Normal file
@@ -0,0 +1,158 @@
|
||||
local brute = require "brute"
|
||||
local creds = require "creds"
|
||||
local nmap = require "nmap"
|
||||
local shortport = require "shortport"
|
||||
local stdnse = require "stdnse"
|
||||
local string = require "string"
|
||||
local bit = require "bit"
|
||||
local bin = require "bin"
|
||||
local table = require "table"
|
||||
description = [[
|
||||
Performs password guessing against pcAnywhere.
|
||||
|
||||
Due to certain limitations of the protocol, bruteforcing
|
||||
is limited to single thread at a time.
|
||||
After a valid login pair is guessed the script waits
|
||||
some time until server becomes available again.
|
||||
|
||||
]]
|
||||
|
||||
---
|
||||
-- @usage
|
||||
-- nmap --script=pcanywhere-brute <target>
|
||||
--
|
||||
-- @output
|
||||
-- 5631/tcp open pcanywheredata syn-ack
|
||||
-- | pcanywhere-brute:
|
||||
-- | Accounts
|
||||
-- | administrator:administrator - Valid credentials
|
||||
-- | Statistics
|
||||
-- |_ Performed 2 guesses in 55 seconds, average tps: 0
|
||||
|
||||
|
||||
author = "Aleksandar Nikolic"
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
categories = {"intrusive", "brute"}
|
||||
|
||||
|
||||
portrule = shortport.port_or_service(5631, "pcanywheredata")
|
||||
|
||||
local arg_timeout = stdnse.get_script_args(SCRIPT_NAME .. ".timeout") or 10
|
||||
|
||||
-- implements simple xor based encryption which the server expects
|
||||
local function encrypt(data)
|
||||
local result = {}
|
||||
local xor_key = 0xab
|
||||
local k = 0
|
||||
if data then
|
||||
result[1] = bit.bxor(string.byte(data),xor_key)
|
||||
for i = 2,string.len(data) do
|
||||
result[i] = bit.bxor(result[i-1],string.byte(data,i),i-2)
|
||||
end
|
||||
end
|
||||
return string.char(table.unpack(result))
|
||||
end
|
||||
|
||||
local retry = false -- true means we found valid login and need to wait
|
||||
|
||||
Driver = {
|
||||
|
||||
new = function(self, host, port)
|
||||
local o = {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
o.host = host
|
||||
o.port = port
|
||||
return o
|
||||
end,
|
||||
|
||||
connect = function( self )
|
||||
self.socket = nmap.new_socket()
|
||||
local response
|
||||
local err
|
||||
local status = false
|
||||
|
||||
stdnse.sleep(2)
|
||||
-- when we hit a valid login pair, server enters some kind of locked state
|
||||
-- so we need to wait for some time before trying next pair
|
||||
-- variable "retry" signifies if we need to wait or this is just not pcAnywhere server
|
||||
while not status do
|
||||
status, err = self.socket:connect(self.host, self.port)
|
||||
self.socket:set_timeout(tonumber(arg_timeout) * 1000)
|
||||
if(not(status)) then
|
||||
return false, brute.Error:new( "Couldn't connect to host: " .. err )
|
||||
end
|
||||
status, err = self.socket:send(bin.pack("H","00000000")) --initial hello
|
||||
status, response = self.socket:receive_bytes(0)
|
||||
if not status and not retry then
|
||||
break
|
||||
end
|
||||
stdnse.print_debug("in a loop")
|
||||
stdnse.sleep(2) -- needs relatively big timeout between retries
|
||||
end
|
||||
if not status or string.find(response,"Please press <Enter>") == nil then
|
||||
--probably not pcanywhere
|
||||
stdnse.print_debug(1, "%s: not pcAnywhere", SCRIPT_NAME)
|
||||
return false, brute.Error:new( "Probably not pcAnywhere." )
|
||||
end
|
||||
retry = false
|
||||
status, err = self.socket:send(bin.pack("H","6f06ff")) -- downgrade into legacy mode
|
||||
status, response = self.socket:receive_bytes(0)
|
||||
|
||||
status, err = self.socket:send(bin.pack("H","6f61000900fe0000ffff00000000")) -- auth capabilities I
|
||||
status, response = self.socket:receive_bytes(0)
|
||||
|
||||
status, err = self.socket:send(bin.pack("H","6f620102000000")) -- auth capabilities II
|
||||
status, response = self.socket:receive_bytes(0)
|
||||
if not status or (string.find(response,"Enter user name") == nil and string.find(response,"Enter login name") == nil) then
|
||||
stdnse.print_debug(1, "%s: handshake failed", SCRIPT_NAME)
|
||||
return false, brute.Error:new( "Handshake failed." )
|
||||
end
|
||||
return true
|
||||
end,
|
||||
|
||||
login = function (self, user, pass)
|
||||
local response
|
||||
local err
|
||||
local status
|
||||
stdnse.print_debug( "Trying %s/%s ...", user, pass )
|
||||
-- send username and password
|
||||
-- both are prefixed with 0x06, size and are encrypted
|
||||
status, err = self.socket:send(bin.pack("C",0x06) .. bin.pack("C",string.len(user)) .. encrypt(user) ) -- send username
|
||||
status, response = self.socket:receive_bytes(0)
|
||||
if not status or string.find(response,"Enter password") == nil then
|
||||
stdnse.print_debug(1, "%s: Sending username failed", SCRIPT_NAME)
|
||||
return false, brute.Error:new( "Sending username failed." )
|
||||
end
|
||||
-- send password
|
||||
status, err = self.socket:send(bin.pack("C",0x06) .. bin.pack("C",string.len(pass)) .. encrypt(pass) ) -- send password
|
||||
status, response = self.socket:receive_bytes(0)
|
||||
if not status or string.find(response,"Login unsuccessful") or string.find(response,"Invalid login.")then
|
||||
stdnse.print_debug(1, "%s: Incorrect username or password", SCRIPT_NAME)
|
||||
return false, brute.Error:new( "Incorrect username or password." )
|
||||
end
|
||||
|
||||
if status then
|
||||
retry = true -- now the server is in "locked mode", we need to retry next connection a few times
|
||||
return true, brute.Account:new( user, pass, creds.State.VALID)
|
||||
end
|
||||
return false,brute.Error:new( "Incorrect password" )
|
||||
end,
|
||||
|
||||
disconnect = function( self )
|
||||
self.socket:close()
|
||||
return true
|
||||
end
|
||||
|
||||
}
|
||||
|
||||
action = function( host, port )
|
||||
|
||||
local status, result
|
||||
local engine = brute.Engine:new(Driver, host, port)
|
||||
engine.options.script_name = SCRIPT_NAME
|
||||
engine.max_threads = 1 -- pcAnywhere supports only one login at a time
|
||||
status, result = engine:start()
|
||||
|
||||
return result
|
||||
end
|
||||
@@ -279,6 +279,7 @@ Entry { filename = "oracle-sid-brute.nse", categories = { "brute", "intrusive",
|
||||
Entry { filename = "ovs-agent-version.nse", categories = { "version", } }
|
||||
Entry { filename = "p2p-conficker.nse", categories = { "default", "safe", } }
|
||||
Entry { filename = "path-mtu.nse", categories = { "discovery", "safe", } }
|
||||
Entry { filename = "pcanywhere-brute.nse", categories = { "brute", "intrusive", } }
|
||||
Entry { filename = "pgsql-brute.nse", categories = { "brute", "intrusive", } }
|
||||
Entry { filename = "pjl-ready-message.nse", categories = { "intrusive", } }
|
||||
Entry { filename = "pop3-brute.nse", categories = { "brute", "intrusive", } }
|
||||
|
||||
Reference in New Issue
Block a user