EXIF data analyzer
どんな問題?
まず下記のリンクが問題文にあります。
https://exif-analyzer.dctf-quals-17.def.camp/flag.php
これだけだと???という感じですが
flag.phpを消して、indexページに飛ぶと問題があります。
さらに ?sourceとリンクに付け加えておくと
そのソースが確認できます。
<?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
先に答えを言っておくと、wgetするときにファイル名に長さ制限があり、長すぎると省略されて.jpgのような画像ファイルの拡張子以外のも保存することが出来ます。
例えば
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php.jpg
のようにしておくと.jpgが省略され
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php
と言った感じです。(実際のAの数は自分で調べといてください)
それを利用して、.phpファイルをおいておき、flag.phpを表示すればこの問題のフラグが入手できます。
どうやって脆弱性を発見したか
ではどのようにしてこの脆弱性を発見したかというと、 exif_read_data
にBoFの脆弱性があると聞き、じゃあファイル名長くしようとしたらたまたまこの脆弱性を発見した次第です。
flag
DCTF{0c52b82e474afc7c06da92d221ffe9361330d9395978e633cdbf01a173d07aa4}
このときAWSに久しぶりにログインしたら毎月2000円課金していたという事実に気づき、結構ショックでした。