#!/usr/bin/perl -wl

use strict;

use IO::Socket;
use LWP::UserAgent;

my($action,$ip,$id,$flag)=@ARGV;

if(!$action || ($action ne 'put' && $action ne 'get' && $action ne 'check')) {
  print "Bad action.\nUsage: $0 <action> <ip> <id> <flag>";
  exit(10);
}

unless($ip) {
  print "No IP defined";
  exit(10);
}

if(($action eq 'put' || $action eq 'get') && (!$flag || !$id)) {
  print "No flag or id defined";
  exit(10);
}

our @useragents=(
  'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.3) Gecko/20100413 Gentoo Firefox/3.6.3',
  'Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.7 Safari/533.2',
  'Opera/9.80 (X11; Linux x86_64; U; en) Presto/2.2.15 Version/10.10',
  'Mozilla/5.0 (compatible; Konqueror/4.4; Linux) KHTML/4.4.2 (like Gecko)',
  'Wget/1.12 (linux-gnu)',
  'curl/7.20.0 (x86_64-pc-linux-gnu) libcurl/7.19.7 GnuTLS/2.8.6 zlib/1.2.4',
  'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2'
);

our $ua = LWP::UserAgent->new;
$ua->agent($useragents[int rand(7)]);
if(!$ua) {
  print "User agent not created";
  exit(10);
}

our $url="http://$ip/cgi-bin/task/launch";

if($action eq 'put') {
  $url.="?action=set&arg=$flag&out=$id";

  my $req = HTTP::Request->new(GET => $url);
  my $res = $ua->request($req);

  if(!$res->is_success) {
    print $res->status_line;
    exit(3);
  }

  exit(1);
} elsif($action eq 'get') {
  $url.="?action=get&in=$id";

  my $req;
  my $res;

  $req = HTTP::Request->new(GET => "http://$ip/~histograph/");
  $res = $ua->request($req);
  if(!$res->is_success)	{
    print $res->status_line;
    exit(3);
  }
  my $htmlcontent=$res->content;
  if(!$htmlcontent=~/$id/) {
    print "List of flags is broken";
    exit(3);
  }


  $req = HTTP::Request->new(GET => $url);
  $res = $ua->request($req);

  if(!$res->is_success)	{
    print $res->status_line;
    exit(3);
  }

  if($res->content_length != 151078) {
    print "No such flag";
    exit(2);
  }

  my $content=$res->content;

  my $serviceflag=getflagfromcontent($content);

  if($serviceflag ne $flag) {
    print "Wrong flag";
    exit(2);
  }
  print "All OK";

  exit(1);
} elsif($action eq 'check') {
  exit(1);
}

print "Impossible error";
exit(10);

# Берем флаг из BMP
sub getflagfromcontent
{
  my $data=$_[0];
  my ($x,$y);

  my @encryptedflag;

  for(0..31) {
    $x=26+14*$_+7;
    
    for $y(12..278) {
      if(getpixelfrombmp($data,$x,$y)==36) {
	$y=278-$y;
	$encryptedflag[$_]=$y;
	last;
      }
    }
  }
  # получили зашифрованный флаг. расшифровываем
  my $flag;
  # сначала брутим смещение, в случайном массиве подстановок
  for my $offset(0..255) {
    my @randarray=(14,121,202,226,72,142,63,102,216,140,124,80,49,92,6,98,125,231,18,70,184,30,205,188,181,81,120,134,189,149,90,66,228,150,69,152,83,48,2,179,223,207,87,192,21,79,9,168,246,133,103,138,95,148,196,238,100,165,156,106,174,85,237,233,8,178,3,61,217,141,58,67,56,105,89,130,5,113,182,19,236,211,71,7,74,240,111,16,117,27,112,78,38,11,144,52,15,241,234,160,40,101,201,22,242,82,229,109,65,235,251,97,230,159,224,88,194,116,169,115,12,208,46,119,176,62,214,177,200,215,108,127,31,25,132,114,250,39,252,43,50,199,136,253,73,227,35,175,245,254,60,29,76,173,33,0,143,249,47,213,104,158,186,41,126,131,183,139,225,42,123,172,163,86,170,244,99,219,222,26,210,153,209,204,75,57,193,36,20,220,107,191,137,145,167,94,212,255,24,171,23,45,118,146,28,155,185,122,221,68,77,17,129,147,93,4,197,84,164,180,206,51,218,34,157,32,203,96,91,37,232,166,44,247,13,1,162,248,53,190,243,161,59,10,198,54,154,110,55,239,187,64,128,135,151,195);
    my @replacearray;

    # хитрая перетасовка
    for(0..255) {
      $replacearray[$randarray[($_+$offset)%256]]=$_;
    }
    #print join ',',@replacearray;
    my @decryptedflag;
    for(0..31) {
      $decryptedflag[$_]=$replacearray[$encryptedflag[$_]];
    }

    #считаем, каким должно быть смещение для флага
    my $realoffset=0;
    for(1..32) {
      $realoffset+=$_*$decryptedflag[$_-1];
    }
    $realoffset=$realoffset%256;
    next unless $realoffset==$offset;

    @decryptedflag=map(chr,@decryptedflag);
    $flag=join '',@decryptedflag;

    # ура, сошлося. на влякий случай еще раз проверим флаг на валидность
    next unless $flag=~/^\w{32}$/;
    return $flag;
  }
  return 'none'; # в файле была какая-то хреньсв 
}

sub getpixelfrombmp
{
  my ($bmp,$x,$y)=@_;
  my $offset=0x436+$x+(500*(300-$y));
  return ord(substr $bmp,$offset,1);
}
