1. Uploading Viruses to Applications
1.1. Problem
A virus file is an excellent test case to see how your application
handles failures in the underlying operating system. This recipe gives
you a 100% harmless way to test how your application responds when a
virus file is uploaded.
1.2. Solution
See Example 1.
Example 1. Uploading a virus through Perl
#!/usr/bin/perl use LWP::UserAgent; use HTTP::Request::Common qw(POST);
$UA = LWP::UserAgent->new(); $page = "http://www.example.com/upload.aspx"; $EICAR = 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*';
$req = HTTP::Request::Common::POST( "$page", Content_Type => 'form-data', Content => [ myFile => [ undef, "Virus.jpg", "Content-Type" => "image/jpeg", "Content" => $EICAR, ], Submit => 'Upload File', ] );
$resp = $UA->request($req);
|
1. 3. Description
This is a handy technique any time you want to build some test data
dynamically and upload it, without having to store it to a file first.
Obviously, if your test data is large, storing it to a file is more
efficient than storing it in memory (otherwise, your Perl process might
become quite large in RAM). But, as you will see, there are some other
really good reasons why we have to perform the virus test this
way.
Virus files make excellent tests against Windows-based servers.
Any Windows-based server that is properly managed will have antivirus software installed. Such antivirus software
operates at the operating system level, scanning the content of files.
If you upload a file named flower.jpg
but its content is really a virus, the operating system will immediately
quarantine the file and make it unavailable to your application. This is
a fascinating problem, since everything works normally, and then
suddenly the file just isn’t there any more.
All industry-standard virus scanners recognize a special file and have agreed
to treat it as if it were a virus, even though it is totally harmless.
As you can imagine, this is a very handy file to have, because it
allows you to test the real response of your virus scanners without
having any danger whatsoever of doing damage to your systems with a
real virus. The EICAR test file can be found at http://www.eicar.org/anti_virus_test_file.htm, and it
is simple to create, even in a text editor. If you use this file in
your application tests, you can see how your operating system,
operations staff, and application software react when a virus is
introduced into the system. It is a little tricky to work with this
file, since—if you have antivirus software installed—it will always be
quarantined and disabled on your testing workstation. If you just want
to perform this test once, manually, the simplest way to use a
non-Windows system (e.g., FreeBSD, Linux, Mac OS) to upload the file.
Those systems will not typically react to any Windows viruses, much
less the test virus file. |
To be safe, we use the EICAR test virus file. However, because
that file is always treated like a real virus, we usually can’t store a
copy on our hard drive and then upload that file. That’s why Example 1 stores the string inside the
Perl script and dynamically uploads it. Your local computer will never
see the “virus,” but the server will receive a file that it will
immediately recognize as a virus.
You will probably want to have access to the server’s logs (e.g.,
web application server logs, operating system logs, etc.) in order to
determine what happened on your server. The worst possible result, of
course, is for nothing to happen at all. No reaction at all would
suggest that your application and its server are perfectly happy storing
virus files, and that’s a significant security failure all by
itself.
Since the XML file is such a
problematic file to work with in many operating systems, it is easier to
handle like we did the virus file. Embed the billion-laughs XML in your
Perl script’s source code and dynamically upload it.
2. Parsing for a Received Value with Perl
2.1. Problem
You send a request to the web application and you need to parse the
response to see what was returned. Rather than using something like
grep, you want to, for example, get
everything that is contained inside a set of HTML tags without worrying
about newlines. We assume you have a way of identifying the particular
HTML element you want.
2.2. Solution
You have to build an HTML-parsing function, fetch the page, and
then execute your parsing function on the HTML. See Example 2.
Example 2. Parsing a page with Perl
#!/usr/bin/perl use LWP::UserAgent; use HTTP::Request::Common qw(GET); use HTML::Parser;
$UA = LWP::UserAgent->new(); $req = HTTP::Request->new( GET => "http://www.example.com/" ); $resp = $UA->request($req);
sub viewstate_finder { my ( $self, $tag, $attr ) = @_;
if ( $attr->{name} eq "__VIEWSTATE" ) { $main::viewstate = $attr->{value}; } }
my $p = HTML::Parser->new( api_version => 3, start_h => [ \&viewstate_finder, "self,tagname,attr" ], report_tags => [qw(input)] ); $p->parse( $resp->content ); $p->eof;
print $main::viewstate . "\n" if $main::viewstate;
|
2.3. Discussion
This is the simplest possible program to fetch a page, parse the
received content, and print some small amount of that content out. An
aspect of most ASP.NET web applications is that the state of the user’s
session is stored partially on the server and partly in a hidden form
field called __VIEWSTATE. This
variable, from an HTML point of view, is an input field (i.e., it
corresponds to an <INPUT> tag).
The subroutine viewstate_finder in Example 2 will receive the tag name and value
of every <INPUT> tag in the
entire web page. Very simply, it looks for the one named __VIEWSTATE and updates a global variable
($main::viewstate) to contain the
value if it’s found.
This callback technique gets cumbersome if you’re looking for the
values of many similar HTML elements. In our case, there are relatively
few <INPUT> tags in the HTML,
and only one of them is named __VIEWSTATE. If you were looking for the
content inside a <TD> tag, it
might be harder, since there are frequently many such tags in a single
HTML document.