my
$VERSION
= 1.1;
our
@ISA
=
qw(Mail::SpamAssassin::Plugin)
;
sub
dbg {
my
$msg
=
shift
; Mail::SpamAssassin::Plugin::dbg(
"Phishing: $msg"
,
@_
); }
sub
new {
my
(
$class
,
$mailsa
) =
@_
;
$class
=
ref
(
$class
) ||
$class
;
my
$self
=
$class
->SUPER::new(
$mailsa
);
bless
(
$self
,
$class
);
$self
->set_config(
$mailsa
->{conf});
$self
->register_eval_rule(
"check_phishing"
,
$Mail::SpamAssassin::Conf::TYPE_BODY_EVALS
);
return
$self
;
}
sub
set_config {
my
(
$self
,
$conf
) =
@_
;
my
@cmds
;
push
(
@cmds
, {
setting
=>
'phishing_openphish_feed'
,
is_admin
=> 1,
type
=>
$Mail::SpamAssassin::Conf::CONF_TYPE_STRING
,
}
);
push
(
@cmds
, {
setting
=>
'phishing_phishtank_feed'
,
is_admin
=> 1,
type
=>
$Mail::SpamAssassin::Conf::CONF_TYPE_STRING
,
}
);
push
(
@cmds
, {
setting
=>
'phishing_uri_noparam'
,
is_admin
=> 1,
default
=> 0,
type
=>
$Mail::SpamAssassin::Conf::CONF_TYPE_BOOL
,
}
);
$conf
->{parser}->register_commands(\
@cmds
);
}
sub
finish_parsing_end {
my
(
$self
,
$opts
) =
@_
;
$self
->_read_configfile(
$self
);
}
sub
_read_configfile {
my
(
$self
) =
@_
;
my
$conf
=
$self
->{main}->{registryboundaries}->{conf};
my
@phtank_ln
;
my
$stripped_cluri
;
local
*F
;
if
(
defined
(
$conf
->{phishing_openphish_feed}) && ( -f
$conf
->{phishing_openphish_feed} ) ) {
open
(F,
'<'
,
$conf
->{phishing_openphish_feed});
for
($!=0; <F>; $!=0) {
chomp
;
next
if
(/^\s*\
$stripped_cluri
=
$_
;
if
(
$conf
->{phishing_uri_noparam} eq 1 ) {
$stripped_cluri
=~ s/\?.*//;
}
my
$phishdomain
=
$self
->{main}->{registryboundaries}->uri_to_domain(
$_
);
if
(
defined
$phishdomain
) {
push
@{
$self
->{PHISHING}->{
$stripped_cluri
}->{phishdomain}},
$phishdomain
;
push
@{
$self
->{PHISHING}->{
$stripped_cluri
}->{phishinfo}->{
$phishdomain
}},
"OpenPhish"
;
}
}
defined
$_
|| $!==0 or
$!==EBADF ? dbg(
"PHISHING: error reading config file: $!"
)
:
die
"error reading config file: $!"
;
close
(F) or
die
"error closing config file: $!"
;
}
if
(
defined
(
$conf
->{phishing_phishtank_feed}) && (-f
$conf
->{phishing_phishtank_feed} ) ) {
open
(F,
'<'
,
$conf
->{phishing_phishtank_feed});
for
($!=0; <F>; $!=0) {
next
if
( $. eq 1);
chomp
;
next
if
(/^\s*\
@phtank_ln
=
split
(/,/,
$_
);
$phtank_ln
[1] =~ s/\"//g;
$stripped_cluri
=
$phtank_ln
[1];
if
(
$conf
->{phishing_uri_noparam} eq 1 ) {
$stripped_cluri
=~ s/\?.*//;
}
my
$phishdomain
=
$self
->{main}->{registryboundaries}->uri_to_domain(
$phtank_ln
[1]);
if
(
defined
$phishdomain
) {
push
@{
$self
->{PHISHING}->{
$stripped_cluri
}->{phishdomain}},
$phishdomain
;
push
@{
$self
->{PHISHING}->{
$stripped_cluri
}->{phishinfo}->{
$phishdomain
}},
"PhishTank"
;
}
}
defined
$_
|| $!==0 or
$!==EBADF ? dbg(
"PHISHING: error reading config file: $!"
)
:
die
"error reading config file: $!"
;
close
(F) or
die
"error closing config file: $!"
;
}
}
sub
check_phishing {
my
(
$self
,
$pms
) =
@_
;
my
$feedname
;
my
$domain
;
my
$stripped_cluri
;
my
$dcnt
;
my
$uris
=
$pms
->get_uri_detail_list();
my
$rulename
=
$pms
->get_current_eval_rule_name();
while
(
my
(
$uri
,
$info
) =
each
%{
$uris
}) {
next
if
(
$uri
=~ /^mailto:/i);
next
unless
(
$info
->{hosts});
if
((
$info
->{types}->{a}) || (
$info
->{types}->{parsed})) {
foreach
my
$cluri
(@{
$info
->{cleaned}}) {
$stripped_cluri
=
$cluri
;
if
(
$self
->{main}->{conf}->{phishing_uri_noparam} eq 1 ) {
$stripped_cluri
=~ s/\?.*//;
$dcnt
=
$stripped_cluri
=~
tr
/\///;
}
if
( (
$self
->{main}->{conf}->{phishing_uri_noparam} eq 1) && (
$dcnt
<= 3) ) {
next
;
}
if
(
exists
$self
->{PHISHING}->{
$stripped_cluri
} ) {
$domain
=
$self
->{main}->{registryboundaries}->uri_to_domain(
$cluri
);
$feedname
=
$self
->{PHISHING}->{
$stripped_cluri
}->{phishinfo}->{
$domain
}[0];
dbg(
"HIT! $domain [$stripped_cluri] found in $feedname feed"
);
$pms
->test_log(
"$feedname ($domain)"
,
$rulename
);
return
1;
}
}
}
}
return
0;
}
1;