File Coverage

blib/lib/App/Waf.pm
Criterion Covered Total %
statement 11 80 13.7
branch 0 34 0.0
condition n/a
subroutine 4 8 50.0
pod 2 4 50.0
total 17 126 13.4


line stmt bran cond sub pod time code
1             package App::Waf;
2              
3 1     1   16775 use 5.006;
  1         3  
4 1     1   6 use strict;
  1         1  
  1         18  
5 1     1   3 use warnings;
  1         4  
  1         79  
6             require Exporter;
7              
8             =encoding utf8
9             =head1 NAME
10              
11             App::Waf - A sample Web Application Firewall,
12             analysis the web logs for illegal attempt in real time。
13             summary the source IP and other tpyes infomations ,using
14             this infomations for ban whith iptables.
15              
16             通过解析web访问日志,实时统计非法访问,结合防火期等进行
17             主动式防御。
18              
19             =head1 VERSION
20              
21             Version 0.06
22              
23             =cut
24              
25             our $VERSION = '0.06';
26              
27             our @ISA = qw(Exporter);
28             our @EXPORT = qw(tail initCount);
29              
30             =head1 SYNOPSIS
31             =head2 实例
32              
33             use App::Waf;
34             my $filename = "example.acess";#日志文件
35             my $numlines = 50000; #要处理的行数,从后读。
36             my $line=tail($filename,$$numlines);
37             ($log,$zcount,$zip,$zrequrl,$zstatus,$siteurl)=initCount($line);
38             print "==============Attack Summary ==================\n";
39             print "\nThe total attack count: $zcount \n";
40             print "\nThe count from source IP: \n\n";
41             print "$_\=> $zip->{$_} \n" for(sort keys %{$zip});
42             print "The count From request Url: \n\n";
43             print "$_\=> $zrequrl->{$_} \n" for(sort keys %{$zrequrl});
44             print "\n\nThe count From Http Status: \n\n";
45             print "$_\=> $zstatus->{$_} \n" for(sort keys %{$zstatus});
46             print "\n\nThe count From Site Url: \n\n";
47             print "$_\=> $siteurl->{$_} \n" for(sort keys %{$siteurl});
48            
49             =head2 结合nginx 和 iptables 进行实时banip的实例(example/banip.pl)
50              
51             加入crontab 每5分钟执行一次。
52              
53             echo "*/5 * * * * perl $dir/banip.pl >> bianip.logs 2>&1 " >> /var/spool/cron/root
54              
55             =head1 SUBROUTINES/METHODS
56              
57             =head2 tail()
58              
59             IN: $logfile,$count;
60              
61             OUT: return the the latest $count lines of the $logfile.
62              
63             =head2 initCount()
64              
65             IN: the content of need to cheack and count.
66              
67             OUT: all types count result.
68              
69             =cut
70              
71 1     1   515 use File::ReadBackwards;
  1         2447  
  1         923  
