Description
Calculate it.
nc ctfquest.trendmicro.co.jp 51740
Resolution
The rule is pretty simple. We just have to calculate what the server send us.
At the very beginning, the server sent us simple mathematics, then negative figures, and then again comma separated numbers (in order to separate thousands), and then big number, and… ROMAIN FIGURES!? Really?! After there was… FULLY WRITTEN NUMBERS?! and finally EVERYTHING mixed?!!! It nearly sadism here
Let’s code:
<php // romain to 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; } // english to 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(); } // Here is our code $socket = fsockopen('ctfquest.trendmicro.co.jp', 51740); while (!feof($socket)) { // There is still something to do $line = ''; while (($char = fgetc($socket)) != '=') { // We get every char until we see equal sign $line .= $char; echo $char; } fgetc($socket); // Space after the equal sign $calc = str_replace(',', '', rtrim($line, ' =')); // clearint the comma $calc = preg_replace_callback('#([A-Z]+)#', function($regs){ return roman($regs[1]); }, $calc); // Dealing with roman figures $calc = preg_replace_callback('#([a-z][a-z ]+)#', function($regs){ return wordsToNumber(trim($regs[1])).' '; }, $calc); // Dealing with english written figures $result = trim(shell_exec('echo '.escapeshellarg($calc).' | bc')); // bc to calculate if ($result !== false) { echo "$line = '$result'\n"; fputs($socket, $result."\r\n"); } }
The falg is: TMCTF{U D1D 17!}