Perl: Гомографические атаки.Можно сравнить строки ascii / non-ascii, визуально похожие? - PullRequest
0 голосов
/ 08 февраля 2019

Я сталкивался с так называемой «атакой с использованием гомографических данных» и хочу отклонить домены, в которых декодированный punycode визуально кажется буквенно-цифровым.Например, www.xn--80ak6aa92e.com отобразит www.apple.com в браузере (Firefox).Домены визуально одинаковы, но набор символов отличается.Chrome уже пропатчил это и браузер отображает punycode

У меня есть пример ниже.

#!/usr/bin/perl

use strict;
use warnings;

use Net::IDN::Encode ':all';
use utf8;                             


my $testdomain = "www.xn--80ak6aa92e.com";
my $IDN = domain_to_unicode($testdomain);
my $visual_result_ascii = "www.apple.com";

print "S1: $IDN\n";
print "S2: $visual_result_ascii";
print "MATCH" if ($IDN eq $visual_result_ascii);

Визуально такие же, но они не будут совпадать.Можно ли сравнить строку юникода ($ IDN) с буквенно-цифровой строкой, визуально то же самое?

Ответы [ 2 ]

0 голосов
/ 09 февраля 2019

После некоторых исследований и благодаря вашим комментариям у меня сейчас есть вывод.Наиболее частые проблемы приходят из кириллицы.Этот набор содержит много визуально похожих на латинские символы, и вы можете создавать множество комбинаций.

Я определил некоторые мошеннические домены IDN, включая следующие имена:

"аррӏе" "сһаѕе" "сіѕсо"

Может быть, здесь, с этимШрифт, вы можете увидеть разницу, но в браузере нет абсолютно никакой визуальной разницы.

Консалтинг https://en.wikipedia.org/wiki/Cyrillic_script_in_Unicode Мне удалось создать таблицу из 12 визуально похожих символов.

Обновление: Я нашел еще 4 латиноподобных символа в кодировке кириллицы, всего 16 в настоящее время.

Можно создать много комбинаций между ними, чтобы создать IDN100% визуально похоже на легальные домены.

0430 a CYRILLIC SMALL LETTER A
0441 c CYRILLIC SMALL LETTER ES
0501 d CYRILLIC SMALL LETTER KOMI DE
0435 e CYRILLIC SMALL LETTER IE
04bb h CYRILLIC SMALL LETTER SHHA 
0456 i CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I 
0458 j CYRILLIC SMALL LETTER JE
043a k CYRILLIC SMALL LETTER KA
04cf l CYRILLIC SMALL LETTER PALOCHKA 
043e o CYRILLIC SMALL LETTER O
0440 p CYRILLIC SMALL LETTER ER
051b q CYRILLIC SMALL LETTER QA 
0455 s CYRILLIC SMALL LETTER DZE
051d w CYRILLIC SMALL LETTER WE 
0445 x CYRILLIC SMALL LETTER HA
0443 y CYRILLIC SMALL LETTER U

Проблема возникает с доменом второго уровня.Расширения также могут быть IDN, но они проверены, не могут быть подделаны и не являются предметом этой проблемы.Регистратор домена проверит, все ли буквы принадлежат одному и тому же набору.IDN не будет принят, если у вас есть сочетание латинских, нелатинских символов.Так что дополнительная проверка бессмысленна.

Моя идея проста.Мы разделяем домен и декодируем только часть SLD, затем сопоставляем визуально похожий список кириллицы.Если все буквы визуально похожи на латиницу, то результат почти наверняка афера.

#!/usr/bin/perl

use strict;
use warnings;

use utf8;
use open ':std', ':encoding(UTF-8)';
use Net::IDN::Encode ':all';
use Array::Utils qw(:all);

my @latinlike_cyrillics = qw (0430 0441 0501 0435 04bb 0456 0458 043a 04cf 043e 0440 051b 0455 051d 0445 0443);

# maybe you can find better examples
my $domain1 = "www.xn--80ak6aa92e.com";
my $domain2 = "www.xn--d1acpjx3f.xn--p1ai";

test_domain ($domain1);
test_domain ($domain2);

sub test_domain {
    my $testdomain = shift;
    my ($tLD, $sLD, $topLD) = split(/\./, $testdomain);
    my $IDN = domain_to_unicode($sLD);

    my @decoded; push (@decoded,sprintf("%04x", ord)) for ( split("", $IDN) );

    my @checker = array_minus( @decoded, @latinlike_cyrillics );
    if (@checker){print "$testdomain [$IDN] seems to be ok\n"}
    else {print "$testdomain [$IDN] is possibly scam\n"}
}
0 голосов
/ 08 февраля 2019

