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!}