Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using PHP as template language

Tags:

php

templates

Edit: Great points all around, dedicated templating language is obviously the way to go. Thanks!

I wrote up this quick class to do templating via PHP -- I was wondering if this is easily exploitable if I were ever to open up templating to users (not the immediate plan, but thinking down the road).

class Template {

private $allowed_methods = array(
    'if', 
    'switch', 
    'foreach',
    'for', 
    'while'
);

private function secure_code($template_code) {
    $php_section_pattern = '/\<\?(.*?)\?\>/';
    $php_method_pattern = '/([a-zA-Z0-9_]+)[\s]*\(/';
    preg_match_all($php_section_pattern, $template_code, $matches);
    foreach (array_unique($matches[1]) as $index => $code_chunk) {
        preg_match_all($php_method_pattern, $code_chunk, $sub_matches);
        $code_allowed = true;
        foreach ($sub_matches[1] as $method_name) {
            if (!in_array($method_name, $this->allowed_methods)) {
                $code_allowed = false;
                break;
            }
        }
        if (!$code_allowed) {
            $template_code = str_replace($matches[0][$index], '', $template_code);
        }
    }
    return $template_code;      
}

public function render($template_code, $params) {
    extract($params);
    ob_start();
    eval('?>'.$this->secure_code($template_code).'<?php ');
    $result = ob_get_contents();
    ob_end_clean();
    return $result;     
}

}

Example usage:

$template_code = '<?= $title ?><? foreach ($photos as $photo): ?><img src="<?= $photo ?>"><? endforeach ?>';
$params = array('title' => 'My Title', 'photos' => array('img1.jpg', 'img2.jpg'));
$template = new Template;
echo $template->render($template_code, $params);

The idea here is that I'd store the templates (PHP code) in the database, and then run it through the class which uses regular expressions to only allow permitted methods (if, for, etc.). Anyone see an obvious way to exploit this and run arbitrary PHP? If so, I'll probably go the more standard route of a templating language such as Smarty...

like image 411
Kunal Avatar asked Mar 06 '26 19:03

Kunal


1 Answers

Sure..

$template_code = '<?= `rm -rf *`; ?>';

Edit:

Can't think of anything else right away. But you should know your scope is compromised IF render is ever called more than once on the same Template instance.

For example, if you render('<?php $this->allowed_methods[] = "eval"; ?>') .. then that instance of Template will have eval as an acceptable function for the next render .. ;)

like image 142
Matt Avatar answered Mar 08 '26 07:03

Matt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!