72              
73             my $DEBUG = 0;
74              
75             my @validurl = (
76             'rfd.php\?include_file',
77             '\.\./',
78             'select.+(from|limit)',
79             '(?:(union(.*?)select))',
80             'having|rongjitest',
81             'sleep\((\s*)(\d*)(\s*)\)',
82             'benchmark\((.*)\,(.*)\)',
83             'base64_decode\(',
84             '(?:from\W+information_schema\W)',
85             '(?:(?:current_)user|database|schema|connection_id)\s*\(',
86             '(?:etc\/\W*passwd)',
87             'into(\s+)+(?:dump|out)file\s*',
88             'group\s+by.+\(',
89             'xwork.MethodAccessor',
90             '(?:define|eval|file_get_contents|include|require|require_once|shell_exec|phpinfo|system|passthru|preg_\w+|execute|echo|print|print_r|var_dump|(fp)open|concat|alert|showmodaldialog)\(',
91             'xwork\.MethodAccessor',
92             '(gopher|doc|php|glob|file|phar|zlib|ftp|ldap|dict|ogg|data)\:\/',
93             'java\.lang',
94             '\$_(GET|post|cookie|files|session|env|phplib|GLOBALS|SERVER)\[',
95             '\<(iframe|script|body|img|layer|div|meta|style|base|object|input)',
96             '(onmouseover|onerror|onload)\=',
97             '\.(bak|inc|old|mdb|sql|backup|java|class)$',
98             '\.(svn|htaccess|bash_history)',
99             '(vhost|bbs|host|wwwroot|www|site|root|hytop|flashfxp).*\.rar',
100             '(phpmyadmin|jmx-console|jmxinvokerservlet)',
101             '/xmlrpc.php',
102             '/(attachments|upimg|images|css|uploadfiles|html|uploads|templets|static|template|data|inc|forumdata|upload|includes|cache|avatar)/(\w+).(php|jsp|asp)',
103              
104             );
105              
106             sub tail {
107              
108 0     0 1   my ( $filename, $linenum ) = @_;
109 0 0         print "DEBUG :: tail() :: IN : $filename,$linenum \n" if $DEBUG;
110 0 0         my $bw = File::ReadBackwards->new($filename)
111             or die "can't read $filename $!";
112 0 0         $linenum=1000 unless $linenum;
113 0           my $count = 0;
114 0           my @lines;
115              
116 0           while ( defined( my $line = $bw->readline ) ) {
117 0           push @lines, $line;
118 0           $count++;
119 0 0         if ( $count == $linenum ) { last }
  0            
120             }
121              
122 0           @lines = reverse @lines;
123 0           return \@lines;
124             }
125              
126             sub initCount {
127              
128 0     0 1   my $line = shift;
129 0           my @re = @validurl;
130 0           my $kcount = shift;
131 0           my ( $zcount, $zip, $zrequrl, $zstatus, $siteurl );
132 0           my $rawlog;
133              
134 0           for (@re) {
135 0           my $result = scarlog1( $_, $line );
136 0           my ( $mycount, $mylog ) = count($result);
137 0           my $key = $_;
138 0 0         $rawlog .= $mylog->{$key} if $mylog->{$key};
139              
140 0 0         $zcount += $mycount->{$key}->[0] if $mycount->{$key}->[0];
141 0 0         print
142             "DEBUG\:: initCount()\::OUT $key $mycount->{$key}->[0] $zcount \n"
143             if $DEBUG;
144             $zip->{$_} += $mycount->{$key}->[1]->{$_}
145 0           for ( keys %{ $mycount->{$key}->[1] } );
  0            
146             $zrequrl->{$_} += $mycount->{$key}->[2]->{$_}
147 0           for ( keys %{ $mycount->{$key}->[2] } );
  0            
148              
149 0 0         if ($DEBUG) {
150             print
151             "DEBUG\:: initCount()\::OUT $key $zrequrl->{$_} $_\=> $mycount->{$key}->[2]->{$_} \n"
152 0           for ( keys %{ $mycount->{$key}->[2] } );
  0            
153             }
154             $zstatus->{$_} += $mycount->{$key}->[3]->{$_}
155 0           for ( keys %{ $mycount->{$key}->[3] } );
  0            
156             $siteurl->{$_} += $mycount->{$key}->[4]->{$_}
157 0           for ( keys %{ $mycount->{$key}->[4] } );
  0            
158              
159             }
160 0 0         if ($DEBUG) {
161             print "DEBUG\:: initCount()\::OUT\::\$zrequrl $_\=>$zrequrl->{$_}\n"
162 0           for ( keys %{$zrequrl} );
  0            
163             }
164 0           return ( $rawlog, $zcount, $zip, $zrequrl, $zstatus, $siteurl );
165             }
166              
167             sub count {
168              
169 0     0 0   my $result = shift;
170              
171 0           my ( $mcount, %rawlog );
172 0           my $count = 0;
173 0           for ( keys %{$result} ) {
  0            
174 0           my ( %ip, %requrl, %status, %siteurl );
175              
176 0 0         next if $result->{$_} eq "";
177 0           $rawlog{$_} .= $result->{$_};
178 0           my @seclogs = split /\n/ms, $result->{$_};
179 0           for (@seclogs) {
180 0           $count++;
181 0 0         print "DEBUG\:: count()\::IN $_\n" if $DEBUG;
182 0           my ( $ip, $requrl, $status, $siteurl ) = (split)[ 0, 6, 8, 10 ];
183 0 0         $ip{$ip}++ if $ip;
184 0 0         $requrl{$requrl}++ if $requrl;
185 0 0         $status{$status}++ if $status;
186 0 0         $siteurl{$siteurl}++ if $siteurl;
187 0 0         print
188             "DEBUG\:: count()\::OUT $ip\=>$ip{$ip} $requrl\=>$requrl{$requrl} $status\=>$status{$status} $siteurl\=>$siteurl{$siteurl} \n"
189             if $DEBUG;
190             }
191              
192 0           $mcount->{$_} = [ $count, \%ip, \%requrl, \%status, \%siteurl ];
193              
194             }
195              
196 0           return $mcount, \%rawlog;
197             }
198              
199             sub scarlog1 {
200              
201 0     0 0   my ( $patter, $lines ) = @_;
202              
203 0           my %result;
204              
205 0           my $code = 'for(@{$lines}) {';
206 0           $code .= 'if (m#';
207 0           $code .= qr($patter);
208 0           $code .= '#) {$result{' . q($patter) . '}.=$_}}';
209              
210             #print $patter, ":\n";
211 0           eval $code;
212 0 0         die "Error ---: $@\n Code:\n$code\n" if ($@);
213              
214             #print "DEBUG scarlog1 :: OUT :: $_: $result{$_}\n" for(keys %result);
215 0           return \%result;
216             }
217              
218             =head1 AUTHOR
219              
220             ORANGE, C<< >>
221              
222             =head1 BUGS
223              
224             Please report any bugs or feature requests to C, or through
225             the web interface at L. I will be notified, and then you'll
226             automatically be notified of progress on your bug as I make changes.
227              
228              
229             =head1 SUPPORT
230              
231             You can find documentation for this module with the perldoc command.
232              
233             perldoc App::Waf
234              
235              
236             You can also look for information at:
237              
238             =over 4
239              
240             =item * RT: CPAN's request tracker (report bugs here)
241              
242             L
243              
244             =item * AnnoCPAN: Annotated CPAN documentation
245              
246             L
247              
248             =item * CPAN Ratings
249              
250             L
251              
252             =item * Search CPAN
253              
254             L
255              
256             =back
257              
258              
259             =head1 ACKNOWLEDGEMENTS
260              
261              
262             =head1 LICENSE AND COPYRIGHT
263              
264             Copyright 2016 ORANGE.
265              
266             This is free software; you can redistribute it and/or modify
267             it under the same terms as the Perl 5 programming language system itself.
268              
269             =cut
270              
271             1; # End of App::Waf