[Trend Micro 2015] [Programming 200] Write-Up

Description

Calculate it.
nc ctfquest.trendmicro.co.jp 51740

Resolution

La règle est simple, il faut calculer ce que le serveur nous donne comme calculs.

Au début ça commence par de simples opérations, puis avec des nombres négatifs, puis des virgules pour séparer les centaines des milliers, puis des grands nombres, puis .. DES NOMBRES ROMAINS ?! puis … DES NOMBRES ECRITS DE TOUTES LETTRES EN ANGLAIS ?! puis … LE TOUT mélangé ?!!! C’est presque du sadisme là 😉

Alors on code :

<?php
// Pour convertir les nombres romains en INT
// From http://stackoverflow.com/questions/1077600/converting-words-to-numbers-in-php#answer-11219737
function roman($roman) {
$romans = array(
    'M' => 1000,
    'CM' => 900,
    'D' => 500,
    'CD' => 400,
    'C' => 100,
    'XC' => 90,
    'L' => 50,
    'XL' => 40,
    'X' => 10,
    'IX' => 9,
    'V' => 5,
    'IV' => 4,
    'I' => 1,
);

$result = 0;

foreach ($romans as $key => $value) {
    while (strpos($roman, $key) === 0) {
        $result += $value;
        $roman = substr($roman, strlen($key));
    }
}
return $result;
}

// Pour convertir les nombres anglais en INT
// From http://stackoverflow.com/questions/6265596/how-to-convert-a-roman-numeral-to-integer-in-php#answer-6266158
function wordsToNumber($data) {
    // Replace all number words with an equivalent numeric value
    $data = strtr(
        $data,
        array(
            'zero'      => '0',
            'a'         => '1',
            'one'       => '1',
            'two'       => '2',
            'three'     => '3',
            'four'      => '4',
            'five'      => '5',
            'six'       => '6',
            'seven'     => '7',
            'eight'     => '8',
            'nine'      => '9',
            'ten'       => '10',
            'eleven'    => '11',
            'twelve'    => '12',
            'thirteen'  => '13',
            'fourteen'  => '14',
            'fifteen'   => '15',
            'sixteen'   => '16',
            'seventeen' => '17',
            'eighteen'  => '18',
            'nineteen'  => '19',
            'twenty'    => '20',
            'thirty'    => '30',
            'forty'     => '40',
            'fourty'    => '40', // common misspelling
            'fifty'     => '50',
            'sixty'     => '60',
            'seventy'   => '70',
            'eighty'    => '80',
            'ninety'    => '90',
            'hundred'   => '100',
            'thousand'  => '1000',
            'million'   => '1000000',
            'billion'   => '1000000000',
            'and'       => '',
        )
    );

    // Coerce all tokens to numbers
    $parts = array_map(
        function ($val) {
            return floatval($val);
        },
        preg_split('/[\s-]+/', $data)
    );

    $stack = new SplStack; // Current work stack
    $sum   = 0; // Running total
    $last  = null;

    foreach ($parts as $part) {
        if (!$stack->isEmpty()) {
            // We're part way through a phrase
            if ($stack->top() > $part) {
                // Decreasing step, e.g. from hundreds to ones
                if ($last >= 1000) {
                    // If we drop from more than 1000 then we've finished the phrase
                    $sum += $stack->pop();
                    // This is the first element of a new phrase
                    $stack->push($part);
                } else {
                    // Drop down from less than 1000, just addition
                    // e.g. "seventy one" -> "70 1" -> "70 + 1"
                    $stack->push($stack->pop() + $part);
                }
            } else {
                // Increasing step, e.g ones to hundreds
                $stack->push($stack->pop() * $part);
            }
        } else {
            // This is the first element of a new phrase
            $stack->push($part);
        }

        // Store the last processed part
        $last = $part;
    }

    return $sum + $stack->pop();
}

 // Finalement notre code 😉
 $socket = fsockopen('ctfquest.trendmicro.co.jp', 51740);
 
 while (!feof($socket)) { // Tant qu'il y a des choses à lire
  $line = '';
  while (($char = fgetc($socket)) != '=') { // On récupère chaque caractère tant qu'on n'arrive pas au signe égal
   $line .= $char;
   echo $char;
  }
  fgetc($socket); // L'espace après le égal
  
  $calc = str_replace(',', '', rtrim($line, ' =')); // On vire la bêtise de séparation entre les centaines et les milliers
  $calc = preg_replace_callback('#([A-Z]+)#', function($regs){ return roman($regs[1]); }, $calc); // On remplace les nombres romains par leur valeur en int
  $calc = preg_replace_callback('#([a-z][a-z ]+)#', function($regs){ return wordsToNumber(trim($regs[1])).' '; }, $calc); // On remplace les nombre en toutes lettres par leur valeur en int
  
  $result = trim(shell_exec('echo '.escapeshellarg($calc).' | bc')); // On utilise bc pour calculer
  
  if ($result !== false) {
   echo "$line = '$result'\n";
  
   fputs($socket, $result."\r\n");
  }
 }

Le flag est : TMCTF{U D1D 17!}

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *