Perl brute force attack - perl

I am having a lot of trouble trying to create a brute force script. The password I need to crack is 1 to 4 characters long and all lowercase letters. I think I have figured out the code to generate all the possible combinations but I am not sure how to test this on a file. Any guidance or hints would be great.
$password = "aaaa";
while ( length $password < 5 ) {
print "$password\n";
$password++;

I had this similar problem. Either you are in my class or scripting classes around the country do this problem at the same time. My professor encourages forum use but we can't share answers with direct classmates at our university.
If you know me from your class by my username, then I ask that you do not use my code. Otherwise enjoy. I have commented the code since learning from working code is the best way to learn.
As long as you are using only letters you can just increment a scalar instead of nesting loops. If you do need to use other characters I bet you could just use an array of possible characters and increment through that array for each position, though let's ignore that since you seem to only need those letters =)
sub brute2()
{
print "Bruteforce Attack...\n";
print "Enter password length: "; #Prompt user for maximum length for pass
chomp(my $plen = (<>)); #Receive input and remove newline character
print "Password Length is $plen\n";
$plen++;
print "Press any key to continue.\n"; #Execute once they hit any key
if (<>)
{
my $pass = "a"; #This code assumes only letters a..z, so we just set here
while ( length $pass < $plen ) #Run check loop until we exaust all possibilities within the maximum length
{
my $status = system("unzip -pp -o -P $pass secret_file_brute.zip > /dev/null 2>&1"); #System call to compare our password against a zip file, this will set status to the return value
print ("Attempting: $pass Return: $status\n");
if ($status == 0) #Return value of 0 means success
{
print ("Password is: $pass Return is: $status\n"); #Print correct password. I did return value also for debug
last; #Break loop since we got correct password
}
$pass++; #Increment $pass var to next iteration IE "a" to "b", "aa" to "ab", "zzz" to "aaaa" etc...
}
}
}

According to the man page I found, unzip returns exit code 82 when it can't decrypt.
sub try {
my ($password) = #_;
system("unzip -qq -o -P $password secret_file_brute.zip >/dev/null 2>&1");
die("Can't launch unzip: $!\n") if $? == -1;
die("unzip killed by signal ".($? & 0x7F)."\n") if $? & 0x7F;
my $exit_code = $? >> 8;
die("unzip exited with error $exit_code\n") if $exit_code && $exit_code != 82;
return !$exit_code;
}
Your code does not generate all of the possible passwords (e.g. it doesn't generate aaa). The following does:
sub brute_force {
for (my $password = 'a'; length($password)<5; ++$password) {
return $password if try($password);
}
return undef;
}
The final bit is to display the results.
{
my $password = brute_force();
defined($password)
or die("Password not found\n");
print("$password\n");
}

Related

"Use of uninitialized value in numeric eq (==)" at particular line of perl script reported [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I'm new to perl scripting and one section of script it is looking for any AIX users that have a value of maxage=0
Here is body of the script.
$msg = "No violations";
$violations = "";
foreach my $user (#if_password_must_expire_users) {
$i++ while (exists $pass_file[$i] && $pass_file[$i] !~ /$user:\s*/);
my $id_found=1 if (exists $pass_file[$i]);
$i++ while (exists $pass_file[$i] && $pass_file[$i] !~ /password\s*=/ && $id_found);
if ($id_found) {
if ($pass_file[$i] =~ /\*\s*$/) {
my $maxage_check=`lssec -f /etc/security/user -s $user -a maxage`;
my ($maxage) = ( $maxage_check =~ /[^=]+\s*([0-9]+)/ );
if ($maxage == 0) {
$violations .= $user."; ";
$msg = "Violations: ";
}
}
}
}
write_result($section,$msg);
The relevant section of code is this:
my $maxage_check=`lssec -f /etc/security/user -s $user -a maxage`;
my ($maxage) = ( $maxage_check =~ /[^=]+\s*([0-9]+)/ );
if ($maxage == 0) {
...
}
The first line runs the external program lssec to get information about a particular user and stores the output from that command in $maxage_check.
The second line attempts to extract the actual maxage information out of the output from the external command and stores that value in $maxage.
The third line checks to see if the value stored in $maxage is zero.
But the warning you're seeing says that when you examine the value in $maxage, on the third line, that value is undefined (or, in Perl terms, undef). That would happen if the extraction on your second line of code didn't extract the value successfully. And that means your regular expression didn't match the data in $maxage_check.
The best way to investigate this further is to display the value of $maxage_check in the cases where the regex doesn't work.
Something like this might work:
my $maxage_check=`lssec -f /etc/security/user -s $user -a maxage`;
my ($maxage) = ( $maxage_check =~ /[^=]+\s*([0-9]+)/ );
if (defined $maxage) {
if ($maxage == 0) {
...
}
} else {
warn "Cannot extract maxage successfully\n";
warn "Input string: $maxage_check";
}
That will show you what the problematic command output is and from there you can work on fixing your regex so it matches correctly.
Update: We don't all work on AIX so we don't have a copy of lssec easily available in order to check what its output looks like. It would have been really helpful if you could have included examples in your question.
But it might be helpful to tell you what your current regex is trying to match:
One or more characters that aren't equals signs, followed by...
Zero or more whitespace characters (spaces, tabs), followed by...
One or more digits (which you capture and store in $maxage)

Perl - Trouble with my unzip system call for zip file crack

I am a junior currently taking a scripting languages class that is suppose to spit us out with intermediate level bash, perl, and python in one semester. Since this class is accelerated, we speed through topics quickly and our professor endorses using forums to supplement our learning if we have questions.
I am currently working on our first assignment. The requirement is to create a very simple dictionary attack using a provided wordlist "linux.words" and a basic bruteforce attack. The bruteforce needs to compensate for any combination of 4 letter strings.
I have used print statements to check if my logic is sound, and it seems it is. If you have any suggestions on how to improve my logic, I am here to learn and I am all ears.
This is on Ubuntu v12.04 in case that is relevant.
I have tried replacing the scalar within the call with a straight word like unicorn and it runs fine, obviously is the wrong password, and it returns correctly. I have done this both in terminal and in the script itself. My professor has looked over this for a good 15 minutes he could spare, before referring me to forum, and said it looked good. He suspected that since I wrote the code using Notepad++ there might be hidden characters. I rewrote the code straight in the terminal using vim and it gave the same errors above. The code pasted is below is from vim.
My actual issue is that my system call is giving me problems. It returns the help function for unzip showing usages and other help material.
Here is my code.
#!/usr/bin/perl
use strict;
use warnings;
#Prototypes
sub brute();
sub dict();
sub AddSlashes($);
### ADD SLASHES ###
sub AddSlashes($)
{
my $text = shift;
$text =~ s/\\/\\\\/g;
$text =~ s/'/\\'/g;
$text =~ s/"/\\"/g;
$text =~ s/\\0/\\\\0/g;
return $text;
}
### BRUTEFORCE ATTACK ###
sub brute()
{
print "Bruteforce Attack...\n";
print "Press any key to continue.\n";
if (<>)
{
#INCEPTION START
my #larr1 = ('a'..'z'); #LEVEL 1 +
foreach (#larr1)
{
my $layer1 = $_; #LEVEL 1 -
my #larr2 = ('a'..'z'); #LEVEL 2 +
foreach (#larr2)
{
my $layer2 = $_; # LEVEL 2 -
my#larr3 = ('a'..'z'); #LEVEL 3 +
foreach (#larr3)
{
my $layer3 = $_; #LEVEL 3 -
my#larr4 = ('a'..'z'); #LEVEL 4 +
foreach (#larr4)
{
my $layer4 = $_;
my $pass = ("$layer1$layer2$layer3$layer4");
print ($pass); #LEVEL 4 -
}
}
}
}
}
}
### DICTIONARY ATTACK ###
sub dict()
{
print "Dictionary Attack...\n"; #Prompt User
print "Provide wordlist: ";
my $uInput = "";
chomp($uInput = <>); #User provides wordlist
(open IN, $uInput) #Bring in wordlist
or die "Cannot open $uInput, $!"; #If we cannot open file, alert
my #dict = <IN>; #Throw the wordlist into an array
foreach (#dict)
{
print $_; #Debug, shows what word we are on
#next; #Debug
my $pass = AddSlashes($_); #To store the $_ value for later use
#Check pass call
my $status = system("unzip -qq -o -P $pass secret_file_dict.zip > /dev/null 2>&1"); #Return unzip system call set to var
#Catch the correct password
if ($status == 0)
{
print ("Return of unzip is ", $status, " and pass is ", $pass, "\n"); #Print out value of return as well as pass
last;
}
}
}
### MAIN ###
dict();
exit (0);
Here is my error
See "unzip -hh" or unzip.txt for more help. Examples:
unzip data1 -x joe => extract all files except joe from zipfile data1.zip
unzip -p foo | more => send contents of foo.zip via pipe into program more
unzip -fo foo ReadMe => quietly replace existing ReadMe if archive file newer
aerify
UnZip 6.00 of 20 April 2009, by Debian. Original by Info-ZIP.
Usage: unzip [-Z] [-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]
Default action is to extract files in list, except those in xlist, to exdir;
file[.zip] may be a wildcard. -Z => ZipInfo mode ("unzip -Z" for usage).
-p extract files to pipe, no messages -l list files (short format)
-f freshen existing files, create none -t test compressed archive data
-u update files, create if necessary -z display archive comment only
-v list verbosely/show version info -T timestamp archive to latest
-x exclude files that follow (in xlist) -d extract files into exdir
modifiers:
-n never overwrite existing files -q quiet mode (-qq => quieter)
-o overwrite files WITHOUT prompting -a auto-convert any text files
-j junk paths (do not make directories) -aa treat ALL files as text
-U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields
-C match filenames case-insensitively -L make (some) names lowercase
-X restore UID/GID info -V retain VMS version numbers
-K keep setuid/setgid/tacky permissions -M pipe through "more" pager
-O CHARSET specify a character encoding for DOS, Windows and OS/2 archives
-I CHARSET specify a character encoding for UNIX and other archives
See "unzip -hh" or unzip.txt for more help. Examples:
unzip data1 -x joe => extract all files except joe from zipfile data1.zip
unzip -p foo | more => send contents of foo.zip via pipe into program more
unzip -fo foo ReadMe => quietly replace existing ReadMe if archive file newer
aerifying
It is obviously not complete. In the main I will switch the brute(); for dict(); as needed to test. Once I get the system call working I will throw that into the brute section.
If you need me to elaborate more on my issue, please let me know. I am focused here on learning, so please add idiot proof comments to any thing you respond to me with.
First: DO NOT USE PERL'S PROTOTYPES. They don't do what you or your professor might wish they do.
Second: Don't write homebrew escaping routines such as AddSlashes. Perl has quotemeta. Use it.
Your problem is not with the specific programming language. How much time your professor has spent on your problem, how many classes you take are irrelevant to the problem. Focus on the actual problem, not all the extraneous "stuff".
Such as, what is the point of sub brute? You are not calling it in this script, it is not relevant to your problem, so don't post it. Narrow down your problem to the smallest relevant piece.
Don't prompt for the wordlist file in the body of dict. Separate the functionality into bite sized chunks so in each context you can focus on the problem at hand. Your dict_attack subroutine should expect to receive either a filehandle or a reference to an array of words. To keep memory footprint low, we'll assume it's a filehandle (so you don't have to keep the entire wordlist in memory).
So, your main looks like:
sub main {
# obtain name of wordlist file
# open wordlist file
# if success, call dict_attack with filehandle
# dict_attack returns password on success
}
Now, you can focus on dict_attack.
#!/usr/bin/perl
use strict;
use warnings;
main();
sub dict_attack {
my $dict_fh = shift;
while (my $word = <$dict_fh>) {
$word =~ s/\A\s+//;
$word =~ s/\s+\z//;
print "Trying $word\n";
my $pass = quotemeta( $word );
my $cmd = "unzip -qq -o -P $pass test.zip";
my $status = system $cmd;
if ($status == 0) {
return $word;
}
}
return;
}
sub main {
my $words = join("\n", qw(one two three four five));
open my $fh, '<', \$words or die $!;
if (my $pass = dict_attack($fh)) {
print "Password is '$pass'\n";
}
else {
print "Not found\n";
}
return;
}
Output:
C:\...> perl y.pl
Trying one
Trying two
Trying three
Trying four
Trying five
Password is 'five'

Brute force attack test on password for file

I'm trying to create a brute force that will work on a specific files password.
I'm not sure how to get this code to work. This is what I have so far. This code produces the correct possible combinations for the password but I am not sure how to implement this into a brute force attack.
my #alpha = qw(a b c d e f g h i j k l m n o p q r s t u v w x y z);
my $password = #alpha[1];
my #combo = ();
for my $one(#alpha){
for my $two(#alpha){
for my $three(#alpha){
for my $four(#alpha){ push #combo, "$one$two$three$four\n"} }}
I assume ill need to use this command somewhere and secret_file_brute.zip is the file I'm using to test on.
I'm not sure how to declare the $password variable and how to enter my generated combinations from above one by one where the $password command is until the passwords is a match.
$returnVal = system("unzip -qq -o -P $password
secret_file_brute.zip > /dev/null 2>&1");
I think you're trying to generate all possible combination of passwords with the 26 latin characters. Right? Why not use the increment operator?
$password = "a";
for (;;) {
say "$password";
$password++;
}
$password will go from a to z, then from aa to zz, then from aaa to zzz, etc. Thus generating each and every possible combination of passwords from the 26 latin alphabetic characters.
If you're only interested in four character combinations:
$password = "aaaa";
while ( length $password < 5 ) {
say "$password";
$password++;
}
Brute force password cracking is very inefficient, so not really useful except as proof of concept.
You've a 4 character alphabetical password, which is a fairly trivial case.
First off - you can write:
my #alpha =( "a".."z" );
generating the words as you're doing will work, but you'll be inserting a linefeed, which means whatever system command you're running won't work.
You also might find making the attempt as you go will improve your speed, not least because you can use multiprocessing trivially for this sort of operation.
Also - you can trap the return code for system to see when you succeed. Capturing the text output of system won't help - you need to inspect $? - see: http://perldoc.perl.org/functions/system.html
Something like this maybe?
#!/usr/bin/perl
use strict;
use warnings;
use Parallel::ForkManager;
my $parallel = 8;
my #alpha = ( "a" .. "z" );
my $manager = Parallel::ForkManager->new($parallel);
my $parent_pid = $$;
for my $one (#alpha) {
for my $two (#alpha) {
for my $three (#alpha) {
for my $four (#alpha) {
$manager->start and next;
system(
"unzip -qq -o -P $one$two$three$four secret_file_brute.zip > /dev/null 2>&1"
);
if ( not $? ) {
print "Password was $one$two$three$four\n";
kill $parent_pid;
}
$manager->finish;
}
}
}
}

ksh perl script.. if condition

Friends...
I have got bash script which calls perl script and emails logfile result everytime.
I want to change my bash script such that it should only email if there is value in perl subroutine row counter (rcounter++) and not all time.
any tips on how to change .ksh file?
.ksh
#!/bin/ksh
d=`date +%Y%m%d`
log_dir=$HOME
output_file=log.list
if ! list_tables -login /#testdb -outputFile $output_file
then
mailx -s "list report : $d" test#mail < $output_file
fi
=======Below if condition also works for me=============================
list_tables -login /#testdb -outputFile $output_file
if ["$?" -ne "0"];
then
mailx -s "list report : $d" test#mail < $output_file
fi
========================================================================
Perl Script: list_tables
use strict;
use Getopt::Long;
use DBI;
use DBD::Oracle qw(:ora_types);
my $exitStatus = 0;
my %options = ()
my $oracleLogin;
my $outputFile;
my $runDate;
my $logFile;
my $rcounter;
($oracleLogin, $outputFile) = &validateCommandLine();
my $db = &attemptconnect($oracleLogin);
&reportListTables($outputFile);
$db->$disconnect;
exit($rcounter);
#---------------------------
sub reportListTables {
my $outputFile = shift;
if ( ! open (OUT,">" . $outputfile)) {
&logMessage("Error opening $outputFile");
}
print OUT &putTitle;
my $oldDB="DEFAULT";
my $dbcounter = 0;
my $i;
print OUT &putHeader();
#iterate over results
for (my $i=0; $i<=$lstSessions; $i++) {
# print result row
print OUT &putRow($i);
$dbCounter++;
}
print OUT &putFooter($dbCounter);
print OUT " *** Report End \n";
closeOUT;
}
#------------------------------
sub putTitle {
my $title = qq{
List Tables: Yesterday
--------------
};
#------------------------------
sub putHeader {
my $header = qq{
TESTDB
==============
OWNER Table Created
};
#------------------------------
sub putRow {
my $indx = shift;
my $ln = sprintf "%-19s %-30s %-19s",
$lstSessions[$indx]{owner},
$lstSessions[$indx]{object_name},
$lstSessions[$indx]{created};
return "$ln\n";
}
#------------------------------
sub getListTables {
my $runDt = shift;
$rcounter = 0;
my $SQL = qq{
selct owner, object_name, to_char(created,'MM-DD-YYYY') from dba_objects
};
my $sth = $db->prepare ($SQL) or die $db->errstr;
$sth->execute() or die $db->errstr;;
while (my #row = $sth->fethcrow_array) {
$lstSessions[$rcounter] {owner} =$row[0];
$lstSessions[$rcounter] {object_name} =$row[1];
$lstSessions[$rcounter] {created} =$row[2];
&logMessage(" Owner: $lstSessions[$rcounter]{owner}");
&logMessage(" Table: $lstSessions[$rcounter]{object_name}");
&logMessage(" created: $lstSessions[$rcounter]{created}");
$rcounter++;
}
&logMessage("$rcounter records found...");
}
thanks..
also happy to include mail-x part in perl if that makes life more easy..
I am not sure I understood your question correctly. Also, your code is incomplete. So there's some guessing involved.
You cannot check the value of a local Perl variable from the caller's side.
But if your question is if the Perl code added anything to the logfile, the solution is simple: Delete the "rcounter records found..." line (which doesn't make sense anyway since it is always executed, whether the query returned results or not). Then, let the shell script backup the logfile before the call to Perl, and make a diff afterwards, sending the mail only if diff tells you there has been output added to the logfile.
If this doesn't help you, please clarify the question.
EDIT (from comments below):
Shell scripting isn't that difficult. Right now, your Perl script ends with:
$db->($exitStatus);
That is your exit code. You don't check that in your shell script anyway, so you could change it to something more useful, like the number of data rows written. A primitive solution would be to make $rcounter global (instead of local to getListTables()), by declaring it at the top of the Perl script (e.g. after my $logFile;). Then you could replace the "exitStatus" line above with simply:
$rcounter;
Voila, your Perl script now returns the number of data rows written.
In Perl, a return code of 0 is considered a failure, any other value is a success. In shell, it's the other way around - but luckily you don't have to worry about that as Perl knows that and "inverts" (negates) the return code of a script when returning to the calling shell.
So all you need is making the mailing depend on a non-zero return of Perl:
if list_tables -login /#testdb -outputFile $output_file
then
mailx -s "list report : $d" test#mail < $output_file
fi
A comment on the side: It looks to me as if your programming skill isn't up to par with the scope of the problem you are trying to solve. If returning a value from Perl to bash gives you that much trouble, you should probably spend your time with tutorials, not with getting input from a database and sending emails around. Learn to walk before you try to fly...

How can I enter a password using Perl and replace the characters with '*'?

I have a Perl script that requires the user to enter a password. How can I echo only '*' in place of the character that the user types, as they type it?
I'm using Windows XP/Vista.
In the past I have used IO::Prompt for this.
use IO::Prompt;
my $password = prompt('Password:', -e => '*');
print "$password\n";
If you don't want use any packages... Only for UNIX
system('stty','-echo');
chop($password=<STDIN>);
system('stty','echo');
You can play with Term::ReadKey. Here is a very simple example, with some detection for backspace and delete key. I've tested it on Mac OS X 10.5 but according to the ReadKey manual it should work under Windows. The manual indicates that under Windows using non-blocking reads (ReadKey(-1)) will fail. That's why I'm using ReadKey(0) who's basically getc (more on getc in the libc manual).
#!/usr/bin/perl
use strict;
use warnings;
use Term::ReadKey;
my $key = 0;
my $password = "";
print "\nPlease input your password: ";
# Start reading the keys
ReadMode(4); #Disable the control keys
while(ord($key = ReadKey(0)) != 10)
# This will continue until the Enter key is pressed (decimal value of 10)
{
# For all value of ord($key) see http://www.asciitable.com/
if(ord($key) == 127 || ord($key) == 8) {
# DEL/Backspace was pressed
#1. Remove the last char from the password
chop($password);
#2 move the cursor back by one, print a blank character, move the cursor back by one
print "\b \b";
} elsif(ord($key) < 32) {
# Do nothing with these control characters
} else {
$password = $password.$key;
print "*(".ord($key).")";
}
}
ReadMode(0); #Reset the terminal once we are done
print "\n\nYour super secret password is: $password\n";
You should take a look at either Term::ReadKey or Win32::Console. You can use those modules to read the single key strokes and emit '*' or whathever.
Building on Pierr-Luc's program, just added some control on the backslashes. With this, you can't keep pressing backslash forever:
sub passwordDisplay() {
my $password = "";
# Start reading the keys
ReadMode(4); #Disable the control keys
my $count = 0;
while(ord($key = ReadKey(0)) != 10) {
# This will continue until the Enter key is pressed (decimal value of 10)
# For all value of ord($key) see http://www.asciitable.com/
if(ord($key) == 127 || ord($key) == 8) {
# DEL/Backspace was pressed
if ($count > 0) {
$count--;
#1. Remove the last char from the password
chop($password);
#2 move the cursor back by one, print a blank character, move the cursor back by one
print "\b \b";
}
}
elsif(ord($key) >= 32) {
$count++;
$password = $password.$key;
print "*";
}
}
ReadMode(0); #Reset the terminal once we are done
return $password;
}
using Pierr-Luc's program
# Start reading the keys
ReadMode(4); #Disable the control keys
while(ord($key = ReadKey(0)) != '13' )
# This will continue until the Enter key is pressed (decimal value of 10)
{
# For all value of ord($key) see http://www.asciitable.com/
if(ord($key) == 127 || ord($key) == 8 && (length($password) > 0)) {
# DEL/Backspace was pressed
#1. Remove the last char from the password
chop($password);
#2 move the cursor back by one, print a blank character, move the cursor back by one
print "\b \b";
} elsif(ord($key) > 32) {
$password = $password.$key;
print "*";
}
}
ReadMode(0); #Reset the terminal once we are done
Have you tried storing the string (so that your program can still read it) and find out its length then create a string of the same length, but only use '*'?