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

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