File Coverage

lib/HTML/Form/XSS.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package HTML::Form::XSS;
2              
3             =pod
4              
5             =head1 NAME
6              
7             HTML::Form::XSS - Test HTML forms for cross site scripting vulnerabilities.
8              
9             =head1 SYNOPSIS
10              
11             use HTML::Form::XSS;
12             use WWW::Mechanize;
13             my $mech = WWW::Mechanize->new();
14             my $checker = HTML::Form::XSS->new($mech, config => '../root/config.xml');
15             $mech->get("http://www.site.com/pagewithform.html");
16             my @forms = $mech->forms();
17             foreach my $form (@forms){
18             my @results = $checker->do_audit($form);
19             foreach my $result (@results){
20             if($result->vulnerable()){
21             my $example = $result->example();
22             print "Example of vulnerable URL: $example\n";
23             last;
24             }
25             }
26             }
27              
28             =head1 DESCRIPTION
29              
30             Provides a simple way to test HTML forms for cross site scripting (XSS)
31             vulnerabilities.
32              
33             Checks to perform are given in a XML config file with the results of each
34             test returned.
35              
36             =head1 METHODS
37              
38             =cut
39              
40 2     2   331037 use strict;
  2         4  
  2         67  
41 2     2   9 use warnings;
  2         4  
  2         58  
42 2     2   2171 use Data::Dumper;
  2         16031  
  2         189  
43 2     2   3130 use XML::Simple;
  0            
  0            
44             use Carp;
45             use HTML::Form::XSS::Result;
46             use base qw(HTML::XSSLint); #we use this module as a base
47             our $VERSION = 0.32;
48             ###################################
49              
50             =pod
51              
52             =head2 new()
53              
54             my $mech = WWW::Mechanize->new();
55             my $checker = HTML::Form::XSS->new($mech, config => '../root/config.xml');
56              
57             Creates a new HTML::Form::XSS object using two required parameters. Firstly a
58             or compatible object, secondly the path to the XML config file.
59              
60             Please see the example config.xml included in this distribution for details.
61              
62             =cut
63              
64             ###################################
65             sub new{
66             my($class, $mech, %params) = @_;
67             if($mech){ #we need this someday
68             if(defined($params{'config'})){ #how can we setup without this
69             my $self = {
70             '_mech' => $mech,
71             '_configFile' => $params{'config'}
72             };
73             bless $self, $class;
74             $self->_loadConfig();
75             return $self;
76             }
77             else{
78             confess("No Config file option given");
79             }
80             }
81             else{
82             confess("No WWW::Mechanize compatible object given");
83             }
84             return undef;
85             }
86             ###################################
87             sub make_params { #passing a check value here, so we can do many checks
88             my($self, $check, @inputs) = @_;
89             my %params;
90             foreach my $input (@inputs){
91             if(defined($input->name()) && length($input->name())){
92             my $value = $self->random_string();
93             $params{$input->name()} = $check . $value;
94             }
95             }
96             return \%params;
97             }
98             ###################################
99              
100             =pod
101              
102             =head2 do_audit()
103              
104             my @results = $checker->do_audit($form);
105              
106             Using the provided object the form is tested for all the
107             XSS attacks in the XML config file.
108              
109             An array of objects are returned, one for
110             each check.
111              
112             =cut
113              
114             #######################################################
115             sub do_audit { #we do many checks here not just one
116             my($self, $form) = @_;
117             my @results;
118             print "Checking...";
119             foreach my $check ($self->_getChecks()){
120             my $params = $self->make_params($check, $form->inputs);
121             my $request = $self->fillin_and_click($form, $params);
122             my $response = $self->request($request);
123             print " " . $response->code();
124             $response->is_success or confess("Can't fetch " . $form->action);
125             my @names = $self->compare($response->content, $params);
126             my $result = HTML::Form::XSS::Result->new( #using are modified result class
127             form => $form,
128             names => \@names,
129             check => $check
130             );
131             push(@results, $result);
132             }
133             print "\n";
134             return @results;
135             }
136             ###################################
137             sub compare{ #we need to make the patterns regex safe
138             my($self, $html, $params) = @_;
139             my @names;
140             foreach my $param (keys(%{$params})){
141             my $pattern = $self->_makeRegexpSafe($params->{$param});
142             if($html =~ m/$pattern/){
143             push(@names, $param);
144             }
145             }
146             return @names;
147             }
148             ###################################
149             #
150             #private methods
151             #
152             ###################################
153             sub _getChecks{
154             my $self = shift;
155             my $config = $self->_getConfig();
156             my $checks = $config->{'checks'}->{'check'};
157             return @{$checks};
158             }
159             ###################################
160             sub _getConfigFile{
161             my $self = shift;
162             return $self->{'_configFile'};
163             }
164             ###################################
165             sub _getConfig{
166             my $self = shift;
167             return $self->{'_config'};
168             }
169             ###################################
170             sub _loadConfig{
171             my $self = shift;
172             my $file = $self->_getConfigFile();
173             my $simple = XML::Simple->new();
174             my $ref = $simple->XMLin($file);
175             $self->{'_config'} = $ref;
176             return 1;
177             }
178             ###################################
179             sub _makeRegexpSafe{
180             my($self, $pattern) = @_;
181             $pattern =~ s/([\(\)])/\\$1/g; #add back slashes where required
182             return $pattern;
183             }
184             ###################################
185             sub _getMech{
186             my $self = shift;
187             return $self->{'_mech'};
188             }
189             ###################################
190              
191             =pod
192              
193             =head1 SEE ALSO
194              
195             L,
196             L,
197             L
198              
199             =head1 AUTHOR
200              
201             MacGyveR
202              
203             Development questions, bug reports, and patches are welcome to the above address
204              
205             =head1 COPYRIGHT
206              
207             Copyright (c) 2009 MacGyveR. All rights reserved.
208              
209             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
210              
211             =cut
212              
213             ####################################################
214             return 1;