Ваш пример, преобразованный с помощью Punycode преобразователя , приводит к этой строке UTF-8:

www.аррӏе.com
$ perl -e 'printf("%02x ", ord) for split("", "www.аррӏе.com"); print "\n"'
77 77 77 2e d0 b0 d1 80 d1 80 d3 8f d0 b5 2e 63 6f 6d

Как Unicode:

$ perl -Mutf8 -e 'printf("%04x ", ord) for split("", "www.аррӏе.com"); print "\n"'
0077 0077 0077 002e 0430 0440 0440 04cf 0435 002e 0063 006f 006d

Использование @входные данные ikegamis:

$ perl -Mutf8 -MEncode -e 'print encode("UTF-8", $_) for ("www.аррӏе.com" =~ /\p{Cyrillic}/g); print "\n"'
аррӏе
$ perl -Mutf8 -MEncode -e 'print encode("UTF-8", $_) for ("www.аррӏе.com" =~ /\P{Cyrillic}/g); print "\n"'
www..com

Оригинальная идея

Я не уверен, существует ли код для этого, но моей первой идеей было бы создать карту \N{xxxx} -> "визуальный эквивалент кода ASCII / UTF-8 ".Затем можно применить карту к строке Unicode, чтобы «преобразовать» ее в код ASCII / UTF-8 и сравнить полученную строку со списком доменов.

Пример кода (я пропускаю материал по декодированию IDNи использовать результат UTF-8 непосредственно в данных испытаний).Возможно, это еще можно улучшить, но, по крайней мере, это показывает идею.

#!/usr/bin/perl
use strict;
use warnings;

use utf8;
use Encode;

# Unicode (in HEX) -> visually equal ASCII/ISO-8859-1/... character
my %unicode_to_equivalent = (
   '0430' => 'a',
   '0435' => 'e',
   '04CF' => 'l',
   '0440' => 'p',
);

while (<DATA>) {
    chomp;

    # assuming that this returns a valid Perl UTF-8 string
    #my $IDN = domain_to_unicode($_);
    my($IDN, $compare) = split(' ', $_) ; # already decoded in test data

    my $visually_decoded =
        join('',              # merge result
             map {            # map, if mapping exists
                 $unicode_to_equivalent{sprintf("%04X", ord($_))} // $_
             }
             split ('', $IDN) # split to characters
        );

    print "Testing: ", encode('UTF-8', $IDN), " -> $compare ";
    print "Visual match!"
        if ($visually_decoded eq $compare);
    print "\n";
}

exit 0;

__DATA__
www.аррӏе.com www.apple.com

Тестовый прогон (зависит от того, сохранят ли при копировании и вставке из ответа исходные строки UTF-8)

$ perl dummy.pl
Testing: www.аррӏе.com -> www.apple.com Visual match!

Подсчет количества сценариев в строке

#!/usr/bin/perl
use strict;
use warnings;

use utf8;
use Encode;
use Unicode::UCD qw(charscript);

while (<DATA>) {
    chomp;

    # assuming that this returns a valid Perl UTF-8 string
    #my $IDN = domain_to_unicode($_);
    my($IDN) = $_;  # already decoded in test data

    # Unicod characters
    my @characters = split ('', $IDN);

    # See UTR #39: Unicode Security Mechanisms
    my %scripts =
        map { (charscript(ord), 1) } # Codepoint to script
        @characters;
    delete %scripts{Common};

    print 'Testing: ',
        encode('UTF-8', $IDN),
        ' (', join(' ', map { sprintf("%04X", ord) } @characters), ')',
        (keys %scripts == 1) ? ' not' : '', " suspicious\n";
}

exit 0;

__DATA__
www.аррӏе.com
www.apple.com
www.école.fr

Тестовый прогон (зависит от того, сохранились ли при копировании и вставке из ответа исходные строки UTF-8)

$ perl dummy.pl
Testing: www.аррӏе.com (0077 0077 0077 002E 0430 0440 0440 04CF 0435 002E 0063 006F 006D) suspicious
Testing: www.apple.com (0077 0077 0077 002E 0061 0070 0070 006C 0065 002E 0063 006F 006D) not suspicious
Testing: www.école.fr (0077 0077 0077 002E 00E9 0063 006F 006C 0065 002E 0066 0072) not suspicious
...