#!/usr/bin/perl -w 
# Poison Null Byte Exercise
# This version of the pirateinfo CGI test lab is designed to simulate
# a case where a "poison null byte" attack can be used. This doesn't
# come up easily, but this does illustrate an application for it.
# Basically, here we are assuming that the user can access many
# legitimate files in the the directory, but there is one file, called
# "restricted", which the user must not see at all costs. To prevent
# this, the naive programmer might implement a scheme like this
# program has whereby the name is explicitly checked against the
# banned file. If there is a match, it stops. Sounds good, but it
# turns out that this:
# http://server/~user/cgi-bin/pirateinfo?pw=pcof8&f=restricted%00IGNORED
# will cause perl to not abort since it thinks the filename is not the
# restricted one. When opening, however, Perl uses C libraries that
# treat the %00 as an end of string marker. The file opens right up.
# 
# Another interesting thing to try with this program is:
# http://server/~user/cgi-bin/pirateinfo?pw=pcof8&f=../pirates/restricted
# In other words, just go up and right back down into the directory of
# the forbidden file.

use strict;
use CGI qw(:standard);
use CGI::Pretty;

print header() . start_html( { 'title'=>'An Ominous Perl CGI Disaster',
                'BGCOLOR'=>'#000000', 'text'=>'#FFFFFF', 'link'=>'#0000FF' } );
print h1('Pirates... Not So Fun') . img({src=>'../pirates/pirate.png'});

# User input. ---------
my $menu= { 'bartroberts.txt'=>'Bart Roberts', 
            'benhornigold.txt'=>'Ben Hornigold', 
            'edwardteach.txt'=>'Edward Teach', 
            'henrymorgan.txt'=>'Henry Morgan', 
            'williamkidd.txt'=>'William Kidd'};
$menu= p( scrolling_list( { 'values'=>[keys %$menu], 'labels'=>$menu, 'name'=>'f', } ) );

my $auth= p( 'Enter thy password' . textfield({'name'=>'pw', 'size'=>8 }) );

print startform("POST", "./pirateinfo3.pl") .
      $auth . $menu. submit() . endform();

# Rough Authentication ---------
&stop unless param(); # Stop if there is no user input.
# Stop if the password is bad.
print h3('Avast Ye!') and &stop unless param('pw') eq "pcof8";

print "Sorry, top secret!!" and &stop if param('f') eq 'restricted';
my $file= "../pirates/" . param('f'); 

           print hr(); #---------------------------
print h3($file); # Output what the userdata is at this point.

open ( FGOOD, "<", $file );
print b($_) . br() while (<FGOOD>);
close FGOOD;
           print hr(); #---------------------------

# Interesting URL character codes to play with to try tricking Perl.
# %20=space, %26=ampersand, %3F=question, %7B=open curly, %7D=close curly,
# %7C=vertical bar, %5C=backslash, %2F=slash, %5E=caret, %7E=tilde,
# %5B=open square, %5D=close square, %60=backtick, %25=percent, %2B=plus
# %21=exclaim, %24=dollar, %28=open paren, %29=close paren, %2A=star, %2D=dash,
# %3C=less than, %3E=greater than, %3A=colon, %3B=semicolon

