jimpudar has asked for the wisdom of the Perl Monks concerning the following question:

Hello fellow Monks,

I was reading perlsec and found the following section regarding Algorithmic Complexity Attacks.

It got me wondering what it would take to mount a DoS attack against a webserver which stored user submitted strings as hash keys.

Assuming the sysadmin has set PERL_HASH_SEED=0, is there an efficient way to find colliding keys?

I came up with the following brute force script, which has yielded me one collision after a couple hours of runtime.

#! /usr/bin/env perl use strict; use warnings; use autodie; use Getopt::Long; use Hash::Util qw(hash_value); my $NUM_COLLISIONS = 1; my $LENGTH = 16; my $REGEX; my $VERBOSE; GetOptions( 'num|n=i' => \$NUM_COLLISIONS, 'length|l=i' => \$LENGTH, 'regex|r=s' => \$REGEX, 'verbose|v' => \$VERBOSE, ) or die "Error in command line options\n"; my $STRING = $ARGV[0] or die "Please supply a string to collide with\n"; my $hash_value = hash_value($STRING); print STDOUT "Finding $NUM_COLLISIONS collisions for '$STRING': '$hash_value'\n +"; my @collisions; while ( @collisions < $NUM_COLLISIONS ) { my $random_string = rnd_str( int( rand($LENGTH) ) + 1, 'a' .. 'z', 'A' .. 'Z', 0 + .. 9 ); next if $random_string eq $STRING; if ($REGEX) { next unless $random_string =~ /$REGEX/; } print STDOUT "Trying '$random_string': " if $VERBOSE; my $test_hash_value = hash_value($random_string); print STDOUT $test_hash_value, "\n" if $VERBOSE; if ( $test_hash_value == $hash_value ) { push @collisions, $random_string; print STDERR "$random_string $test_hash_value\n"; } } sub rnd_str { join '', @_[ map { rand @_ } 1 .. shift ]; }

I was able to find that the keys 'x', 'K1h80PEnbon', 'xVBKjDhadr0L', and 'Bz4Avmv0X83G' all have the hash key '1039123353', but it seems that finding enough keys to mount a successful DoS attack would take a very long time without thousands of processors.

Can any of you suggest a more efficient method?

Best regards,

Jim

Replies are listed 'Best First'.
Re: Hash Collisions with PERL_HASH_SEED=0
by dave_the_m (Monsignor) on Apr 06, 2018 at 08:18 UTC
    Why would a sysadmin have set PERL_HASH_SEED=0?

    Anyway, rather than brute-forcing, a real attack would use the known hash seed and the known hash algorithm, and with those known factors it's fairly trivial to offline generate a set of short strings which all map to the same hash bucket slot (but not necessarily to the same hash value, which has more bits than the number of buckets).

    But no, I'm not going to explain how.

    Dave.

      When PERL_HASH_SEED=0 isn't used, each hash is given its own random seed at creation, and it switches to a new random seed when Perl detects a degenerate hash. So, those "known factors" can't be known without PERL_HASH_SEED=0.

      Hi, Dave,

      Thanks for the reply - that was very clear.

      I don't think any sysadmin would actually have PERL_HASH_SEED=0, I was just curious after reading that bit of info in perlsec.

      Looks like I'll be spending some time learning about how hash tables are implemented!

      Thanks again,

      Jim

A reply falls below the community's threshold of quality. You may see it by logging in.