diff --git a/CHANGELOG b/CHANGELOG
index c72d36b34..db263fe88 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,8 @@
# Nmap Changelog ($Id$); -*-text-*-
+o [NSE] Ported the pop3-brute script to use the brute library.
+ [Piotr Olma]
+
o Fixed a compilation problem on Solaris 9 caused by a missing
definition of IPV6_V6ONLY. Reported by Dagobert Michelsen.
diff --git a/scripts/pop3-brute.nse b/scripts/pop3-brute.nse
index 634fd1bd5..1e127bb42 100644
--- a/scripts/pop3-brute.nse
+++ b/scripts/pop3-brute.nse
@@ -5,102 +5,122 @@ Tries to log into a POP3 account by guessing usernames and passwords.
---
-- @args pop3loginmethod The login method to use: "USER"
-- (default), "SASL-PLAIN", "SASL-LOGIN",
--- "SASL-CRAM-MD5", or "APOP".
+-- "SASL-CRAM-MD5", or "APOP". Defaults to "USER",
--
-- @output
-- PORT STATE SERVICE
-- 110/tcp open pop3
--- | pop3-brute: root : password
+-- | pop3-brute-ported:
+-- | Accounts:
+-- | user:pass => Login correct
+-- | Statistics:
+-- |_ Performed 8 scans in 1 seconds, average tps: 8
-author = "Philip Pickering"
+author = "Philip Pickering, Piotr Olma"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"intrusive", "brute"}
require 'pop3'
require 'shortport'
-require 'unpwdb'
+require 'brute'
+
+
+Driver = {
+ new = function(self, host, port, login_function, is_apop)
+ local o = {}
+ setmetatable(o, self)
+ self.__index = self
+ o.port = port
+ o.host = host
+ o.login_function = login_function
+ o.is_apop = is_apop
+ return o
+ end,
+
+ -- Attempts to connect to the POP server
+ -- @return true on success
+ -- @return false, brute.Error object on failure
+ connect = function(self)
+
+ self.socket = nmap.new_socket()
+ local opts = {timeout=10000, recv_before=true}
+ local best_opt, line
+ self.socket, _, best_opt, line = comm.tryssl(self.host, self.port, "" , opts)
+
+ if not self.socket then
+ local err = brute.Error:new("Failed to connect.")
+ err:setAbort(true)
+ return false, err
+ end --no connection
+ if not pop3.stat(line) then
+ local err = brute.Error:new("Failed to make a pop-connection.")
+ err:setAbort(true)
+ return false, err
+ end -- no pop-connection
+
+ if self.is_apop then
+ self.additional = string.match(line, "<[%p%w]+>") --apop challenge
+ end
+ return true
+ end, --connect
+
+ -- Attempts to login to the POP server
+ --
+ -- @param username string containing the login username
+ -- @param password string containing the login password
+ -- @return status, true on success, false on failure
+ -- @return brute.Error object on failure
+ -- brute.Account object on success
+ login = function(self, username, password)
+ local pstatus
+ local perror
+ pstatus, perror = self.login_function(self.socket, username, password, self.additional)
+ if pstatus then
+ return true, brute.Account:new(username, password, "OPEN")
+ elseif (perror == pop3.err.pwError) then
+ return false, brute.Error:new("Wrong password.")
+ elseif (perror == pop3.err.userError) then
+ return false, brute.Error:new("Wrong username.")
+ end
+ return false, brute.Error:new("Login failed.")
+ end, --login
+
+ disconnect = function(self)
+ self.socket:close()
+ end, --disconnect
+
+ check = function(self)
+ return true
+ end, --check
+}
portrule = shortport.port_or_service({110, 995}, {"pop3","pop3s"})
action = function(host, port)
- local pMeth = nmap.registry.args.pop3loginmethod
- if (not pMeth) then pMeth = nmap.registry.pop3loginmethod end
- if (not pMeth) then pMeth = "USER" end
+ local pMeth = nmap.registry.args.pop3loginmethod
+ if (not pMeth) then pMeth = nmap.registry.pop3loginmethod end
+ if (not pMeth) then pMeth = "USER" end
- local login
- local additional
-
- local stat = pop3.stat
-
- if (pMeth == "USER") then
- login = pop3.login_user
- elseif (pMeth == "SASL-PLAIN") then
- login = pop3.login_sasl_plain
- elseif (pMeth == "SASL-LOGIN") then
- login = login_sasl_login
- elseif (pMeth == "SASL-CRAM-MD5") then
- login = login_sasl_crammd5
- elseif (pMeth == "APOP") then
- login = login_apop
- end
-
-
- local status
- local line
- local socket = nmap.new_socket()
- local opts = {timeout=10000, recv_before=true}
-
- local socket, nothing, bopt, line = comm.tryssl(host, port, "" , opts)
-
- if not socket then return end -- no connection
- if not stat(line) then return end -- no pop-connection
-
- local apopChallenge = string.match(line, "<[%p%w]+>")
-
- if pMeth == "APOP" then
- additional = apopChallenge
- end
-
- local getUser
- local _
-
- status, getUser = unpwdb.usernames()
- if (not status) then return end
-
-
- local currUser = getUser()
- while currUser do
- local getPW
- status, getPW = unpwdb.passwords()
- if (not status) then return end
-
- local currPw = getPW()
-
- while currPw do
- local pstatus
- local perror
-
- pstatus, perror = login(socket, currUser, currPw, additional)
-
- if (pstatus) then
- return currUser .. " : " .. currPw
- elseif (perror == pop3.err.pwError) then
- currPw = getPW()
- elseif (perror == pop3.err.userError) then
- currPw = nil
- else
- local socstatus = socket:connect(host, port, bopt)
- if not socstatus
- then return
- else _, line = socket:receive()
- if not stat(line) then return end -- no connection
- end
- end
- end
- currUser = getUser()
- getPW("reset")
- end
- return -- "wrong pw"
+ --determine function we will use to login to server
+ local is_apop = false
+ if (pMeth == "USER") then
+ login_function = pop3.login_user
+ elseif (pMeth == "SASL-PLAIN") then
+ login_function = pop3.login_sasl_plain
+ elseif (pMeth == "SASL-LOGIN") then
+ login_function = pop3.login_sasl_login
+ elseif (pMeth == "SASL-CRAM-MD5") then
+ login_function = pop3.login_sasl_crammd5
+ elseif (pMeth == "APOP") then
+ login_function = pop3.login_apop
+ is_apop = true
+ else
+ login_function = pop3.login_user
+ end
+ local engine = brute.Engine:new(Driver, host, port, login_function, is_apop)
+ engine.options.script_name = SCRIPT_NAME
+ status, accounts = engine:start()
+ return accounts
end