Nmap Development mailing list archives
Re: [NSE] new scripts and libraries: brute library
From: David Fifield <david () bamsoftware com>
Date: Wed, 11 Aug 2010 20:16:46 -0600
On Sun, Aug 08, 2010 at 05:31:36PM +0200, Patrik Karlsson wrote:
I've been working on some stuff during the past few weeks, and as I'm back to work tomorrow, I thought I would "offload" it to the list. Some of it I have already posted but I might have made changes since, so I'm including it all again. Some of the libraries unfortunately still have chunks of (ugly) undecoded data. The foremost reason for this is the lack of documentation. The scripts and libraries have all undergone limited testing, but as always I welcome further testing, comments and suggestions. Here's a brief description of each library and script and a zip file with everything needed inside.
This is great stuff. It's hard to overstate what a valuable contributor you've become. In fact, it's starting to overwhelm my powers of review. I don't have access to all the servers these scripts work with. Because your code has been of such uniformly high quality, I'm going to spend less time looking over the code. For this batch, I'm going to take it in parts, starting with the brute library. A plea to other readers: When Patrik or anyone asks for help testing scripts, as at http://twitter.com/nevdull77/status/20637197568, please take the time to test. The easiest thing to do is just run the scripts and report the output they produced. If one crashes, the script author can usually diagnose the problem quickly.
o Brute framework - A smallish brute framework that provides the basic iterators and logic - For the moment the current scripts make use of it: x domcon-brute - see more information below x http-brute - performs password guessing against basic authentication x http-form-brute - performs form-based password guessing x informix-brute - see more information below x oracle-brute - see more information below x svn-brute - performs password guessing against subversion x vnc-brute - see more information below
I wanted to see how easy it was to write a new brute script using only the documentation for the brute library. I followed the example and made this script to talk to a server that returns "YES\n" or "NO\n".
description = "" categories = {} require("brute") require("stdnse") function portrule(host, port) return port.number == 4000 end local brute_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() return self.socket:connect(self.host.ip, self.port.number, "tcp") end, disconnect = function(self) return self.socket:close() end, check = function(self) return true end, login = function(self, username, password) local status, err, reply status, err = self.socket:send(username .. ":" .. password .. "\n") if not status then -- What? end status, reply = self.socket:receive_bytes(1) if not status then -- What? end if reply == "YES\n" then return true, brute.Account:new(username, password, "OPEN") else return false, brute.Error:new("login failed") end end } function action(host, port) local status, accounts status, accounts = brute.Engine:new(brute_driver, host, port):start() if not status then return accounts else return stdnse.format_output(true, accounts) end end
This is a little longer than the naive brute script would be, but I feel it is worth it for the automatic parallelization. It found a password for "root" quickly. $ ./nmap --datadir . --script sample-brute 192.168.0.190 -p 4000 -d2 -Pn -n --script-args brute.firstonly=1 PORT STATE SERVICE REASON 4000/tcp open remoteanything syn-ack | sample-brute: | | Accounts | root:monkey => Login correct | Statistics |_ Perfomed 25 guesses in 1 seconds, average tps: 25 What do you do when there's a socket error in the login method? Is there a way to report it, or perhaps ask the brute library to retry the credentials? A nice thing would be the ability to provide feedback to automatically reduce the number of threads, like the congestion control in the port scanning engine. I noticed that the script can say "Re-trying"; what makes this happen and how can it be controlled? It should be documented. Please also include documentation for the account states "OPEN", "LOCKED", and "DISABLED". I notice that there is a brute.emptypass script argument. I think that this is better controlled with a password list. Our default list already includes the empty password. There are other script arguments that I think could be made unnecessary with a different interface. Instead of brute.emptypass, brute.useraspass, brute.unique, and brute.passonly, what do you think of allowing the user to provide his own username and password iterators? Or course the defaults would be unpwdb.usernames and unpwdb.passwords. You could even keep the script arguments as a convenience. I'm picturing an interface like this: engine = brute.Engine:new(brute_driver, host, port) engine.usernames = my_username_iterator Things like brute.useraspass and brute.unique could be nicely implemented as wrapper iterators, rather than special-purpose code in the library. I envision that the brute library would have the most common iterators included in it. Someone wanting a unique list of usernames, for example, could do engine.usernames = brute.unique(my_username_iterator) (Or the library could do that transparently when the brute.unique script argument is given.) The reason for all this is that there may be specialized passwords, for example, that a service wants to add, along the lines of brute.useraspass. The vnc-brute script might want to do this: function extra_passwords(extras) local count = 0 local status, passwords = unpwdb.passwords() if not status then return status, passwords end return true, function(cmd) if cmd == "reset" then count = 0 end if count < #extras then count = count + 1 return extras[count] end return passwords(cmd) end end engine = brute.Engine:new(brute_driver, host, port) engine.passwords = function() return true, extra_passwords({"vnc", "VNC"}) end Other iterators could do things like changing the case of letters, appending "1", anything. Putting the knowledge in external iterators means the brute library doesn't have to know about everything that's possible. I notice that by default, the library checks every password for one user, then every password for the next, and so on. This can be controlled through the brute.mode argument. I think that putting passwords in the outer loop is a better default. What do people think about this? Another default is to keep trying credentials after a successful set is found, in an attempt to find them all. Will this last until the unpwdb time limit expires? What does everyone prefer for a default for this? Related to the previous paragraph, if there's going to be a debug message for every attempted credential, then there should definitely be one for a successful login. I don't understand the purpose of the check method. For many protocols its just going to return true. All it does is stop the engine at the very beginning if the function returns false; couldn't that just as easily be done in the action function, and simplify brute's interface? Since you've made it so easy to control the number of threads with brute.threads, this is a good opportunity to measure the effect or parallelism. I tried vnc-brute against the LAN with different script counts. In this case the difference was slight but maybe other protocols or network scenarios will do better. brute.threads=1 |_ Perfomed 2498 guesses in 8 seconds, average tps: 312 brute.threads=10 |_ Perfomed 2498 guesses in 7 seconds, average tps: 356 I want you to commit this library as it is, and make further changes under revision control. I think this is close enough to what is wanted that we shouldn't fuss with it too much before committing it. David Fifield _______________________________________________ Sent through the nmap-dev mailing list http://cgi.insecure.org/mailman/listinfo/nmap-dev Archived at http://seclists.org/nmap-dev/
Current thread:
- [NSE] new scripts and libraries Patrik Karlsson (Aug 08)
- Re: [NSE] new scripts and libraries: service probes David Fifield (Aug 11)
- Re: [NSE] new scripts and libraries: service probes Patrik Karlsson (Aug 14)
- Re: [NSE] new scripts and libraries: service probes David Fifield (Aug 18)
- Re: [NSE] new scripts and libraries: service probes Patrik Karlsson (Aug 19)
- Re: [NSE] new scripts and libraries: service probes Patrik Karlsson (Aug 14)
- Re: [NSE] new scripts and libraries: service probes David Fifield (Aug 11)
- Re: [NSE] new scripts and libraries: brute library David Fifield (Aug 11)
- Re: [NSE] new scripts and libraries: brute library David Fifield (Aug 11)
- Re: [NSE] new scripts and libraries: brute library Ron (Aug 11)
- Re: [NSE] new scripts and libraries: brute library Ron (Aug 11)
- Re: [NSE] new scripts and libraries: brute library Patrik Karlsson (Aug 14)
- Re: [NSE] new scripts and libraries: brute library David Fifield (Aug 18)
- Re: [NSE] new scripts and libraries: brute library Patrik Karlsson (Aug 19)
- Re: [NSE] new scripts and libraries: brute library David Fifield (Aug 20)
- Re: [NSE] new scripts and libraries: brute library Patrik Karlsson (Aug 20)
- Re: [NSE] new scripts and libraries: brute library David Fifield (Aug 21)
- Re: [NSE] new scripts and libraries: brute library David Fifield (Aug 11)