Questions about this topic? Sign up to ask in the talk tab.

Perl

From NetSec
Revision as of 11:22, 23 November 2011 by LashawnSeccombe (Talk | contribs) (Regular Expressions)

Jump to: navigation, search

Practical Extraction and Report Language is the oldest of the interpreted languages, python being its 3 years younger sibling. The perl interpreter is written in C, a compiled language.

Perl is flexible and can be used to write web applications, command line applications, or services.

Development Environment

To develop in perl you will need only a perl interpreter and a text editor. For those of you who find un highlighted perl, there are a variety of windows & linux text editors with syntax highlighting support.

Windows:

  • notepad++
  • cygwin's vim implementation

Linux:

  • vim
  • nano
  • emacs
  • geany
  • gedit

Linux & Unix

On most distributions, perl and cpan come bundled by default. In the case it is not, a simple apt-get, emerge, yum install, pacman, or any other package manager should install it quickly. You can determine if perl is installed by typing `which perl' at the bash command line. If a filename is returned, you're good to go.

Windows

You can do everything we're going over by installing cygwin with perl. CYGWIN is available at http://www.cygwin.com/install.html

 For compilation to .exe, we recommend "pp", you can install this by `typing cpan -i pp' from your cygwin shell.
c3el4.png There is also a perl written by activestate- searching for "activestate perl" in any search engine will find it

CPAN

CPAN is the module and package installer for perl. It can be accessed on most distributions simply by typing `cpan'. On windows, you can access it by typing `cpan' in your CYGWIN shell.

Notice: If `cpan' does not work, try `perl -e 'shell' -mCPAN'. If this does not work, your installation may be broken.

Your first program

Code

To run this code, you'll only need to put it in a text file. Save it as "hello.pl", and then you can execute the following to run it from either cygwin or bash:

  • chmod +x hello.pl
  • ./hello.pl

Alternatively you can simply type:

  • perl hello.pl

<syntaxhighlight lang="perl">#!/usr/bin/perl use strict; use warnings; print "Hello world!\n";</syntaxhighlight>

Analysis

The shebang declares the location of the code's interpreter. I.e. if you're writing bash, you'll need to put:

 #!/bin/bash

at the top of your file. In perl, it's typically:

 #!/usr/bin/perl

This should be the first line in any perl you write. You can also use:

 #!env perl

If you are unsure of the path and you have it in your environment variables.

Notice: If for some reason `#!env perl' and `#!/usr/bin/perl' do not work, running `which perl' from the bash command line will return the proper bath.

This is only required if you want to directly execute your script (i.e. ./script.pl). If you get permissions errors when attempting this, you can execute it via `perl script.pl' or running `chmod +x script.pl' before running `./script.pl'.

With perl in particular, its real easy for ugliness to occur. To counter this, the next lines are:

<syntaxhighlight lang="perl">use strict; use warnings;</syntaxhighlight>

Strict perl forces you to maintain some semblence of syntax. Without the strict usage, you can basically run amok with code, perl will not care.

The print "Hello world!\n" line simply prints "Hello world!" with a newline character on the end. On windows you may need to change "\n" to "\r\n", depending on which interpreter you've installed.

c3el4.png You can also reference the hex code for this via a \x character, "\x0a\x0d".

Variables & Data Types

In strict perl, variables must be declared using the "my" or "our" operators. "my" is used implicitly in non-shared memory, whereas "our" is used explicitly for shared memory to pass data between threads.

Scalars

Scalars in perl are prefixed with a $. A scalar may contain any string, integer, or floating point value. It may also contain a reference pointer. An example declaration:

<syntaxhighlight lang="perl">my $message = "Hello world!\n"; print $message;</syntaxhighlight>

Arrays

Arrays (or lists) have elements. Typically an array in perl can contain anything - each element can be something different. An array element may be a hash, hash reference, scalar, or another array.

Arrays are prefixed by the @ character:

<syntaxhighlight lang="perl">my @messages = ("Hello world!\n","I like perl!\n"); print $messages[0]; print $messages[1]; print "Size of messages array: ". $#messages . "\n"; </syntaxhighlight>

c3el4.png You can access and modify array elements directly:

<syntaxhighlight lang="perl"> $messages[0] = "Hello world!\n"; </syntaxhighlight>

Helper Functions

join()

Join will compile an array into a scalar. Using the array example above, @messages, the following code will generate the string "Hello world!\n, I like perl!\n" as a scalar:

<syntaxhighlight lang="perl">my @messages = ("Hello world!\n","I like perl!\n"); my $joined_message = join(", ",@messages); print $joined_message;</syntaxhighlight>

