diff --git a/CHANGELOG b/CHANGELOG
index 76de324f9..47b0d007d 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,12 @@
# Nmap Changelog ($Id$); -*-text-*-
+o Added a new NSE Unpwdb (username/password database) library for easily
+ obtaining usernames or passwords from a list. The functions usernames()
+ and passwords() return a closure which returns a new list entry with
+ every call, or nil when the list is exhausted. You can specify your
+ own username and/or password lists via the script arguments userdb
+ and passdb, respectively. [Kris]
+
o The Ports/Hosts display in Zenmap now has different colors for open
and closed ports. [Vladimir]
diff --git a/docs/scripting.xml b/docs/scripting.xml
index 8b8403971..ed5c60d9c 100644
--- a/docs/scripting.xml
+++ b/docs/scripting.xml
@@ -1705,6 +1705,67 @@ if(s) code_to_be_done_on_match end
+
+ Username/Password Database Functions
+ unpwdb NSE module
+
+ The unpwdb module provides functions for easily obtaining
+ usernames and/or passwords from a "database" (list). The most obvious use
+ for this library is brute-force attack. The first two functions' return values
+ are setup for use with exception handling via nmap.new_try().
+ exceptions in NSE
+
+
+
+
+
+
+
+ This function returns a closure which returns a new username
+ with every call, or nil when the list is
+ exhausted. This closure takes an optional argument of
+ "reset" to rewind the list to the beginning.
+ You can specify your own username list with the script argument
+ userdb.
+
+
+
+
+
+
+
+
+ This function returns a closure which returns a new password
+ with every call, or nil when the list is
+ exhausted. This closure takes an optional argument of
+ "reset" to rewind the list to the beginning.
+ You can specify your own password list with the script argument
+ passdb.
+
+
+
+
+
+
+
+
+ This function returns the suggested number of seconds to
+ attempt a brute force attack, based on Nmap's timing values
+ (, etc) and whether or not a user-defined
+ list is used. You can use the script argument
+ notimelimit to make this function return
+ nil, which means the brute-force should
+ run until the list is empty. If notimelimit
+ is not used, be sure to still check for nil
+ return values on the above two functions in case you finish
+ before the time limit is up.
+
+
+
+
+
+
+
Data File Parsing Functionsdatafiles NSE module
diff --git a/nselib/data/passwords.lst b/nselib/data/passwords.lst
new file mode 100644
index 000000000..281b4fa34
--- /dev/null
+++ b/nselib/data/passwords.lst
@@ -0,0 +1,200 @@
+
+password1
+abc123
+fuckyou
+monkey1
+iloveyou1
+fuckyou1
+i
+password
+number1
+football1
+nicole1
+123456
+iloveyou2
+123abc
+princess1
+bubbles1
+blink182
+babygirl1
+123456a
+qwerty1
+jordan1
+iloveyou
+fuck
+bitch
+asshole
+password2
+michael1
+love123
+soccer1
+hockey1
+fuckyou2
+anthony1
+poohbear1
+justin1
+iloveyou!
+greenday1
+fuckyou!
+snoopy1
+password3
+chocolate1
+cheese1
+charlie1
+a123456
+soccer2
+orange1
+loser1
+liverpool1
+jordan23
+jesus1
+iloveyou.
+cookie1
+bitch1
+baseball1
+ballin1
+ashley1
+amanda1
+tigger1
+summer1
+shadow1
+qwerty12
+password!
+nigger1
+loveyou1
+iloveu1
+friends1
+forever1
+computer1
+chicken1
+carmen1
+babygurl1
+1qwerty
+yankees1
+william1
+tweety1
+taylor1
+superman1
+shorty1
+scooby1
+password.
+passw0rd
+panda1
+nirvana1
+matthew1
+marie1
+loveme1
+joshua1
+iloveyou3
+hollister1
+hello1
+green1
+fuckoff
+fluffy1
+faggot
+elizabeth1
+chocolate!
+brandon1
+batman1
+12345a
+yellow1
+whatever1
+victoria1
+trustno1
+tigger
+sunshine1
+spongebob1
+soccer14
+simba1
+red123
+orlando1
+michelle1
+loser
+kisses1
+joseph1
+jimmy1
+jessica1
+freedom1
+football2
+element1
+dragon1
+david1
+chris1
+charlotte1
+cameron1
+butterfly1
+buster1
+bowwow1
+bailey1
+andrew1
+50cent
+123qwe
+whatever
+weed420
+water1
+sweet16
+stupid1
+steven1
+steelers1
+soccer8
+soccer4
+soccer13
+slipknot1
+single1
+sidekick3
+ronaldo7
+rocky1
+puppy1
+pimpin1
+penis1
+peanut1
+password4
+panic!
+noodles1
+muffin1
+mother1
+monkey2
+money1
+money$
+mommy1
+loveu2
+lover1
+lovely1
+love22
+love12
+killer1
+jasper1
+iverson3
+internet1
+iloveu2
+hottie1
+hannah1
+google1
+george1
+gangsta1
+fuckyou.
+fucku
+fuck
+elephant1
+disney1
+cutiepie1
+cunt
+cookies1
+compaq1
+candy1
+bubble1
+booboo1
+baseball3
+banana1
+babyboy1
+asdf1234
+asd123
+angels1
+angel1
+andrew
+aaliyah1
+1password
+1234abcd
+
+zxcvbnm1
+young1
diff --git a/nselib/data/usernames.lst b/nselib/data/usernames.lst
new file mode 100644
index 000000000..06d91bc63
--- /dev/null
+++ b/nselib/data/usernames.lst
@@ -0,0 +1,10 @@
+root
+admin
+administrator
+webadmin
+sysadmin
+netadmin
+guest
+user
+web
+test
diff --git a/nselib/unpwdb.lua b/nselib/unpwdb.lua
new file mode 100644
index 000000000..0c3846027
--- /dev/null
+++ b/nselib/unpwdb.lua
@@ -0,0 +1,153 @@
+-- Kris Katterjohn 06/2008
+
+module(..., package.seeall)
+
+---- Username/Password DB Library
+--
+-- usernames() - Returns a closure which returns a new username with every call
+-- until the username list is exhausted (in which case it returns nil)
+--
+-- passwords() - Returns a closure which returns a new password with every call
+-- until the password list is exhausted (in which case it returns nil)
+--
+-- timelimit() - Returns the suggested number of seconds to attempt a brute
+-- force attack, based on Nmap's timing values (-T4, etc) and whether or not a
+-- user-defined list is used. You can use the script argument "notimelimit" to
+-- make this function return nil, which means the brute-force should run until
+-- the list is empty. If "notimelimit" is not used, be sure to still check for
+-- nil return values on the above two functions in case you finish before the
+-- time limit is up.
+--
+-- The first two functions return multiple values for use with exception handling
+-- via nmap.new_try(). The first value is the boolean success indicator, the
+-- second value is the closure.
+--
+-- The closures can take a parameter of "reset" to rewind the list to the
+-- beginning.
+--
+-- You can select your own username and/or password database to read from with
+-- the script arguments userdb and passdb, respectively. Comments are allowed
+-- in these files, prefixed with "#!comment:". Comments cannot be on the same
+-- line as a username or password because this leaves too much ambiguity, e.g.
+-- does the password in "mypass #!comment: blah" contain a space, two spaces,
+-- or do they just separate the password from the comment?
+--
+----
+
+local usertable = {}
+local passtable = {}
+
+local customdata = false
+
+-- So I don't have to type as much :)
+local args = nmap.registry.args
+
+local userfile = function()
+ if args.userdb then
+ customdata = true
+ return args.userdb
+ end
+
+ return nmap.fetchfile("nselib/data/usernames.lst")
+end
+
+local passfile = function()
+ if args.passdb then
+ customdata = true
+ return args.passdb
+ end
+
+ return nmap.fetchfile("nselib/data/passwords.lst")
+end
+
+local filltable = function(filename, table)
+ if #table ~= 0 then
+ return true
+ end
+
+ local file = io.open(filename, "r")
+
+ if not file then
+ return false
+ end
+
+ while true do
+ local l = file:read()
+
+ if not l then
+ break
+ end
+
+ -- Comments takes up a whole line
+ if not l:match("#!comment:") then
+ table[#table + 1] = l
+ end
+ end
+
+ file:close()
+
+ return true
+end
+
+local closure = function(table)
+ local i = 1
+
+ return function(cmd)
+ if cmd == "reset" then
+ i = 1
+ return
+ end
+ local elem = table[i]
+ if elem then i = i + 1 end
+ return elem
+ end
+end
+
+-- If we're reading from a user-defined username or password list,
+-- we'll give them a timeout 1.5x the default. If the "notimelimit"
+-- script argument is used, we return nil.
+timelimit = function()
+ local t = nmap.timing_level()
+
+ -- Easy enough
+ if args.notimelimit then
+ return nil
+ end
+
+ if t <= 3 then
+ return (customdata and 900) or 600
+ elseif t == 4 then
+ return (customdata and 450) or 300
+ elseif t == 5 then
+ return (customdata and 270) or 180
+ end
+end
+
+usernames = function()
+ local path = userfile()
+
+ if not path then
+ return false, "Cannot find username list"
+ end
+
+ if not filltable(path, usertable) then
+ return false, "Error parsing username list"
+ end
+
+ return true, closure(usertable)
+end
+
+passwords = function()
+ local path = passfile()
+
+ if not path then
+ return false, "Cannot find password list"
+ end
+
+ if not filltable(path, passtable) then
+ return false, "Error parsing password list"
+ end
+
+ return true, closure(passtable)
+end
+