#!/usr/bin/env perl use v5.10.1; use strict; use warnings; use DBI; use File::Basename; use Digest; use Digest::MD5 qw(md5); use Digest::SHA qw(sha1 sha224 sha256 sha384 sha512); use Mcrypt qw(:ALGORITHMS :MODES :FUNCS); sub encrypt { my ($algo, $key, $data, $mode) = @_; my $td = mcrypt_load( $algo, "", $mode, '' ); mcrypt_init($td, $key, ""); my $encrypted = mcrypt_encrypt($td, $data); mcrypt_end($td); return $encrypted; } sub my_crypt { my ($key, $content) = @_; my $kfirst = pack('H*', substr($key, 0, 64)); $content = encrypt(SERPENT, $kfirst, $content, ECB); if (length $key > 64) { my $ksec = pack('H*', substr($key, 64, 64)); $content = encrypt(SERPENT, $ksec, $content, ECB); } return unpack('H*', $content); } #Return number of good solutions my $exit = 0; my $root = dirname(__FILE__); chdir($root); # First, read PHP configuration to extract some settings my $profile; my $submission_dir; open my $conf, "<", "$root/onyx/config/root.xml"; for my $p (<$conf>) { if ($p =~ /<(?:option|var) name="(.*)">(.*)<\/(?:option|var)>/) { $profile = $2 if ($1 eq "profile"); $submission_dir = $2 if ($1 eq "submission_dir"); } } close $conf; my $end_time = 1999999999; if (-f "$root/shared/challenge_started") { open my $conf, "<", "$root/shared/challenge_started"; $end_time = <$conf>; close $conf; chomp($end_time); $end_time += 14400; } die("TIME expired!") if time() > $end_time; die("No DB profile found") if ! $profile; die("submission_dir is not a directory") if ! $submission_dir || ! -d $submission_dir; # Read db settings my %db_settings; open my $dbprof, "<", "$root/onyx/db/$profile.profile.php"; while (<$dbprof>) { if (/\$___profile\[['"](.+)['"]\] = ['"](.+)['"]/) { $db_settings{$1} = $2; } } close $dbprof; my $dbh; # List all files to treat opendir(my $dh, $submission_dir) || die "Can't opendir submission_dir: $!"; for my $f (readdir $dh) { if ($f =~ /^([0-9]+)-([0-9]+)-([a-zA-Z0-9_]+)$/) { my $good = -1; my $team = $1; my $theme = $2; my $exercice = $3; open my $fh, "<", "$submission_dir/$f"; my %solution; $solution{md5} = <$fh>; chomp( $solution{md5} ); $solution{sha1} = <$fh>; chomp( $solution{sha1} ); $solution{sha256} = <$fh>; chomp( $solution{sha256} ); $solution{sha384} = <$fh>; chomp( $solution{sha384} ); $solution{sha512} = <$fh>; chomp( $solution{sha512} ); $solution{whirlpool} = <$fh>; chomp( $solution{whirlpool} ); close $fh; # use Data::Dumper; # print STDERR Dumper(\%solution); $dbh = DBI->connect("DBI:mysql:database=$db_settings{db};host=$db_settings{host};port=3306", $db_settings{user}, $db_settings{pass}, {'RaiseError' => 1, 'PrintError' => 1}) or die $DBI::errstr if !$dbh; query($dbh, "INSERT INTO exercice_tries (id_exercice, id_team, time) VALUES ('$exercice', $team, CURRENT_TIMESTAMP);"); my $sth = query($dbh, "SELECT format, value FROM exercice_keys WHERE id_exercice = ".$dbh->quote($exercice)); # Check solutions while (my $row = get_row($sth)) { $good = 1 if ($good == -1); my $type = @$row[0]; my $sol = @$row[1]; my $filh; my $tmp_solution; if ($type eq "md5") { $filh = md5($f); } elsif ($type eq "sha1") { $filh = sha1($f); } elsif ($type eq "sha224") { $filh = sha224($f); } elsif ($type eq "sha256") { $filh = sha256($f); } elsif ($type eq "sha384") { $filh = sha384($f); } elsif ($type eq "sha512") { $filh = sha512($f); } elsif ($type eq "whirlpool") { my $hash = Digest->new( 'Whirlpool' ); $hash->add( $f ); $filh = $hash->digest; } else { warn "$type not implemented"; } $tmp_solution = my_crypt($sol, $filh) if ($filh); #say STDERR "check $type: $solution{$type} vs $tmp_solution"; if ($solution{$type} ne $tmp_solution) { $good = 0; last; } } # Register solve if ($good == -1) { say STDERR localtime().": Exercice $exercice doesn't exist ; given by team $team in theme $theme."; } elsif ($good == 1) { # Check if the exercice exists $sth = query($dbh, "SELECT `require` FROM exercices E WHERE E.id_theme = $theme AND E.id = ".$dbh->quote($exercice)); if ($sth->rows) { my $row = get_row($sth); # Check if the team has solved dependancies $sth = query($dbh, "SELECT S.id FROM solved S WHERE S.id_exercice = ".$dbh->quote(@$row[0])) if @$row[0]; if (! @$row[0] || $sth->rows) { # Check if the team has not already solved this exercice $sth = query($dbh, "SELECT S.id FROM solved S WHERE S.id_team = $team AND S.id_exercice = ".$dbh->quote($exercice)); if (! $sth->rows) { say "resetresetreset:TEAM$team,$theme:SYNCSYN:TEAM$team:SYNC:HOME:SYNC:all:SY"; say STDERR localtime().": Team $team solve exercice $exercice in $theme"; query($dbh, "INSERT INTO solved (id_team, id_exercice, time) VALUES ($team, ".$dbh->quote($exercice).", CURRENT_TIMESTAMP);"); $exit++; } else { warn localtime().": Team $team try to solve exercice $exercice in $theme but ALREADY solved it"; } } else { warn localtime().": Team $team try to solve exercice $exercice in $theme but has NOT SOLVED required exercice ".@$row[0]; } } else { warn localtime().": Team $team try to solve exercice $exercice in $theme but does not exist"; } } else { say "Creset:T$team,$theme:SYNC"; say STDERR localtime().": Team $team didn't give the correct answer for exercice $exercice."; } # Remove the file unlink("$submission_dir/$f"); } } closedir $dh; $dbh->disconnect() if $dbh; exit( $exit > 126 ? 126 : $exit ); sub query { my $sth = $_[0]->prepare($_[1]); $sth->execute(); die($_[0]->errstr) if (!$sth); return $sth; } sub get_row { return $_[0]->fetchrow_arrayref(); }