split()

Split takes a scalar and converts it to an array using a delimiter. Using our string from earlier:

<syntaxhighlight lang="perl">my $joined_message = "Hello world!\n, I like perl!\n"; my @messages = split('/, /',$joined_message); print $messages[0]; print $messages[1]; print "Size of messages array: ". $#messages . "\n";</syntaxhighlight>

push()
c3el4.png The push() function is used to append an element or elements to the end of an array, similar to the push instruction in assembly and treats the array like a stack.
 
my @array;
push(@array,'element one');
push(@array,('element two','element three'));
 
The professor says
You can also add to the end of an array with:
$array[$#array] = "new element";
pop()
c3el4.png The pop() function is similar to the pop instruction in assembly and treats the array like a stack.
my @array;
$array[$#array] = 1;
$popped = pop(@array);
 
The professor says
The same affect can be acheived with:
$popped = $array[$#array--];
RPU0j.png Executing pop() on an array will delete the highest order array element.
unshift()
c3el4.png The unshift() function is like the inverse of the push() function and treats the array like a stack. In stead of pushing to the top of the stack, this function operates against the bottom of the stack.
my @array;
$array[0] = 1;
unshift(@array,0); # $array[0] now contains "0" and $array[1] now contains [1].
 
shift()
c3el4.png The shift() function is like the inverse of the pop() function and treats the array like a stack. In stead of popping from the top of the stack, this function operates against the bottom of the stack.
my @array = (0,1);
my $first_element = shift(@array); # $array[0] now contains one, and @array only contains one element
 
RPU0j.png Executing shift() on an array will delete the lowest order array element, changing the index of all elements.

Hashes

A hash is very similar to a struct in C.

Introduction

Hashes are prefixed by the % character. Hash element values are prefixed by $. A hash element may contain another hash, an array, or a scalar.

c3el4.png You can directly modify the key inside of a hash:

<syntaxhighlight lang="perl">$hash{'key'} = 'value';</syntaxhighlight>

c3el4.png You can also create a key => value pair on declaration:

<syntaxhighlight lang="perl">my %hash = ('key' => 'value', 'key2' => 'value2');</syntaxhighlight>

  • Example:

<syntaxhighlight lang="perl">my %user; $user{'username'} = "hatter"; $user{'network'} = "irc.blackhatacademy.org"; print "The user " . $user{'username'} . " is connected to " . $user{'network'} . "\n"; </syntaxhighlight>

Helper Functions

each()
Notice: This uses a while loop. While loops are covered later in this article.
c3el4.png "while my each" can be used to isolate $key => $value pairs from a hash as follows with our %user hash:

<syntaxhighlight lang="perl">while(my($key,$value) = each(%user)) { print "Key: $key, Value: $value\n"; };</syntaxhighlight>

keys
Notice: This uses a foreach() loop and casting. Foreach and casting are covered later in this article.
c3el4.png We can isolate $key=>$value pairs the same as above using keys in stead of each:

<syntaxhighlight lang="perl">foreach my $key (@{sort keys %user}) { print "Key: $key, Value: ". $user{$key} ."\n"; };</syntaxhighlight>

References

c3el4.png A reference is very similar to a pointer in C.

Hash References

c3el4.png A hash reference is a scalar created using the \ operator as follows:
 
my %user;
$user{'name'}    = "hatter";
$user{'network'} = "irc.blackhatacademy.org";
 
my $hashref = \%user;
 
Notice: Once you've created a hashref (hash reference) you must use pointers to access a key:
 
print $user->{'name'} . "\n";
print $user->{'network'} . "\n";
 

Callback References

Notice: This involves user-defined functions. User-defined functions are covered later in this article.

A callback reference is a scalar that points to a function. To create a callback reference:

my $callback = \&function_name;
 

To execute the callback function and pass it arguments:

$callback->($arg1, $arg2);

Casting

c3el4.png Casting is the process of transitioning from one data type to another.

This is typically done using curly brackets {} preceeded by a data type designator ($,%, or @).

  • To cast a hash reference back to a hash:
 
my %hash;
my $hashref = \%hash; #create the hash reference
 
my %casted  = %{$hashref}; #Cast back to a hash.
 
  • To cast a list of keys in a hash into an array:
 
my @casted = @{keys %hash};
 
  • To cast a scalar value to an integer:
 
my $integer = int($scalar);
 

Boolean Logic

Operators

Mathematical

  • =

The = operator assigns a value to a variable.

  • ==

The == operator is used to test if a variable is equal to a value or another variable.

  • !

The ! operator means "not". It applies to = and any variable. For example, "if (!$scalar)" is used to determine if the $scalar variable is null, zero, or undefined. When used before a = operator, this becomes "not equal to".

  • eq

Sometimes because variables may not be a string or integer, the eq operator is used to determine if the two are equal.

c3el4.png The following operators are used for greater than, less than, and greater than or equal to, less than or equal to, etc; similar to other languages:
  • >
  • gt
  • <
  • lt
  • >=
  • gte
  • <=
  • lte

Regular Expression

c3el4.png The ~ operator is used with regular expressions, which are covered later in this article.

The ~ operator can be used in a variety of ways:

  • =~
  • !~

Statements

if

c3el4.png An if statement may have 3 types of clauses: if,elsif, and else.

For the below example, assume that the $age scalar is passed as a command line argument:

 
if (int($age) == $age) {  #Making sure it's an integer.
    if ($age < 18) {      #If the age is less than 18:
        print "You must be at least 18 to view this.\n";
    } elsif ($age < 21) { # If the age is more than 18, but less than 21:
        print "Because you are under 21, some features may be restricted.\n";
    } else {              # If none of the conditions have been met:
        display_content();
    }
}
 

unless

c3el4.png An unless statement may only have the unless clause and an else clause.
unless ($age >= 21) {
    print "All content is restricted for users under the age of 21.\n";
} else {
    print "Welcome to our sample age gate!\n";
    display_content();
}
 

AND an OR

c3el4.png And an or are used to apply multiple conditions to a boolean statement.
  • && is the way perl represents "and"
  • || is the way perl represents "or"

Example:

 
  if ($age < 21 && $age >= 18) {
      print "Some content will be restricted because you are not older than 21.\n";
  }
 

switch

c3el4.png To use perl's switch() routine you must have use Switch; before your switch() statement.

A switch statement allows a programmer to avoid long chains of "elsif" statements. It condenses the amount of required lines of code. Perl's switch statement is very similar to the switch() statement in C and C++, though the syntax is a little different.

c3el4.png A perl switch() statement may contain case and else clauses.
Perl switch cases can also be used to determine if a value is in a list, an array element, hash key, or matches a regular expression or string.
Notice: In this example, suppose $option was a numeric value for an integer based menu with 3 options.
 
use Switch;
switch(int($option)) {
    case 1 {  # Essentially the same as if ($option == 1)
        print "You picked option 1!\n";
    }
    case 2 { # Essentially the same as elsif ($option == 2)
        print "You picked option 2!\n";
    }
    case 3 { # Essentially the same as elsif ($option == 3)
        print "You picked option 3!\n";
    }
    else { 
        print "invalid menu option!\n";
    }
}
 

For more information, see perldoc switch, or : http://perldoc.perl.org/Switch.html

Golfing

c3el4.png The term golfing applies to condensing a boolean statement into one line.
The professor says
Golfing is typically used when you only need to execute one line of code for a boolean statement.
 
print "You are not 18 or older!\n" unless ($age >= 18);
 
  • Is essentially the same as:
 
print "You are not 18 or older!\n" if ($age < 18);
 
  • Is essentially the same as this un-golfed statement:
 
unless ($age >= 18) {
    print "You are not 18 or older!\n";
}
 

Helper Natives

c3el4.png These helper natives are boolean statements that assist with the determination of the existence of or the defining of a variable.

exists

The exists native applies specifically to hashes and hash references.

print "This user has an age.\n" if exists $user->{'age'};
 

defined

The defined native determines if a scalar value is defined:

 
print "We received a response from the server.\n" if defined $response;
 

undef

The undef native determines if a scalar value is un-defined:

 
print "We received a response from the server.\n" unless undef $response;
 

Bitwise Manipulations

c3el4.png Perl's bitwise manipulations cover the syntax for performing bitwise math on variables.

AND

  • & - The AND operator.
 
my $num = 10;
$num = $num & 25;
print $num . "\n";
 

NOT

  • ~ - The NOT operator
 
my $num = 10;
$num = ~$num;
print $num . "\n";
 

OR

  • | - The OR operator
 
my $num = 10;
$num = $num | 25;
print $num . "\n";
 

XOR

  • ^ - The XOR (exclusive or) operator
 
my $num = 10;
$num = $num ^ 25;
print $num . "\n";
 

Bit Shifting

  • << - The shift left operator
  • >> - The shift right operator

<syntaxhighlight lang="perl">my $num = 10; $num = $num << 2; #Shift left two bits $num = $num >> 2; #Shift right two bits print $num . "\n"; </syntaxhighlight>

Bit Rotation

c3el4.png Perl bit rotation requires the Bit::ShiftReg package from CPAN. More information available there.

Loops

c3el4.png A loop is a block of code that continues to execute until a condition is met.

While

  • A while loop executes while a condition is true.
my $switch;
my $counter;
while (undef $switch) {
    print $counter;
    $counter++;
    $switch = 1 if ($counter > 100);
}
 The above code will execute until $switch is defined.
The professor says
It is possible to create an infinite loop using while (1) { ... }.

Until

  • An until loop executes until a condition is true.
my $switch;
my $counter;
until (defined $switch) {
    print $counter;
    $counter++;
    $switch = 1 if ($counter > 100);
}
 The above code will execute until $switch is defined.

For

  • A for loop has a built-in counter and stops at a pre-defined number.
my @messages = ("Hello world!\n","I like perl!\n");
for (my $counter = 0; $counter < $#array; ++$counter) {
   print $messages[$counter];
}
 The above code will iterate through every element in an array.
The professor says
It is possible to create an infinite loop using for (;;) {...}.

Foreach

  • A foreach loop is built specifically for array handling and iterates through all of the elements in an array.
my @messages = ("Hello world!\n","I like perl!\n");
foreach my $message (@messages) {
   print $message;
}
 The above code will iterate through every element in an array.

User Input

Command Line Arguments

Command line arguments are passed at execution time; e.g.

 perl script.pl -a arg1 -b arg2 ...

Getopt::Std

Notice: This requires Getopt::Std. The perldoc is here.
Code
 
use strict;
use warnings;
use Getopt::Std;
 
my %opts;
getopts('m:b',\%opts);
 
print $opts{m} . "\n";
print "The boolean -b option was set!\n" if defined $opts{b};
print "The boolean -b option was not set!\n" if undef $opts{b};
 
Analysis
c3el4.png The getopts() function takes a string of flags to parse as well as a hash reference.

You can execute the script as follows:

 perl script.pl -m "hello" -b
 perl script.pl -m "hello"

In the above example, we see the line:

 getopts('m:b',\%opts);

The 'm:b', the first argument to the function, designates what command line arguments to parse. The colon after the 'm' specifies that it takes an additional parameter, in this case, the message to say. The -b does not have a colon; we are using it to demonstrate a flag that does not require an additional parameter.

The second argument is a hash reference to designate where the return data is stored; in this case, $opts{m} contains "hello" and opts{b} is either defined or undefined based on whether or not it was present in the flags when the script was executed.

Getopt::Long

Notice: This requires Getopt::Long. The perldoc is here.
Code
 
use strict;
use warnings;
use Getopt::Long;
 
my $message, $boolean;
GetOptions('message=s' => \$message, 'boolean' => \$boolean);
 
print $message . "\n";
print "The boolean -b option was set!\n" if defined $boolean;
print "The boolean -b option was not set!\n" if undef $boolean;
 
Analysis
c3el4.png The GetOptions() function receives message formats and references for variable assignment.

You can execute the script as follows:

 perl script.pl --message "hello" --boolean
 perl script.pl --message "hello"

In the above example, we see the line:

 GetOptions('message=s' => \$message, 'boolean' => \$boolean);

You can see from the execution pattern above that the GetOptions() function provides an interface for the "double-dash" style command line arguments. The GetOptions() function receives a hash. The =s after message designates that the --message parameter receives a string data type. An =i will change it to integer. Simple no = will set the flag to a boolean; similar to an argument without a colon in Getopt::Std. Notice each variable is passed as a reference.

STDIN (Standard Input)

c3el4.png Reading from standard input in perl is very simple.
 
print "Enter your name :";
my $name = <>;
print "Your name is $name\n";
 
The professor says
The <> operator, in this case, is used to read data from the command line. It will return after a newline character is received (when the user presses enter).

Regular Expressions

Types of Regex

  • Matching (=~ //)
  • Exclusive Matching (m//)
  • Find & Replace (s//)

Grouping

Patterns

  • \d - digit (anything from 0 to 9)
  • \D - anything except a digit
  • \w - word (anything from a to z)
  • \W - anything except a word
  • . - any character
  • * - matches zero or more of the preceding character
  • + - matches one or more of the preceding character

Modifiers

  • i - Case insensitivity
  • g - greedy/global matching
  • U - "Ungreedy"

Lists, Ranges, and Length Designation

Loops and Statements

User-Defined Functions

User-Defined Packages & Objects

Throughput

c3el4.png Throughput is a library that provides abstraction for sockets, threading, logging, and dynamic module loading.

Download

Usage

LESSON

Perl Regex - Hatter

1.0 - Introduction The shebang declares the location of the code's interpreter. I.e. if you're writing bash, you'll need to put:

<syntaxhighlight lang="bash">#!/bin/bash</syntaxhighlight>

at the top of your file. In perl, it's typically:

<syntaxhighlight lang="bash">#!/usr/bin/perl</syntaxhighlight>

This should be the first line in any perl you write. You can also use:

<syntaxhighlight lang="bash">#!env perl</syntaxhighlight>

If you are unsure of the path and you have it in your environment variables. With perl in particular, its real easy to get it ugly as hell.

To counter this, your next two lines will be:

<syntaxhighlight lang="perl"> use strict; use warnings; </syntaxhighlight>

Strict perl forces you to maintain some semblence of syntax. Without the strict usage, you can basically run amok with code, perl does not care.

Our script so far should look like:

<syntaxhighlight lang="perl">

  1. !/usr/bin/perl

use strict; use warnings; </syntaxhighlight>

Now, thanks to mepholic, I've removed sensitive data from this log and made it available for everyone:

 http://blackhatacademy.org/sample_asterisk.log

You will need to save this file.

WINDOWS USERS:

TODAY we'll be writing a regex to read asterisk logs to determine ip's with authentication failures.

Our perl script is going to do the following :

1) Analyze an asterisk log 2) Determine IP's with auth failures 3) Determine number of auth failures per IP 4) Block IP's going over a configurable threshhold

To participate in this lesson, please download and install perl and a text editor of your choice.

You've got a few different data types in perl and its different than other languages. You have scalars (ints or strings) prefixed with $ You have arrays/lists prefixed with @ You have hashes (similar to a struct/associative array) prefixed with % You have references prefixed with a \

You can declare a variable by saying:

<syntaxhighlight lang="perl"> my [$%@]varname; </syntaxhighlight>

So if its a scalar:

<syntaxhighlight lang="perl"> my $scalar; </syntaxhighlight>

So :

<syntaxhighlight lang="perl"> my $scalar = 0; my $scalar = "foo"; </syntaxhighlight>

Either is acceptable or just:

<syntaxhighlight lang="perl"> my $scalar; </syntaxhighlight>

Now, for our example, we'll want to analyze each line. So let's look at these failed lines:

 [Aug 27 07:34:43] NOTICE[2762] chan_sip.c: Registration from '"1561"<sip:[email protected]>' failed for '113.105.152.180:40586' - No matching peer found

In this particular instance, we know the ip comes right before the last : in the string. So to match the ip itself and not the whole line, We'd do something like this:

 /\x27([\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}):[^:]+$/

Where \x27 is a single quote. Obviously, this won't work for failed auths because it will match shit that isn't a failed auth. It'll also match successes or any line with an ip like that.

Here comes an in-depth explanation of that line:

Single quote, any digit between one and 3 characters in length, a dot, so on and so forth (match an IP), until the last : in the string, and it has to be right before the last : in the string. The [^:]+ at the end makes it so if a : occurs after that, it will no longer match as [^:]+ matches everything until the end of the string.

Now we've got to make it match failures too, the only real important data we care about is the ip, the count of failed auths and whether or not they're already in iptables for block because if they are we don't want to add another rule.

It means we've already blocked'em and these were previously analyzed logs

We'll use a hash to hold our ip's with failed auth and the value of each $hash{$ip} will contain the count of the failures. %hash is how it is declared and referred to but when you refer to a key of the hash, you want to put $ since its a scalar value you're accessing inside the hash.

You can directly modify the key inside of a hash by doing:

<syntaxhighlight lang="perl"> $hash{'key'} = 'value'; </syntaxhighlight>

Also, you can create an key=>value pair by doing:

<syntaxhighlight lang="perl"> my %hash = ( 'key' => 'value', 'key2' => 'value2' ); </syntaxhighlight>

You can copy the hash tree to another hash by doing:

<syntaxhighlight lang="perl"> my %hash2 = %hash; </syntaxhighlight>

If you want to print out a tree of the hashes, you can use:

<syntaxhighlight lang="perl"> while(my($key,$value) = each(%hash)) { print "Key: $key, Value: $value\n"; }; </syntaxhighlight>

Resulting Log:

 phobos public_html # perl test.pl
 113.105.152.180:10001
 220.134.238.64:2194
 67.205.85.58:7789
 80.254.76.242:4

So, http://blackhatacademy.org/test.pl.txt, will spit out your ip's and number of failures. This data is then used to blackhole IP's (preventing them from affecting the server)

That'll add a blackholed IP route if

1) They are over $threshhold failures (25) 2) They are not already blackholed