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

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

Leave a Reply

Your email address will not be published. Required fields are marked *