Skip to content

Commit

Permalink
Add test to prove a path traversal attack
Browse files Browse the repository at this point in the history
If I try to retrieve the translations using the following url:

    http://localhost/translations?locales=randomstring/something

The file `something.js` gets created in the subdirectory
`messages.randomstring` of the cache directory:

    /var/www/someproject/app/cache/dev/bazinga-js-translation/messages.randomstring/something.js

This is the actual string that gets passed to the constructor of
`ConfigCache` by the JsTranslationBundle controller.

I can now traverse down from the JsTranslationBundle cache directory
(without first creating the `messages.randomstring` directory using the
previous step, this won't work):

    http://localhost/translations?locales=randomstring/../../evil

becomes:

    /var/www/someproject/app/cache/dev/bazinga-js-translation/messages.randomstring/../../evil.js

... and depending on the configuration of the server, I could also do:

    http://localhost/translations?locales=randomstring/../../../../../web/evil

=>

    /var/www/someproject/app/cache/dev/bazinga-js-translation/messages.randomstring/../../../../../web/evil.js

Thus creating the file `evil.js` (and `evil.js.meta`) under the Symfony
`web` root. Depending on file system permissions, this will also
overwrite existing files.

Signed-off-by: William DURAND <william.durand1@gmail.com>
  • Loading branch information
willdurand committed Jul 29, 2014
1 parent 360aa09 commit df6c0fd
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 1 deletion.
8 changes: 7 additions & 1 deletion Controller/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
* @author William DURAND <william.durand1@gmail.com>
Expand Down Expand Up @@ -143,7 +145,11 @@ public function getTranslationsAction(Request $request, $domain, $_format)
'include_config' => true,
));

$cache->write($content, $resources);
try {
$cache->write($content, $resources);
} catch (IOException $e) {
throw new NotFoundHttpException();
}
}

$response = new Response(
Expand Down
26 changes: 26 additions & 0 deletions Tests/Controller/ControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,30 @@ public function testGetTranslationsWithNumericKeys()
JSON
, $response->getContent());
}

public function testGetTranslationsWithPathTraversalAttack()
{
$client = static::createClient();

// 1. `evil.js` is not accessible
$crawler = $client->request('GET', '/translations?locales=randomstring/../../evil');
$response = $client->getResponse();

$this->assertEquals(404, $response->getStatusCode());

// 2. let's create a random directory with a randome js file
$crawler = $client->request('GET', '/translations?locales=randomstring/something');
$response = $client->getResponse();

$this->assertFileExists(sprintf('%s/%s/messages.randomstring/something.js',
$client->getKernel()->getCacheDir(),
'bazinga-js-translation'
));

// 3. path traversal attack
$crawler = $client->request('GET', '/translations?locales=randomstring/../../evil');
$response = $client->getResponse();

$this->assertEquals(200, $response->getStatusCode());
}
}

0 comments on commit df6c0fd

Please # to comment.